繁体   English   中英

使用Pattern和Matcher的Java正则表达式

[英]Java Regular Expressions using Pattern and Matcher

我的问题与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()而不是.find()可能会加快对非匹配的搜索。

我担心你的代码看起来非常有效。 这是我的版本:

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的测试字符串一样)

您可以将正则表达式改进为: "(\\\\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);
}

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

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

然后

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

在比赛中。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM