Java正则表达式的简单使用

前言

正则表达式是描述一组字符串的方法,它以这组字符串中的每个字符的共同特征为基础。正则表达式可以用于搜索、编辑、操纵文本与数据。你应该学习一种特殊的语法来创建正则表达式,这种语法已经超出了Java编程语言标准的语法。正则表达式的变化很复杂,不过一旦你理解了它们是如何被构造的话,你就能解释或者创建任意的正则表达式了。
java.util.regex包主要由Pattern、Matcher、 PatternSyntaxException类构成。

Pattern

Pattern对象表示一个已编译的正则表达式。Pattern 类没有提供公共的构造方法,要创建一个Pattern对象,首先必须调用公共的静态 compile 方法。
public static Pattern compile(String regex):将给定的正则表达式编译到Pattern中。
public static Pattern compile(String regex,int flags):将给定的正则表达式编译到具有给定标志的Pattern中。
常用标志如下,(?X)是嵌入到正则表达式的标志字符:
1、Pattern.CASE_INSENSITIVE(?i):默认情况下,大小写不明感的匹配只适用于US-ASCII字符集,这个标志能让表达式忽略大小写进行匹配。要想对Unicode字符进行大小不明感的匹配,只要将UNICODE_CASE与这个标志合起来就行了。例如:Pattern.matches("(?i:Ab)","ab")。
2、Pattern.COMMENTS(?x)在这种模式下,匹配时会忽略正则表达式里的空格字符,不是指表达式里的"\s",而是指表达式里的空格,tab,回车之类。注释从#开始,一直到这行结束。例如:Pattern.matches("(?x:#这行是备注\na b)","ab")。
3、Pattern.DOTALL(?s)在这种模式下,表达式'.'可以匹配任意字符,包括表示一行的结束符,默认不匹配行的结束符。例如:Pattern.matches("(?s:.)","\n")。
4、Pattern.MULTILINE(?m):在这种模式下,'^'和'$'分别匹配一行的开始和结束。此外,'^'仍然匹配字符串的开始,'$'也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
5、Pattern.UNICODE_CASE(?u): 在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不明感的匹配。默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。
6、Pattern.UNIX_LINES(?d): 在这个模式下,只有'\n'才被认作一行的结束。
7、Pattern.LITERAL:指定此标志后,指定Pattern的输入字符串就会作为字面值字符串来对待,输入字符串中的元字符或转义序列不具有任何特殊意义。 \Q和\E之间的字符串和这个模式作用一样。例如:Pattern.matches("\\Q.*\\E",".*")。

典型的调用顺序是:
Pattern p = Pattern.compile("a*b")
Matcher m = p.matcher("aaaaab")
boolean b = m.matches()

在仅使用一次正则表达式时,可以方便地通过此类定义 matches 方法,此方法编译表达式并在单个调用中将输入序列与其匹配。
boolean b = Pattern.matches("a*b", "aaaaab")

flags方法和pattern方法分别返回已编译的Pattern的标志和正则表达式。

split方法和string类的split方法一样,将给定字符串按照正则表达式拆分成数组。可以带一个参数或者两个参数,第二个参数n默认是0。如果n 大于零,那么模式至多应用 n-1 次,数组的长度不大于 n,并且数组的最后条目将包含除最后的匹配定界符之外的所有输入。如果 n 非正,那么将应用模式的次数不受限制,并且数组可以为任意长度。如果 n 为零,那么应用模式的次数不受限制,数组可以为任意长度,并且将丢弃尾部空字符串。

quote方法返回指定字符串的字面值模式字符串,即返回\Q\E这样的字符串。

Matcher

