Tutorial :How to replace strings in a code



Question:

I want to perform a batch replace operation on a project by following some rules. For e.g. I am taking notes in the code like this:

On every code piece, which is commented like this, I want to perform a replace operation, which will replace the input code piece with the output code piece in the following examples:

Input 1:

//+  a++;  //+(+SomeException$SomeMessage)  

Output 1:

try  {      a++;  }  catch (AnException)  {      throw;  }  catch (Exception ex)  {      throw new SomeException("SomeMessage", "15", ex);  }  

Input 2:

//+  a++;  //-(+InvalidOperationException$SomeMessage)  

Output 2:

try  {      a++;  }  catch (InvalidOperationException ex)  {      throw new AnException("SomeMessage", "16", ex);  }  

Input 3:

//+  a++;  //-(SomeMessage)  

Output 3:

try  {      a++;  }  catch (Exception ex)  {      throw new AnException("SomeMessage", "17", ex);  }  

The magic numbers (15, 16, 17) will increase for each code piece commented like this. I know this is not the best practice but I am not making the decisions and I am expected to handle exceptions like this, so I thought I can ease the pain by taking notes and batch replacing in the end. What is the best way to do this? Should I write my own code to perform replaces or is there some regex replace tool or something like that exist that can automatically make this for me?

Update: This is a one time job and my magic number has to be globally unique. So if it was 25 for the last match in a file, it must be 26 for the first match in the next file.


Solution:1

What is the best way to do this? Should I write my own code to perform replaces or is there some regex replace tool or something like that exist that can automatically make this for me?

I'd write a little program in C++ or C# to do this. There are presumably other tools and script languages that can do it; but given that it's a trivial job in C++ or C# and given that I aready know how to do it in these languages, why not?

I don't know what you mean by the "best" way, but for me at least this would be one of the easiest ways.


Solution:2

This looks like a simple language that you're going to compile into another language that looks like Java. A compiler is the right tool for a job like this, especially because you need to keep around the state of the current magic number. It also seems likely that whoever is making the decisions would want to add new features to the language, in which case a solution glued together with regular expressions might not work properly.

If I'm right about what you really want, your question is reduced to the problem of "How do I write a Domain Specific Language?" I'm not sure what the best method would be for this, but if you know Perl you could probably put together a solution with Parse::RecDescent.

I think it's possibly to do this with scripting and regular expressions, but this is the type of problem for which compilers were invented. If you end up making something hacky, God help the person that has to maintain it after you! :)


Solution:3

You could write a CodeSmith template that reads that input and outputs that output. But, I'm not sure you could do it in-line. That is, you would need a file of just inputs and then your template could give you the file of outputs. I'm not sure if that acceptable tho.


Solution:4

There's a lot of ways you could do this, even though you probably shouldn't (as you seem to realize, this will just result in meaningless exceptions). Nevertheless, here's a sed/sh combo to do the first one. It doesn't handle the autonumbering or your other variants. I'll leave that as an exercise for the OP.

P1='\/\/+'; P2='\(.*\)'; P3='\/\/+(+\([^$]*\)$\(.*\))';   echo 'foo()\n//+\na++\n//+(+SomeException$Message)'|sed ' /'$P1'/ { N; /'$P2'/ { N; /'$P3'/ { s/'$P1'\n'$P2'\n'$P3'/try\n{\n\t\1\n}\ncatch (AnException)\n{\n\tthrow;\n}\ncatch (Exception ex)\n{\n\tthrow new \2("\3", "0", ex);\n}/ } } } '  

The echo is just a test string.


Solution:5

As an Emacs user, for a one time job I'd do this by defining keyboard macros, then use set/increment/insert-register for the autonumbering magic. There shouldn't really be any need for writing your own elisp functions.

Though if you need to perform this on more than just a couple of files, you'll probably be better off writing a script to do the job.


Solution:6

If you do not happen to use an IDE like Emacs (as answered by many) with strong regex support I would write a little script. Note that text manipulation is in general more a scripting operation, e.g. Perl, Ruby, due to regex support in the language itself. On the other hand if you are very familiar with say Java Pattern, then writing it in Java is propably the fastest solution, even if you need more overhead esp. for a one time operation.

So a litte Ruby script might look like that (beware, I did not test it):

$cnt = 1  IO.readlines(filename).collect { |line|    if line =~ /^\s*\/\/\+\s*$/      $cnt += 1      ["try\n", "{\n" ]    elsif line =~ /^\s*\/\/\+\(\+(.+)\$(.+)\)\s*/      ["}\n", "catch (#{$1} ex)\n", "{\n",          "throw new AnException(\"#{$2}\", \"#{$cnt}\", ex);\n", "}\n"]    # propably more else for all cases    else      line    end  }.flatten  # save the file again  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »