mjswartz mjswartz - 6 months ago 11
Java Question

Replace all semicolons in for() loop with @ signs

I am trying to write some code to find for loops, replace their containing semicolons with @ signs, and add a new line after the closing parenthesis. The current algorithm I have is

pattern = "for(";
if (line.contains(pattern))
{
openPos = line.indexOf(pattern) + "for".length();

Occurence = 1;
closePos = findClose(line, openPos, '(', ')');
if (closePos != -1)
{
// Replace all line terminators within loop ()'s with @'s
for (int lt = 0; lt < lineTerminator.size(); lt++)
{
tempLine = line.substring(openPos + "(".length(), closePos).replaceAll(";", "@");
}
line = line.substring(0, openPos + "(".length()) + tempLine + ")\n" + line.substring(closePos + 1, line.length()).trim();
multiLine = "";
}
}


This works great for single instances of a for loop on one line, but a new case that I ran into is when running this on a production JavaScript file, it doesn't work on any for loops after the first. I tried to encapsulate this in a while loop to continue on the same line while it can keep finding for loops as follows

indexOfPattern = line.indexOf(pattern);
while (indexOfPattern >= 0)
{
openPos = indexOfPattern + pattern.length();
Occurence = 1;
closePos = findClose(line, openPos, '(', ')');
if (closePos != -1)
{
// Replace all line terminators within additional loop ()'s with @'s
for (int lt = 0; lt < lineTerminator.size(); lt++)
{
tempLine = line.substring(openPos + "(".length(), closePos).trim().replaceAll(lineTerminator.get(lt), "@");
}
line = line.substring(0, openPos + "(".length()) + tempLine + ")\n" + line.substring(closePos + 1, line.length()).trim();
}
indexOfPattern = line.indexOf(pattern, indexOfPattern + pattern.length());
}


but this is replacing semicolons outside of the for loop. Does anyone know of any slicker way to do this?

Edit: Here's some expected output

Input:

for(h=0;b[h];) for(i=0;i<10;i++) for(a in b) { do; some; things; }


Output:

for(h=0@b[h]@) for(i=0@i<10@i++) for(a in b) { do; some; things; }


Edit 2: I selected the regex answer since it seems to work for a lot of the cases except for this one (ridiculous javascript junk ahead):

for(b[this.id]=this,this.settings=new c.classes.configurable(c.settings,j.settings||{}),Object.defineProperty(this,"graph",{value:new c.classes.graph(this.settings),configurable:!0}),Object.defineProperty(this,"middlewares",{value:[],configurable:!0}),Object.defineProperty(this,"cameras",{value:{},configurable:!0}),Object.defineProperty(this,"renderers",{value:{},configurable:!0}),Object.defineProperty(this,"renderersPerCamera",{value:{},configurable:!0}),Object.defineProperty(this,"cameraFrames",{value:{},configurable:!0}),Object.defineProperty(this,"camera",{get:function(){return this.cameras[0]}}),Object.defineProperty(this,"events",{value:["click","rightClick","clickStage","doubleClickStage","rightClickStage","clickNode","clickNodes","doubleClickNode","doubleClickNodes","rightClickNode","rightClickNodes","overNode","overNodes","outNode","outNodes","downNode","downNodes","upNode","upNodes"],configurable:!0}),this._handler=function(a){var b,c={};for(b in a.data)c[b]=a.data[b];c.renderer=a.target,this.dispatchEvent(a.type,c)}.bind(this),f=j.renderers||[],d=0,e=f.length;e>d;d++)


Notice the nested
for(b in a.data)
towards the end - this is what's giving the regular expression answer problems. Anybody got a catch-all to handle this silly case?

Answer

Here is a regex approach...

public String replaceForSemicolons(String input) {
    String pattern = "for\\s*\\([^;]+;[^;]+[^\\)]+\\)\\s*\\{";
    Pattern reg = Pattern.compile(pattern);
    Matcher matcher = reg.matcher(input);
    StringBuffer output = new StringBuffer();
    int previousEnd = 0;

    while(matcher.find()) {
        //get the matched 'for' without the opening bracket
        String matchedString = input.substring(matcher.start(), matcher.end()-1);
        //replace the semicolons with @
        matchedString = matchedString.replaceAll(";", "@");
        //append everything from the end of the last match to the start of this match
        output.append(input.substring(previousEnd, matcher.start()));
        //append the matched string with the replaced semicolons
        output.append(matchedString);
        //add a new line and the opening bracket that we left out from the matched string
        output.append("\n{");
        previousEnd = matcher.end();
    }

    //append the rest of the string
    output.append(input.substring(previousEnd));

    return output.toString();
}