Matcher是一个解释Pattern和对输入字符串进行匹配操作的引擎。与 Pattern 相似,Matcher 也没有定义公共的构造方法,通过调用 Pattern 对象的matcher方法来获得一个 Matcher 对象:
Pattern pattern = Pattern.compile("abcd");
Matcher matcher = pattern.matcher("abcd");
默认是在整个输入序列中匹配,但是可以调用region方法设置输入序列中的一部分作为匹配区域。Matcher的显式状态包括最近成功匹配的开始和结束索引,由start和end方法获取。它还包括模式中每个捕获组捕获的输入子序列的开始(start(int group索引))和结束(end(int group索引))索引以及该子序列的总数(groupCount方法)。group方法还可以返回每个捕获组捕获的字符串,group(0)始终代表整个匹配,从group(1)开始才是捕获组。groupCount为0代表没有捕获组。Matcher的 reset() 方法重置Matcher,如果需要重新输入序列,则调用其 reset(CharSequence) 方法,重置Matcher将放弃其显式状态信息。
Matcher有三个匹配方法,matches、lookingAt、find,每个方法都返回一个表示成功或失败的布尔值。
matches:和Pattern.matches静态方法一样,将整个输入与正则进行匹配,整个字符串符合正则表达式,才返回true。
lookingAt:将输入从头开始与正则匹配,用来检测字符串的开头部分是否符合正则表达式,如果符合,返回true。
find:从当前位置开始匹配,找到一个匹配的字符串,下次匹配的位置将会变为匹配字符串最后一位的后面。

    public static void main(String[] args) {
        Pattern pattern = Pattern.compile("(\\d+)");
        Matcher matcher = pattern.matcher("123a4567b90d");
        while (matcher.find()) {
            System.out.println(matcher.group(1));
            System.out.println("匹配到的字符串开始索引:" + matcher.start());
            System.out.println("匹配到的字符串结束索引:" + (matcher.end() - 1));
        }
    }
123
匹配到的字符串开始索引:0
匹配到的字符串结束索引:2
4567
匹配到的字符串开始索引:4
匹配到的字符串结束索引:7
90
匹配到的字符串开始索引:9
匹配到的字符串结束索引:10

PatternSyntaxException

对象是一个未检查异常,表示正则表达式的一个语法错误。


构造摘要


行结束符

行结束符 是一个或两个字符的序列,标记输入字符序列的行结尾。以下代码被识别为行结束符:
新行(换行)符 ('\n')
后面紧跟新行符的回车符 ("\r\n")
单独的回车符 ('\r')
下一行字符 ('\u0085')
行分隔符 ('\u2028') 
段落分隔符 ('\u2029)
如果指定 UNIX_LINES(?d)标志,则新行符('\n')是唯一识别的行结束符。 
如果指定 DOTALL 标志,则正则表达式 . 可以与任何字符包括行结束符除外匹配。 
默认情况下,正则表达式 ^ 和 $ 忽略行结束符,仅分别与整个输入序列的开头和结尾匹配。如果指定MULTILINE标志,则 ^ 在输入的开头和行结束符之后发生匹配,$ 在输入的结尾和行结束符之前匹配。

逻辑运算

XY:X 后面跟着 Y
X|Y:X或Y

字符

正则表达式 描述 例子
x x代表的字符 Pattern.matches("a", "a")
\\ 反斜杠字符 Pattern.matches("\\\\", "\\")
\0n 8进制值n,Unicode码点等于此值的字符(0 <= n <= 7) Pattern.matches("\\00", (char) 0 + "")
\0nn 8进制值nn,Unicode码点等于此值的字符(0 <= n <= 7) Pattern.matches("\\061", "1")
\0mnn 8进制值mnn,Unicode码点等于此值的字符(0 <= m <= 3、0 <= n <= 7) Pattern.matches("\\0377", "ÿ")
\xhh 16进制值hh,Unicode码点等于此值的字符 Pattern.matches("\\x31", "1")
\uhhhh 16进制值hhhh,Unicode码点等于此值的字符 Pattern.matches("\\u597D", "好")
\x{h...h} 16进制值{h...h},Unicode码点等于此值的字符,支持辅助平面字符 Pattern.matches("\\x{597D}", "好")
\t 制表符 ('\u0009') Pattern.matches("\\u0009", "\t")
\n 换行符 ('\u000A') Pattern.matches("\\u000A", "\n")
\r 回车符 ('\u000D') Pattern.matches("\\u000D", "\r")
\f 换页符 ('\u000C') Pattern.matches("\\u000C", "\f")
\a 报警符 ('\u0007') Pattern.matches("\\u0007", "\a")
\e 转义符 ('\u001B') Pattern.matches("\\u001B", "\e")


字符类别

正则表达式 描述 例子
[abc] a,,b 或c Pattern.matches("[abc]", "a")
[^abc] 除a,,b或c之外的任意字符 Pattern.matches("[^abc]", "d")
[a-zA-Z] a到z或A到Z Pattern.matches("[a-zA-Z]", "a")
[a-d[m-p]] a到d或m到p,相当于[a-dm-p],并集 Pattern.matches("[a-d[m-p]]", "a")
[a-z&&[def]] d、e或f,交集 Pattern.matches("[a-z&&[def]]", "d")
[a-z&&[^bc]] a到z中除了b和c,相当于[ad-z] Pattern.matches("[a-z&&[^bc]]", "d")
[a-z&&[^m-p]] a-z中除了m到p,相当于:[a-lq-z] Pattern.matches("[a-z&&[^m-p]]", "d")


预定义字符类别

正则表达式 描述
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^\d]
\h 水平空白字符:[ \t\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]
\H 非水平空白字符
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\v 垂直空白字符:[\n\x0B\f\r\x85\u2028\u2029]
\V 非垂直空白字符
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]


