为什么正则表达式Matcher.find没有显示符合标准的单词

时间:2017-10-01 20:52:40

标签: java regex string matcher

给定的正则表达式代码是

import java.util.regex.*;

public class Test {
    public static void main(String[] args) {
        String longString = " Derek Banas CA 12345 PA (412)555-1212 johnsmith@hotmail.com 412-555-1234 412 555-1234 "; 
        regexChecker("\\s[A-Za-z]{2,20}\\s", longString);
    }

    public static void regexChecker(String theRegex, String str2Check){
        Pattern checkRegex = Pattern.compile(theRegex);     
        Matcher regexMatcher = checkRegex.matcher( str2Check );
        while ( regexMatcher.find() ){
            if (regexMatcher.group().length() != 0){
                System.out.println( regexMatcher.group().trim() );
                System.out.println( "Start Index: " + regexMatcher.start());
                System.out.println( "Start Index: " + regexMatcher.end());
            }
        }
    }
}

这里的输出是

Derek
Start Index: 0
Start Index: 7
CA
Start Index: 12
Start Index: 16
PA
Start Index: 21
Start Index: 25

1>为什么Derek的输出是'结束指数7'而不是6?
2>为什么'Banas'不是输出的一部分?

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:0)

您的模式包含非空格后的空格。这就解释了你的问题的两个:“Derek”和“Banas”之间的空间是第一场比赛的一部分,这使得它成为“Banas”比赛的一部分(因为你是在“巴纳斯”之前需要另一个空间来匹配)。

如果您同时将\\s更改为\\b,它将匹配字边界 - 不使用该空格。然后输出:

Derek
Start Index: 1
Start Index: 6
Banas
Start Index: 7
Start Index: 12
CA
Start Index: 13
Start Index: 15
PA
Start Index: 22
Start Index: 24
johnsmith
Start Index: 39
Start Index: 48
hotmail
Start Index: 49
Start Index: 56
com
Start Index: 57
Start Index: 60

此时你可能会得到你不想要的比赛。

您可以继续捕获前面的空白,但最后删除一个空格。像这样的模式:

regexChecker("\\s[A-Za-z]{2,20}", longString);

输出:

Derek
Start Index: 0
Start Index: 6
Banas
Start Index: 6
Start Index: 12
CA
Start Index: 12
Start Index: 15
PA
Start Index: 21
Start Index: 24
johnsmith
Start Index: 38
Start Index: 48

答案 1 :(得分:0)

模式匹配一​​个空格,2到20个ASCII字母和一个空格之后。这意味着第一个匹配的结尾是Derek之后的空格,即第7个索引。

这也说明了Banas不匹配的事实:第一场比赛已经消耗了Banas之前的空间,而第一场\sB不匹配,因此,Banas被跳过。

您需要使最后\s非消耗,请使用

"\\s[A-Za-z]{2,20}(?!\\S)"
                 ^^^^^^

请参阅regex demo

(?!\S)否定前瞻与字符串中的位置匹配,该位置后面紧跟着空格或字符串结尾。请注意,您也可以使用类似的&#34;技巧&#34;使用第一个\s,如果您将其转换为(?<!\S) lookbehind,"(?<!\\S)[A-Za-z]{2,20}(?!\\S)"。然后,没有空格将落在匹配值内。

请参阅this regex demo

解决此问题的另一种方法是使用\b字边界,这也是零宽度断言,"\\b[A-Za-z]{2,20}\\b"