1

我对正则表达式比较陌生,我不确定这是否是解决我的问题的方法,但这里有。

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

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. 使用上下文无关语法,但我将最后保留此选项。

提前致谢!

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

4

3 回答 3

4

您应该考虑为此使用 LL 解析器而不是正则表达式。正则表达式不是每个解析需求的正确答案,而只是正则语言。如果您有上下文无关语法,请使用 LL 解析器。

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

于 2013-01-27T00:21:58.357 回答
1

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

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

您可能想在这里测试一下。

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

更新:这是经过测试的 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));
        }
    }
}
于 2013-01-27T00:43:15.617 回答
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;
    }
}
于 2013-01-27T00:47:55.570 回答