前言
Pattern
Pattern p = Pattern.compile("a*b")
Matcher m = p.matcher("aaaaab")
boolean b = m.matches()
boolean b = Pattern.matches("a*b", "aaaaab")
Matcher
Matcher matcher = pattern.matcher("abcd");
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标志,则 ^ 在输入的开头和行结束符之后发生匹配,$ 在输入的结尾和行结束符之前匹配。
逻辑运算
字符
正则表达式 | 描述 | 例子 |
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,比如单词和单词的边界,符号和符号的边界。
这里的单词不是\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 ]
分割的字符串:[—]
分割的字符串:[—]
分割的字符串:[ _]
分割的字符串:[离]
转义
捕获组
非捕获组
非捕获组,它只分组而不捕获文本,也就不占用分组编号,普通非捕获组的语法是(?: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。