3

示例代码:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Regex {
    public static void main(String[] args) {
        String data = "Shyam and you. You are 2.3 km away from home. Lakshmi and you. Ram and you. You are Mike. ";
        Pattern pattern = Pattern.compile(
                "\\s*((?:[^\\.]|(?:\\w+\\.)+\\w)*are.*?)(?:\\.\\s|\\.$)",
                Pattern.DOTALL);
        Matcher matcher = pattern.matcher(data);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
        }
    }
}

输出:

You are 2.3 km away from home. 

You are Mike. 

我在执行上面的代码时得到了预期的输出。但问题是在使用更大的字符串测试相同的正则表达式时,它会显示溢出错误。我进行了大致相同的搜索,发现正则表达式中的 (A|B)* 之类的交替会导致问题。有没有办法解决这个问题?请帮忙。

4

2 回答 2

3

我试图重构你的正则表达式以避免回溯。你能试试这个正则表达式吗:

Pattern pattern = Pattern.compile("(?>[^.]|(?:\\w+\\.)+\\w)+\\sare\\s.*?(?>\\.\\s|\\.$)",
                  Pattern.DOTALL);

(?>group)称为原子分组

根据:http ://www.regular-expressions.info/atomic.html

原子分组

原子组是一个组,当正则表达式引擎从中退出时, automatically throws away all backtracking positions remembered by any tokens inside the group. 原子团是非捕获的。语法是(?>group).

于 2013-08-28T15:14:37.610 回答
1

正如 Pshemo 在评论中明智地指出的那样,您的问题可能是灾难性回溯的结果(由于所有那些嵌套的量词),而不是与输入字符串的长度有关。上面的链接提供了一个很好的示例,说明了为什么您可以StackOverflowErrors使用短输入字符串和看似简单的正则表达式。

简而言之,这意味着在某些情况下,模式匹配器可以采取指数级的步骤(与输入的长度相比)来确定匹配/不匹配。发生这种情况时,堆栈会“溢出”,因为模式匹配递归太深了。嵌套量词尤其常见,例如(x+x+)+y上面链接中的 ,或您的模式中的(几个示例之一)((?:\\w+\\.)+\\w)*

如果您解释了您要为什么编写正则表达式,我们很可能会帮助您想出一个在您输入不幸或恶意输入时不会崩溃的方法。

鉴于您对要求的评论,如果您完全避免使用正则表达式,您可以轻松地做到这一点。只需将输入拆分为分隔符(在您的情况下为". "),然后在每个结果中搜索关键字。正如几位评论者所提到的,无论如何拆分数据通常更安全,尤其是在大小未知的情况下。

String[] sentences = data.split("\\. ");
for (String sentence : sentences) {
    if (sentence.contains("are")) {
        System.out.println(sentence.concat(". "));
    }
}
于 2013-08-28T14:46:40.433 回答