边界匹配器

正则表达式 描述
^ 匹配行的开头,受多行模式影响
$ 匹配行的结尾,受多行模式影响
\b 单词边界
\B 非单词边界
\b:单词和符号之间的边界。
\B:不是\b的边界都属于\B,比如单词和单词的边界,符号和符号的边界。
这里的单词不是\w代表的0-9a-zA-Z_,我猜想应该是w的超集,包括比如汉字、希腊字母、英文字母、数字、下划线等等,符号可以是中文符号、英文符号、空格、制表符、换行符等等,更具体的包括哪些只能在实践中测试。参考下面的例子:
public static void main(String[] args) {  
        String str = "(我(i ——\t_离";  
        String rex = "\\b";  
        Pattern pattern = Pattern.compile(rex);  
        String[] result = pattern.split(str);  
        for (String string : result) {  
            System.out.println("分割的字符串:" + "[" + string + "]");  
        }  
    }  
分割的字符串:[(]  
分割的字符串:[我]  
分割的字符串:[(]  
分割的字符串:[i]  
分割的字符串:[ —— ]  
分割的字符串:[_离]  

public static void main(String[] args) {  
        String str = "(我(i ——\t_离";  
        String rex = "\\B";  
        Pattern pattern = Pattern.compile(rex);  
        String[] result = pattern.split(str);  
        for (String string : result) {  
            System.out.println("分割的字符串:" + "[" + string + "]");  
        }  
    }  
分割的字符串:[]  
分割的字符串:[(我(i ]  
分割的字符串:[—]  
分割的字符串:[—]  
分割的字符串:[    _]  
分割的字符串:[离]  


转义

反斜杠用于引进转义构造,还可以用于引用特殊字符,例如\\代表反斜杠,\(代表左圆括号。


捕获组

捕获组是通过从左到右计算其圆括号来编号的。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:((A)(B(C)))、(A)、(B(C))、(C),组编号0始终代表整个匹配。之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后调用Matcher类的group方法获取。

非捕获组

非捕获组,它只分组而不捕获文本,也就不占用分组编号,普通非捕获组的语法是(?:X),X是正则表达式构造。

数量词

Greedy

X?   X,一次或一次也没有
X*   X,零次或多次
X+   X,一次或多次
X{n}  X,恰好 n 次
X{n,}   X,至少 n 次
X{n,m}  X,至少 n 次,但是不超过 m 次
public static void main(String[] args) {
        Pattern p = Pattern.compile(".{3,10}[0-9]");
        String s = "abcd1efgh2";
        Matcher m = p.matcher(s);
        if (m.find())
            System.out.println(m.start() + "-" + m.end());
        else
            System.out.println("没匹配");
    }
输出:0-10
解释:Greedy是尽量吃入后再吐出。这个表达式 {3,10}吃入最多字符的10个字符:abcd1efgh2。吃入之后后面的[0-9]发现没有匹配的,吐出最后一个字符看是数字结果匹配。

Reluctant
X??   X,一次或一次也没有
X*?   X,零次或多次
X+?   X,一次或多次
X{n}?   X,恰好 n 次
X{n,}?   X,至少 n 次
X{n,m}?   X,至少 n 次,但是不超过 m 次
public static void main(String[] args) {
        Pattern p = Pattern.compile(".{3,10}?[0-9]");
        String s = "abcd1efgh2";
        Matcher m = p.matcher(s);
        if (m.find())
            System.out.println(m.start() + "-" + m.end());
        else
            System.out.println("没匹配");
    }
输出:0-5
解释:对于Reluctant 来说,就是Greedy的一个相反的匹配模式,他从左到有一个一个开始吃入,而不是整个字符串一个一个吐出。这个表达式{3,10}的吞入最少字符的3个字符:abc,吃入之后后面的[0-9]发现没有匹配的,再吃入1个字符后才有匹配。

Possessive
X?+   X,一次或一次也没有
X*+   X,零次或多次
X++   X,一次或多次
X{n}+   X,恰好 n 次
X{n,}+   X,至少 n 次
X{n,m}+   X,至少 n 次,但是不超过 m 次
 public static void main(String[] args) {
        Pattern p = Pattern.compile(".{3,10}+[0-9]");
        String s = "abcd1efgh2";
        Matcher m = p.matcher(s);
        if (m.find())
            System.out.println(m.start() + "-" + m.end());
        else
            System.out.println("没匹配");
    }
输出:没匹配
它和greedy类似,也是全部吃入,但是唯一不同的是它不吐出。


先行断言和后行断言

先行断言和后行断言其实就是预测之后的字符和之前的字符,只有首先符合预测结果,才能继续匹配,在预测过程中,匹配的位置不会变化,所以被称为“零宽”。例如,预测a后面是bc,那么所有a后面是bc的字符串符合,接着正常匹配,匹配位置依然从a后面开始而不是从c开始。以下4种都属于特殊结构的非捕获组。

(?=pattern) 正向先行断言 :代表字符串中的一个位置,紧接该位置之后的字符序列能够匹配pattern。
例如:Pattern.matches("a(?=b)bc", "abc")返回true。

(?!pattern) 负向先行断言 :代表字符串中的一个位置,紧接该位置之后的字符序列不能匹配pattern。
例如:Pattern.matches("a(?!bcd)bc", "abc")返回true,Pattern.matches("a(?!bc)bc", "abc")返回false。

 (?<=pattern) 正向后行断言 :代表字符串中的一个位置,紧接该位置之前的字符序列能够匹配pattern。
例如:Pattern.matches("a(?<=a)bc", "abc")返回true。

(?<!pattern) 负向后行断言 :代表字符串中的一个位置,紧接该位置之前的字符序列不能匹配pattern。
例如:Pattern.matches("a(?<!ab)bc", "abc")返回true,Pattern.matches("a(?<!a)bc", "abc")返回false。


开启关闭特殊标志

这里的标志就是Pattern类里的区分大小写、多行模式等。Pattern中大部分标志可以使用嵌入式字符串,也可以使用Pattern的常量进行设置。嵌入式字符串直接嵌入在正则表达式里,可以控制开启和关闭、是否捕获。标志前加“-”表示关闭。
(?idmsux-idmsux) :将开启或者关闭标志i d m s u x。
(?idmsux-idmsux:X):将开启或者关闭标志i d m s u x,仅对X有效,但是X是作为非捕获组。
例如:Pattern.matches("(?i)abc(?-i)abc", "aBCabc")返回true,Pattern.matches("(?i)abc(?-i)abc", "aBCaBc")返回false。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章