淘先锋技术网

首页 1 2 3 4 5 6 7

Java正则匹配的语法,请参考:Pattern (Java Platform SE 8 )

matches和find区别

matches: 输入的字符串必须和正则一摸一样,类似字符串相等的比较方法, "b".equals("b");

find:输入的字符串里面只要包含了正则式表达的内容即可,类似字符串包含的方法, "b".contains("b");

        String word = "my number is 188"; // matches=false, find=true
        String word1 = "188999"; // matches=false, find=true
        String word2 = "8"; // matches=true, find=true
        Pattern p = Pattern.compile("\\d");
        Matcher m = p.matcher(word2);
        System.out.println(m.matches());
        System.out.println(m.find());

默认匹配案例

       String word = "ac\nab";
       Pattern p = Pattern.compile("^a.*");
       Matcher m = p.matcher(word);
       while (m.find()){
           System.out.println(m.group());
       }
//输出
// ac

上面的结果实际上只会输出ac,而ab并不会输出,这是因为Java正则中,如果出现了^ 或 $,默认情况下会忽略任何换行符,也就是说仅仅匹配第一行,后面的所有内容都会被忽略掉,如果我们想要不忽略,就得使用多行匹配模式

如果我们不使用 ^ 和 $ ,那么没问题可以匹配到所有,但如果我们就想在严格的 ^ 和 $ 中进行匹配呢?那么就得使用多行匹配模式了

多行匹配模式MULTILINE

多行匹配模式有两种语法

第一种,使用嵌入表达式:(?m)

       String word = "ac\nab";
       Pattern p = Pattern.compile("(?m)^a.*"); 
       Matcher m = p.matcher(word);
       while (m.find()){
           System.out.println(m.group());
       }
//输出
// ac
// ab
第二种,指定Flag参数:Pattern.MULTILINE
    String word = "ac\nab";
       Pattern p = Pattern.compile("^a.*", Pattern.MULTILINE);
       Matcher m = p.matcher(word);
       while (m.find()){
           System.out.println(m.group());
       }

全字符匹配模式DOTALL

在Java正则语法里面元字符 . 代表除了换行符外的任何字符,但有些时候我们就想匹配有换行符分隔的内容应该怎么做呢?

如果我们使用多行匹配模式,就会发现行不通

在Java里面使用 Pattern.DOTALL 参数 或者 (?s) 嵌入式表达式,代表让 . 代表所有字符,包含换行符
       String word = "run\nhad\noop";
//       Pattern p = Pattern.compile("h.*p", Pattern.DOTALL);
       Pattern p = Pattern.compile("(?s)h.*p");
       Matcher m = p.matcher(word);
       while (m.find()){
           System.out.println(m.group());
       }
// 输出
// had
// oop


联合模式匹配 MULTILINE & DOTALL

有时候我们的匹配规则,比较复杂,可能需要联合多种模式一起用:

比如下面的规则:

工作的很好,ok,现在我们需求改为 忽略换行符之后,仅匹配h开头和p结尾的字符串, 我们来分析下:

仅用MULTILINE肯定不行,因为h和p之间隔的有换行符

仅用DOTALL也不行,因为不区分多行,而是把整体当作一个大字符串了

所以只能联合 MULTILINE + DOTALL 两种模式了:

       String word = "run\nhad\noop\nhi\nspx";
//     Pattern p = Pattern.compile("(?ms)^h.*p$"); //嵌入式表达式
       Pattern p = Pattern.compile("^h.*p$", Pattern.DOTALL | Pattern.MULTILINE);
       Matcher m = p.matcher(word);
       while (m.find()){
           System.out.println(m.group());
       }
// 输出
// had
// oop

忽略大小写CASE_INSENSITIVE

       String word = "cAt";
       Pattern p = Pattern.compile("(?i)^h.*p$");
//       Pattern p = Pattern.compile("cat", Pattern.CASE_INSENSITIVE);
       Matcher m = p.matcher(word);
       while (m.find()){
           System.out.println(m.group());
       }


Linux换行符UNIX_LINES

默认模式中\r\n都会被当做换行符:

       String input= "This is the first line\r"
               + "This is the second line\r"
               + "This is the third line\r";
       Pattern p = Pattern.compile("^T.*e");
       Matcher m = p.matcher(input);
       while (m.find()){
           System.out.println("["+m.group()+"]");
       }
// 输出
// [This is the first line]

当指定了UNIX_LINES后,只会在. ^ $ 中,其他的换行字符都会都会当成一个普通字符

    String input= "This is the first line\r"
               + "This is the second line\r"
               + "This is the third line\r";
       Pattern p = Pattern.compile("^T.*e", Pattern.UNIX_LINES);
       Matcher m = p.matcher(input);
       while (m.find()){
           System.out.println("["+m.group()+"]");
       }
