带有额外扭曲的Curly Brackets RegEx

时间:2013-01-27 00:02:55

标签: java regex

我对正则表达式比较陌生,我不确定这是解决问题的方法,但现在可以了。

我的文本文件可能包含以下内容:

program A {
   int x = 10;
   tuple date {
            int day;
            int month;
            int year;
   }
}

function B {
    int y = 20;
    ...
}

process C {
    more code;
}

我需要提取程序或函数或进程之间的任何文本。所以只有3种类型的标题。

所以我决定使用正则表达式来获取大括号之间的任何文本。我开始的方式是通过这个表达式,假设我事先知道标识符列表:

(program|function|process)+ A[\s\S]*(?=function)

这样可以很好地捕获程序A中的任何文本。但有时程序A可能不会被函数跟随。随后可以是流程或其他程序。在我的最后一组中添加OR后,它将无法正常工作。

(program|function|process)+ A[\s\S]*(?=function|process|program)

我看到它的方式是通过3个选项:

  1. 通过正则表达式,但上述可行吗?
  2. 跟踪大括号,但如果缺少输入则会怎样。如果在另一组代码中找到匹配括号,则可能很难抛出错误。
  3. 使用无上下文语法,但最后我将保留此选项。
  4. 提前致谢!

    PS:我用它来帮助RegExpr:http://gskinner.com/RegExr/?33i30

3 个答案:

答案 0 :(得分:4)

您应该考虑使用LL解析器而不是regexp。正则表达式不是解决每个解析需求的正确答案,而是仅适用于常规语言。如果您有无上下文语法,请使用LL解析器。

https://en.wikipedia.org/wiki/LL_parser

答案 1 :(得分:1)

如果您更喜欢正则表达式解决方案,请尝试以下方法:

/(program|function|process).*?{(.*?)}\n+(program|function|process)/m

您可能需要对其进行测试here

然而,正则表达式解决方案对您的问题并不健全。在使用之前我们必须做出一些假设。例如,代码需要格式良好。玩它以防万一它应该为你提供一个解决方法。

更新:这是经过测试的Java代码:

public class Test {
    public static void main(String[] args) throws IOException {
        String input = FileUtils.readFileToString(new File("input.txt"));
        Pattern p = Pattern.compile("(?<=program|function|process)[^{]*\\{(.*?)\\}\\s*(?=program|function|process|$)", Pattern.DOTALL);
        Matcher m = p.matcher(input);
        while(m.find()) {
            System.out.println(m.group(1));
        }
    }
}

答案 2 :(得分:1)

如果你真的不想使用语法,你可以实现一个简单的解析器,它可以逐行分析文件:

请看我的例子:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.io.IOUtils;

public class SourceCodeProgram {

    public static void main(String[] args) throws Exception {
        File source = new File("C:\\test.txt");
        SourceCodeScanner scanner = new SourceCodeScanner(source);
        for (Code code : scanner.readAll()) {
            System.out.println(code);
            System.out.println("-----------");
        }
    }
}

class SourceCodeScanner {

    private File source;

    private Pattern startCodePattern = Pattern.compile(
            "^(\\s)*(program|function|process)", Pattern.CASE_INSENSITIVE);

    public SourceCodeScanner(File source) {
        this.source = source;
    }

    public Collection<Code> readAll() throws Exception {
        List<String> lines = readFileLineByLine();
        List<Code> codes = new ArrayList<Code>();
        StringBuilder builder = new StringBuilder(512);

        for (String line : lines) {
            if (containsSourceCodeHeader(line)) {
                int length = builder.length();
                if (length != 0) {
                    codes.add(new Code(builder.toString().trim()));
                    builder.delete(0, length);
                }
            }
            addNextLineOfSourceCode(builder, line);
        }
        String lastCode = builder.toString();
        if (containsSourceCodeHeader(lastCode)) {
            codes.add(new Code(builder.toString().trim()));
        }
        return codes;
    }

    private boolean containsSourceCodeHeader(String line) {
        return startCodePattern.matcher(line).find();
    }

    private void addNextLineOfSourceCode(StringBuilder builder, String line) {
        builder.append(line);
        builder.append(IOUtils.LINE_SEPARATOR);
    }

    private List<String> readFileLineByLine() throws Exception {
        FileInputStream fileInputStream = new FileInputStream(source);
        return IOUtils.readLines(new BufferedInputStream(fileInputStream));
    }
}

class Code {
    private String value;

    public Code(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return value;
    }
}