4

我的问题与 Java 中的正则表达式有关,特别是给定搜索模式的多个匹配项。我需要获取的所有信息都在 1 行,它包含一个映射到 IP 地址的别名(例如 SA)。每一个都用逗号分隔。我需要提取每一个。

SA "239.255.252.1", SB "239.255.252.2", SC "239.255.252.3", SD "239.255.252.4"

我的 Reg Ex 看起来像这样:

Pattern alias = Pattern.compile("(\\S+)\\s+\"(\\d+\\.\\d+\\.\\d+\\.\\d+)\"");  
Matcher match = alias.matcher(lineInFile)  
while(match.find()) {  
   // do something  
}

这行得通,但我对此并不完全满意,因为自从引入了这一小段代码以来,我的程序已经放慢了一点(< 1 秒),但足以注意到差异。

所以我的问题是,我是否以正确的方式处理这个问题?是否有更有效或更轻量级的解决方案而不需要 while(match) 循环?和/或模式/匹配器类?

4

6 回答 6

1

如果该行可能不包含除该别名定义之外的任何内容,则使用.match()而不是.find()可能会加快对不匹配项的搜索。

于 2010-09-29T09:28:46.540 回答
0

如果您注意到那段代码的差异 < 1 秒,那么您的输入字符串必须包含大约一百万(至少大约 100k)的条目。我认为这是一个相当公平的性能,如果不编写自己的专用解析器,我看不出如何显着优化它。

于 2010-09-29T11:42:13.093 回答
0

恐怕你的代码看起来已经很高效了。这是我的版本:

Matcher match = Pattern
                .compile("(\\w+)\\s+\"(\\d+\\.\\d+\\.\\d+\\.\\d+)\"")
                .matcher(lineInFile);  
while(match.find()) {  
    //do something  
}

有两个微优化:

  1. 无需将模式保留在一个额外的变量中,内联
  2. 对于别名,搜索单词字符,而不是非空格字符

实际上,如果你做了很多这样的处理并且模式永远不会改变,你应该将编译后的模式保持在一个常量中:

private static final Pattern PATTERN = Pattern
            .compile("(\\w+)\\s+\"(\\d+\\.\\d+\\.\\d+\\.\\d+)\"");

Matcher match = PATTERN.matcher(lineInFile);  
while(match.find()) {  
    //do something  
}

更新:我在RegExr上花了一些时间想出了一个更具体的模式,它应该只检测有效的 IP 地址作为奖励。我知道它很难看,但我的猜测是它非常有效,因为它消除了大部分回溯:

([A-Z]+)\s*\"((?:1[0-9]{2}|2(?:(?:5[0-5]|[0-9]{2})|[0-9]{1,2})\.)
{3}(?:1[0-9]{2}|2(?:5[0-5]|[0-9]{2})|[0-9]{1,2}))

(为了便于阅读,所有反斜杠都需要在 java 中进行转义,但您可以在 RegExr 上对其进行测试,就像使用 OP 的测试字符串一样)

于 2010-09-29T09:36:44.013 回答
0

"(\\S{2})\\s+\"((\\d{1,3}\\.){3}\\d{1,3})\""您可以通过更明确地指定 IP 地址来改进您的正则表达式。

尝试使用StringTokenizer. 它不使用正则表达式。(如果您担心使用遗留类,请查看它的源代码并了解它是如何完成的。)

StringTokenizer st = new StringTokenizer(lineInFile, " ,\"");
while(st.hasMoreTokens()){
    String key = st.nextToken();
    String ip = st.nextToken();
    System.out.println(key + " ip: " +  ip);
}
于 2010-09-29T09:38:46.933 回答
0

预编译和重用 Pattern 对象(IMO)可能是最有效的优化。模式编译可能是一个昂贵的步骤。

重用 Matcher 实例(例如使用reset(CharSequence))可能会有所帮助,但我怀疑它会产生很大的不同。

正则表达式本身无法显着优化。一种可能的加速方法是(\d+\.\d+\.\d+\.\d+)([0-9\.]+). 这可能会有所帮助,因为它减少了潜在回溯点的数量……但您需要做一些实验才能确定。明显的缺点是它匹配不是有效 IP 地址的字符序列。

于 2010-09-29T11:13:28.097 回答
0

我不知道这是否会产生很大的性能优势,但你也可以先做

string.split(", ") // separate groups

接着

string.split(" ?\"") // separate alias from IP address

在比赛上。

于 2010-09-29T10:00:01.400 回答