// 输出
// This is the third line]

注意 \r 代表回车,会覆盖之前输出的内容,所以这里看到的结果是最后一段的结果

增加注释COMMENTS

可以在正则中加入解释

       String input= "abc\nbbc";
       Pattern p = Pattern.compile("a.*c # 寻找以a开头以c结尾的单词", Pattern.COMMENTS);
       Matcher m = p.matcher(input);
       while (m.find()){
           System.out.println("["+m.group()+"]");
       }

文字解析模式LITERAL

       String input= "abc\nbbc";
		//仅能与 CASE_INSENSITIVE 和 UNICODE_CASE 搭配
       Pattern p = Pattern.compile("a.*", Pattern.LITERAL);
       Matcher m = p.matcher(input);
       while (m.find()){
           System.out.println("["+m.group()+"]");
       }
// 输出为空,所有的元字符会被当成普通字符

非ASCII编码忽略大小写UNICODE_CASE

默认情况下忽略大小写匹配仅支持ASCII编码,如果非ASCII编码需要使用 UNICODE_CASE 和 CASE_INSENSITIVE 组合才有效果

       String input= "À";
       Pattern p = Pattern.compile("à", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
       Matcher m = p.matcher(input);
       while (m.find()){
           System.out.println("["+m.group()+"]");
       }

UNICODE_CHARACTER_CLASS模式

启用此模式,可以使用一些特定匹配规则:

Classes	Matchesb
\p{Lower}	A lowercase character:\p{IsLowercase}
\p{Upper}	An uppercase character:\p{IsUppercase}
\p{ASCII}	All ASCII:[\x00-\x7F]
\p{Alpha}	An alphabetic character:\p{IsAlphabetic}
\p{Digit}	A decimal digit character:p{IsDigit}
\p{Alnum}	An alphanumeric character:[\p{IsAlphabetic}\p{IsDigit}]
\p{Punct}	A punctuation character:p{IsPunctuation}
\p{Graph}	A visible character: [^\p{IsWhite_Space}\p{gc=Cc}\p{gc=Cs}\p{gc=Cn}]
\p{Print}	A printable character: [\p{Graph}\p{Blank}&&[^\p{Cntrl}]]
\p{Blank}	A space or a tab: [\p{IsWhite_Space}&&[^\p{gc=Zl}\p{gc=Zp}\x0a\x0b\x0c\x0d\x85]]
\p{Cntrl}	A control character: \p{gc=Cc}
\p{XDigit}	A hexadecimal digit: [\p{gc=Nd}\p{IsHex_Digit}]
\p{Space}	A whitespace character:\p{IsWhite_Space}
\d	A digit: \p{IsDigit}
\D	A non-digit: [^\d]
\s	A whitespace character: \p{IsWhite_Space}
\S	A non-whitespace character: [^\s]
\w	A word character: [\p{Alpha}\p{gc=Mn}\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}\p{IsJoin_Control}]
\W	A non-word character: [^\w]

这里的匹配使用的unicode下的表示字符,参考:UTS #18: Unicode Regular Expressions

搜索 punctuation 关键词,可以看到unicode下的表示符号,就是我们键盘上非数字非字母部分的符号表示:

       Pattern p = Pattern.compile("\\p{Punct}");
       Matcher m = p.matcher("`");
       System.out.println(m.matches()); // returns true
       
       Pattern p1 = Pattern.compile("\\p{Punct}", Pattern.UNICODE_CHARACTER_CLASS);
       Matcher m1 = p1.matcher("`");
       System.out.println(m1.matches()); // returns false

注意上面的第二个不匹配,因为启动了UNICODE_CHARACTER_CLASS,必须用UNICODE_CHARACTER_CLASS下的字符表示才可以匹配

UNICODE的同等关系的CANON_EQ模式

这个一般用在UNICODE的字符中,举个例子:

“◌̇” U+0307 Combining Dot Above Unicode Character

unicode字符U+0307 代表字母上方的一个点 ḃ

而通过 b + \u0307 就能组成 ḃ , 而 ḃ 也有专门的unicode字符表示: \u1E03

也就是说 b\u0307 = \u1E03

在Java的正则里面,如果想要等价表示这个关系,就必须使用CANON_EQ模式匹配才可以

    String regex = "b\u0307";
        System.out.println(regex);
        System.out.println("\u1E03");
        Pattern pattern = Pattern.compile(regex, Pattern.CANON_EQ);
        Matcher matcher = pattern.matcher("\u1E03");
        if(matcher.matches()) {
            System.out.println("Match found");
        } else {
            System.out.println("Match not found");
        }
// 输出
// ḃ
// ḃ
// Match found