Serhat Ozgel
Serhat Ozgel

Reputation: 23766

How to replace strings in a code

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.

Upvotes: 1

Views: 536

Answers (6)

Peter Kofler
Peter Kofler

Reputation: 9440

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

Upvotes: 0

Lars Haugseth
Lars Haugseth

Reputation: 14881

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.

Upvotes: 0

ChrisW
ChrisW

Reputation: 56083

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.

Upvotes: 1

Matthew Flaschen
Matthew Flaschen

Reputation: 284786

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.

Upvotes: 0

JP Alioto
JP Alioto

Reputation: 45117

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.

Upvotes: 0

James Thompson
James Thompson

Reputation: 48162

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! :)

Upvotes: 0

Related Questions