使用模式和匹配器的Java正则表达式
我的问题与Java中的正则表达式有关,特别是与给定搜索模式的多个匹配有关。我需要获取的所有信息都在一行中,其中包含一个映射到IP地址的别名(例如SA)。每一个都用逗号分隔。我需要提取每一个使用模式和匹配器的Java正则表达式,java,regex,matcher,Java,Regex,Matcher,我的问题与Java中的正则表达式有关,特别是与给定搜索模式的多个匹配有关。我需要获取的所有信息都在一行中,其中包含一个映射到IP地址的别名(例如SA)。每一个都用逗号分隔。我需要提取每一个 SA "239.255.252.1", SB "239.255.252.2", SC "239.255.252.3", SD "239.255.252.4" 我的前注册医生是这样的: Pattern alias = Pattern.compile("(\\S+)\\s+\"(\\d+\\.\\d+\\.\\
SA "239.255.252.1", SB "239.255.252.2", SC "239.255.252.3", SD "239.255.252.4"
我的前注册医生是这样的:
Pattern alias = Pattern.compile("(\\S+)\\s+\"(\\d+\\.\\d+\\.\\d+\\.\\d+)\"");
Matcher match = alias.matcher(lineInFile)
while(match.find()) {
// do something
}
这是可行的,但我并不完全满意,因为自从引入这段小代码以来,我的程序已经慢了一点(<1秒),但足以注意到一个不同
所以我的问题是,我是否以正确的方式进行这项工作?是否有一种更高效或可能更轻量级的解决方案,而不需要while(match)循环?和/或模式/匹配器类?如果行中可能不包含除别名定义以外的任何内容,则使用
.match()
而不是.find()
可能会加快对非匹配项的搜索速度。恐怕您的代码看起来已经相当有效了。
以下是我的版本:
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
}
更新:我花了一些时间想出了一个更具体的模式,它应该只检测有效的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的测试字符串中一样)您可以通过更明确地指定IP地址将regex改进为:
“(\\s{2}\\s+\”(\\d{1,3}){3}\\d{1,3}\”
尝试使用StringTokenizer
的性能。它不使用正则表达式。
(如果您担心使用遗留类,那么请查看其源代码并了解它是如何实现的。)
我不知道这是否会带来很大的性能优势,但您也可以先这样做
string.split(", ") // separate groups
然后
string.split(" ?\"") // separate alias from IP address
在匹配上。预编译和重用模式对象(IMO)可能是最有效的优化。模式编译可能是一个昂贵的步骤 重用Matcher实例(例如,使用
reset(CharSequence)
)可能会有所帮助,但我怀疑这是否会有很大的不同
正则表达式本身无法显著优化。一种可能的加速方法是将
(\d+\.\d+.\d+.\d+)
替换为([0-9\.]+)
。这可能会有所帮助,因为它减少了潜在回溯点的数量。。。但是你需要做一些实验来确定。明显的缺点是,它匹配的字符序列不是有效的IP地址。如果您注意到这段代码的差异小于1秒,那么您的输入字符串必须包含大约一百万(或者至少大约100k)个条目。我认为这是一个相当公平的性能,我看不出在不编写自己的专用解析器的情况下如何显著优化它。StringTokenizer是一个遗留类,出于兼容性原因保留了它,尽管新代码中不鼓励使用它。建议任何寻求此功能的人改用String的split方法或java.util.regex包。(来源:)也就是说,扫描仪可能是一个不错的选择:是的,我知道。这就是为什么我在我的帖子里放了一张便条。StringTokenizer在内部使用String的indexOf
和substring
方法,这样我们就可以看到它是如何工作的,如果它比正则表达式快的话,就可以在我们的新代码中复制它的功能。这就是为什么我在我的帖子中写了一条注释我错过了它。这一定是我的盲日,对不起。所以两张正则表达式通行证比一张快?“我很怀疑。”西尼泽:我也很怀疑。我不使用Java,所以我不能分析它。但这可能值得一试。第一次微观优化的效果可能太小,无法衡量。第二个改变了正则表达式的含义,但不清楚它是否有多大帮助。然而,预编译和重用模式绝对值得。关于第二个微观优化:查看模式类的代码,我认为这实际上可能会减慢模式匹配的速度!是的,这是有道理的。查找小字符类的否定应该比查找lqrge字符类(如\w)更有效。当我在测试中发现\w+比\S+快15-20%时,我会立即更新我的答案。好吧,也许之后我会保留它:-)非常感谢所有花时间回答我问题的人。这对我来说是一个非常有用的练习,因为我还是一个Java新手。顺便说一句,我添加了一些关于模式RegExp的更具体的信息,这似乎有助于解决问题。在我放入的第一个别名/IP对之前,有一个已知字符串(“别名”),这肯定有帮助。再次感谢各位!重用matcher听起来是个坏主意,因为它会破坏多线程场景中的情况(除非引入对象池,这真的是太过分了)
string.split(" ?\"") // separate alias from IP address