3

I have a complete Java based code base, where members are named:

String m_sFoo;
Array m_arrKeepThings;

Variable/object names includes both a m_ prefix to indicate a member, and an hungarian notation type indicator.

I'm looking for a way to perform a single time code replacment to (for example on the above to cases):

Array keepThings;
String foo;

Of course there are many other alternatives, but I hope that based on two examples, I'll be able to perform the full change. Performances is not an issue as it's a single time fix.

To clarify, if I had to explain this in lines, it would be:

  1. Match words starting with m_[a-zA-Z].
  2. After m_, drop whatever is there before the first Capital letter.
  3. Change the first capital letter to lower case.
VMAtm
  • 27,943
  • 17
  • 79
  • 125
JAR.JAR.beans
  • 9,668
  • 4
  • 45
  • 57
  • 2
    Why you dont use the refactoring features of your IDE? – KingCrunch Jul 24 '11 at 12:18
  • Because changing 8k variable names across 3k files, is a little too much for me. – JAR.JAR.beans Jul 24 '11 at 12:20
  • I think a regex is not enough, you may need to understand the AST to perform those changes (depends on code complexity). Step #1 is maybe too generic, must can only match arribute names. – home Jul 24 '11 at 12:40
  • Thanks. Suely enough, I expect to have an additional 10% of the work done manually, it's the first chunk where I need help with. – JAR.JAR.beans Jul 27 '11 at 06:01

3 Answers3

1

If you are really, really sure that the proposed changed won't result in clashes (variables that only differ in their prefix) I would do it with a line of perl:

perl -pi.bak -e "s/\bm_[a-z_]+([A-Z]\w*)\b/this.\u$1/g;" *.java

This will perform an inline edit of your Java sources, while keeping a backup with extension .bak replacing your pattern between word boundaries (\b) capitalising the first letter of the replacement (\u) multiple times per line.

You can then perform a diff between the backup files and the result files to see if all went well.

rsp
  • 23,135
  • 6
  • 55
  • 69
1

Check out this post: Regex to change to sentence case

Generally I am afraid that you cannot change the case of letters using regular expressions. I'd recommend you to implement a simple utility (using any language you want). You can do it in java. Just go through your file tree, search for pattern like m_[sidc]([A-Z]), take the captured sequence, call toLowerCase() and perform replace.

Other solution is to search and replace for m_sA, then m_sB, ... m_sZ using eclipse. Total: 26 times. It is a little bit stupid but probably anyway faster than implementing and debugging of your own code.

Community
  • 1
  • 1
AlexR
  • 114,158
  • 16
  • 130
  • 208
0

Here is some Java code that works. It is not pure regex, but based on:

Usage:

String str = "String m_sFoo;\n"
        + "Array m_arrKeepThings;\n"
        + "List<? extends Reader> m_lstReaders; // A silly comment\n"
        + "String.format(\"Hello World!\"); /* No m_named vars here */";
// Read the file you want to handle instead

NameMatcher nm = new NameMatcher(str);
System.out.println(nm.performReplacements());

NameMatcher.java

package so_6806699;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author martijn
 */
public class NameMatcher
{

    private String input;
    public static final String REGEX = "m_[a-z]+([A-Z0-9_\\$\\µ\\£]*)";
    public static final Pattern PATTERN = Pattern.compile(REGEX);

    public NameMatcher(String input)
    {
        this.input = input;
    }

    public String performReplacements()
    {
        Matcher m = PATTERN.matcher(input);
        StringBuilder sb = new StringBuilder();

        int oldEnd = 0;
        while (m.find())
        {
            int start = m.start();
            int end = m.end();

            String match = input.substring(start, end);
            String matchGroup1 = match.replaceAll(REGEX, "$1");
            if (!matchGroup1.isEmpty())
            {
                char[] match_array = matchGroup1.toCharArray();
                match_array[0] = Character.toLowerCase(match_array[0]);
                match = new String(match_array);
            }

            sb.append(input.substring(oldEnd, start));
            oldEnd = end;

            sb.append(match);
        }
        sb.append(input.substring(oldEnd));
        return sb.toString();
    }
}

Demo Output:

String foo;
Array keepThings;
List<? extends Reader> readers; // A silly comment
String.format("Hello World!"); /* No m_named vars here */

Edit 0: Since dollar signs ($), micro (µ) and pound (£) are valid characters for Java name variables, I edited the regex.

Edit 1: It seems that there are a lot of non-latin characters that are valid (éùàçè, etc). Hopefully you don't have to handle them.

Edit 2: I'm only a human being! So be aware of errors there might be in the code! Make a BACKUP first!

Edit 3: Code improved. A NPE was thrown when the code contains this: m_foo. These will be unhandled.

Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
  • This is very close, but I'm having problem completing this in a real life scenario where I need to ename the member when being used as well, as in: **this.m_sFoo**; probbaly an additional match pattern ? – JAR.JAR.beans Jul 27 '11 at 06:00
  • So, do you want to remove the `this.` part as well? I don't think that's a great idea. I think the code I gave you should work good. – Martijn Courteaux Jul 29 '11 at 07:51