我的问题与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(匹配)循环?和/或模式/匹配类?
答案 0 :(得分:1)
如果该行可能不包含除别名定义之外的任何内容,那么使用.match()
代替.find()
可能会加快搜索不匹配。
答案 1 :(得分:0)
我担心你的代码看起来非常有效。 这是我的版本:
Matcher match = Pattern
.compile("(\\w+)\\s+\"(\\d+\\.\\d+\\.\\d+\\.\\d+)\"")
.matcher(lineInFile);
while(match.find()) {
//do something
}
有两种微观优化:
实际上,如果你做了很多这样的处理并且模式永远不会改变,你应该将编译后的模式保持为常量:
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的测试字符串一样)
答案 2 :(得分:0)
您可以通过更明确地指定IP地址来将正则表达式提高到:"(\\S{2})\\s+\"((\\d{1,3}\\.){3}\\d{1,3})\""
。
尝试使用StringTokenizer
的效果。它不使用正则表达式。
(如果您担心使用遗留类,那么请查看其来源并了解它是如何完成的。)
StringTokenizer st = new StringTokenizer(lineInFile, " ,\"");
while(st.hasMoreTokens()){
String key = st.nextToken();
String ip = st.nextToken();
System.out.println(key + " ip: " + ip);
}
答案 3 :(得分:0)
我不知道这是否会产生很大的性能优势,但你也可以先做
string.split(", ") // separate groups
然后
string.split(" ?\"") // separate alias from IP address
在比赛中。
答案 4 :(得分:0)
预编译和重用Pattern对象(IMO)可能是最有效的优化。模式编译可能是一个昂贵的步骤。
重用Matcher实例(例如使用reset(CharSequence)
)可能有所帮助,但我怀疑它会有很大的不同。
正则表达式本身无法显着优化。一种可能的加速方式是将(\d+\.\d+\.\d+\.\d+)
替换为([0-9\.]+)
。这可能有所帮助,因为它减少了潜在回溯点的数量......但你需要做一些实验才能确定。明显的缺点是它匹配的是无效IP地址的字符序列。
答案 5 :(得分:0)
如果你注意到&lt;在那段代码上1秒,那么你的输入字符串必须包含大约一百万(ot至少大约100k)的条目。我认为这是一个非常公平的性能,如果不编写自己的专用解析器,我无法看到如何显着优化它。