用@符号替换 for() 循环中的所有分号

Replace all semicolons in for() loop with @ signs

我正在尝试编写一些代码来查找 for 循环,将其包含的分号替换为 @ 符号,并在右括号后添加一个新行。我目前的算法是

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 = "";
    }
}

这对于一行中 for 循环的单个实例非常有用,但是我 运行 进入的一个新案例是当 运行 在生产 JavaScript 文件中使用它时,它在第一个之后不适用于任何 for 循环。我试图将其封装在一个 while 循环中以在同一行上继续,同时它可以继续查找 for 循环,如下所示

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());
}

但这是在 for 循环之外替换分号。有谁知道这样做有什么更巧妙的方法吗?

编辑:这是一些预期的输出

输入:

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

输出:

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

编辑 2:我选择了正则表达式答案,因为它似乎适用于除此之外的很多情况(荒谬的 javascript 前面的垃圾):

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++)

注意最后嵌套的 for(b in a.data) - 这就是给出正则表达式答案问题的原因。有人有万能的办法来处理这个愚蠢的案子吗?

这是一个正则表达式方法...

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();
}

除非您使用某种类型的 tokenization,否则几乎(如果不是完全不可能)完成所有情况的 100%。例如,如果您有以下内容:

for (b[this.id] = this, this.settings = new c.classes.configurable(c.settings, j.settings || {}), Object.defineProperty(this, "graph", {

正则表达式将卡在 j.settings || {} 中的 { 而不是一直到 d; d++)

这与你 can not really parse HTML or XML with regex 的原因相同。而不是做 search/replace 你真的需要构建一个简单的标记器,例如看看下面的 psudo 代码:

var depth = 0
var ouput = ""
for each char in string {
  if char == '{' {
    depth += 1
  }
  if char == '}' {
    depth -= 1
  }
  if depth > 0 && char == ';'{
    output = output + "@"
  } else {
    output = output + char
  }
}

您很可能必须向上述分词器添加一些额外的状态才能完成您想做的一切……但它应该为您提供一个良好的起点。