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

时间:2010-09-29 09:03:58

标签: java regex 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(匹配)循环?和/或模式/匹配类?

6 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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

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

有两种微观优化:

  1. 无需额外保留模式 变量,内联
  2. 对于别名,搜索单词 字符,而不是非空格字符
  3. 实际上,如果你做了很多这样的处理并且模式永远不会改变,你应该将编译后的模式保持为常量:

    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)的条目。我认为这是一个非常公平的性能,如果不编写自己的专用解析器,我无法看到如何显着优化它。

相关问题