Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用模式和匹配器的Java正则表达式_Java_Regex_Matcher - Fatal编程技术网

使用模式和匹配器的Java正则表达式

使用模式和匹配器的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+\\.\\

我的问题与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+\\.\\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  
}
有两种微观优化:

  • 不需要额外保留图案 变量,内联的
  • 对于别名,请搜索word 字符,而不是非空格字符
  • 事实上,如果您进行了大量这样的处理,并且模式从未改变,则应保持编译后的模式不变:

    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