Java 处理模式语法异常和扫描文本

Java 处理模式语法异常和扫描文本,java,regex,Java,Regex,我想从一个大约一百万个名字的庞大列表中找到一个文本文档集合中的名字。我先从名单上的名字做一个模式: BufferedReader TSVFile = new BufferedReader(new FileReader("names.tsv")); String dataRow = TSVFile.readLine(); dataRow = TSVFile.readLine();// skip first line (header) String combine

我想从一个大约一百万个名字的庞大列表中找到一个文本文档集合中的名字。我先从名单上的名字做一个模式:

    BufferedReader TSVFile = new BufferedReader(new FileReader("names.tsv"));

    String dataRow = TSVFile.readLine();
    dataRow = TSVFile.readLine();// skip first line (header)

    String combined = "";
    while (dataRow != null) {
        String[] dataArray = dataRow.split("\t");
        String name = dataArray[1];
        combined += name.replace("\"", "") + "|";

        dataRow = TSVFile.readLine(); // Read next line of data.
    }
    TSVFile.close();
    Pattern all = Pattern.compile(combined);
这样做之后,我得到了一个
IllegalPatternSyntax
异常,因为有些名称的名称或其他正则表达式中包含
'+'
。我试图通过以下两种方式来解决这个问题:

    if(name.contains("\""){
    //ignore this name }
没有正常工作,但也很混乱,因为你必须手动逃离一切,并多次运行它,浪费你的时间。 然后我尝试使用
quote
方法:

   Pattern all = Pattern.compile(Pattern.quote(combined));

但是现在,我在文本文档中再也找不到任何匹配项,即使我在文本文档上也使用了
quote
。如何解决这个问题?

我同意@dragon66的评论,你不应该引用管道“|”。因此,使用
Pattern.quote()
,您的代码将与下面的代码类似:


我还建议验证您的问题域是否需要优化,以替换使用
字符串combined=“”StringBuilder
类上创建code>,以避免在循环中创建不必要的新字符串。

Guillermerama为您的代码提供了错误修复

我将添加一些性能改进。正如我指出的那样,java的正则表达式库不可伸缩,如果用于搜索,则速度会更慢

但是使用多字符串搜索算法可以做得更好。例如,通过使用:

搜索(
finder.findAll()
)确实(在我的计算机上)需要<1毫秒的时间。对java.util.regex执行同样的操作大约需要20毫秒

您可以使用RexLex提供的其他算法来调整此性能

设置需要以下代码:

private static Iterable<String> createLines() {
    List<String> list = new ArrayList<>();
    for (int i = 0; i < 100000; i++)  {
        list.add(i + "\t" + name(i));
    }
    return list;
}

private static String name(int i) {
    String s = String.valueOf(i);
    while (s.length() < 5)  {
        s = '0' + s;
    }
    return s;
}
私有静态Iterable createLines(){
列表=新的ArrayList();
对于(int i=0;i<100000;i++){
列表。添加(i+“\t”+名称(i));
}
退货清单;
}
私有静态字符串名称(int i){
字符串s=字符串。值(i);
而(s.长度()<5){
s='0'+s;
}
返回s;
}

我认为问题在于您还引用了应该转义的管道符号。也许您可以像这样构造正则表达式时手动引用名称:combined+=“\\Q”+name+“\\E |”;这可能无法回答您的问题,但是:正则表达式(即
java.util.regex
提供的正则表达式)不能很好地扩展,尤其是在搜索时。最好使用多字符串搜索算法(如Aho-Corasick)。@CoronA您知道我可以从哪里获得对Aho-Corasick实现的支持吗?我想知道如何在循环中添加关键字。应该很简单:在循环之前创建一个
trieBuilder=new Trie.builder()
。在循环中添加
trieBuilder.addKeyword(关键字)
。调用
Trie-Trie=trieBuilder.build()
以获取最终的Trie。如果这不能解决您的问题,那么我建议您就此打开另一个问题(并向我指出)。如果每个
字符串都是唯一的,这是否也是一种改进?@Pete如果每个
字符串都是唯一的,那么您的重复连接肯定会消耗大量内存。9/10次,您需要一个
StringBuilder
来重复连接,而另1/10次是您需要担心同步的时候,因此使用
StringBuffer
//setting up a test file
Iterable<String> lines = createLines();
Files.write(Paths.get("names.tsv"), lines , CREATE, WRITE, TRUNCATE_EXISTING);

// read the pattern from the file
BufferedReader TSVFile = new BufferedReader(new FileReader("names.tsv"));

Set<String> combined = new LinkedHashSet<>();

String dataRow = TSVFile.readLine();
dataRow = TSVFile.readLine();// skip first line (header)

while (dataRow != null) {
  String[] dataArray = dataRow.split("\t");
  String name = dataArray[1];
  combined.add(name);

  dataRow = TSVFile.readLine(); // Read next line of data.
}

TSVFile.close();

// search the pattern in a small text
StringSearchAlgorithm stringSearch = new AhoCorasick(new ArrayList<>(combined));
StringFinder finder = stringSearch.createFinder(new StringCharProvider("test " + name(38) + "\n or " + name(799) + " : " + name(99999), 0));
System.out.println(finder.findAll());
[5:10(00038), 15:20(00799), 23:28(99999)]
private static Iterable<String> createLines() {
    List<String> list = new ArrayList<>();
    for (int i = 0; i < 100000; i++)  {
        list.add(i + "\t" + name(i));
    }
    return list;
}

private static String name(int i) {
    String s = String.valueOf(i);
    while (s.length() < 5)  {
        s = '0' + s;
    }
    return s;
}