字符
教程 :JavaSchool
[Q&A] 什么是普通字符?
字母、数字、下划线、汉字等文字符号。没有特殊定义的标点符号。
[Q&A] 什么是转义字符?
字符本身有特殊含义,在其前面放置 \
才表示其字面意义
。或其自身的字面意义
前面加上 \
具有了特殊含义。
\f 换页符
\n 换行符
\r 回车符
\t 制表符
\v 垂直制表符
() [] {} ^ $ * + ? . | \ 在正则表达式里有特殊含义, \加上这些字符表示这些字符本身
\r \n \r\n 区别
拓展: java回车与换行的区别、CR LF CRLF区别、 \r \n \r\n区别、如何获取换行符呢?如何以换行符来分隔字符串?
[Q&A] java中对[
的正则匹配为什么需要用两个\
转义?
第一个\
是对后面 \
的转义,\\[
表示[
字符本身。 [Ref] java中对[的正则匹配为什么需要用两个\转义?
Pattern类
Java中Matcher类的matches和find的区别
字符集
[Q&A] 什么是标准字符集?
符号 | 含义 | 举例 |
---|---|---|
\d | 与任何十进制数字匹配 | \d 等效于 [0-9] |
\D | 与任何不是十进制数的字符匹配 | \D 等效于 [^0-9] |
\w | 与任何单词字符匹配 | \w 等效于 [a-zA-Z_0-9] |
\W | 与任何非单词字符匹配 | \W 等效于 [^a-zA-Z_0-9] |
\s | 与任何空白字符匹配 | \s 等效于 [ \f\n\r\t\v] ,注意还包含空格 |
\S | 与任何非空白字符匹配 | \S 等效于 [^ \f\n\r\t\v] |
[\s\S] | 所有字符 | |
. | 通配符,匹配除\n 外任一单个字符 |
[Q&A] 正则表达式 \w 可以匹配汉字吗
可以!\w
表示 A~Za~z0~9_
中任意一个。但是在某些情况下,\w
也会匹配本地字符集,比如中文系统的中文,全角数字等。一是要看你的系统是什么系统,中文系统下是可以匹配汉字的。二是要看你的应用环境,如果是在C# 程序中,是可以匹配汉字的,在javascript或验证控件中,是不可以匹配汉字的。所以在明确要求是A~Z,a~z,0~9,_
中的一个的时候,用[A-Za-z0-9_]
,而不用\w
。 [Ref] 正则表达式 \w 可以匹配汉字吗
split(“ “) 和 split(“\s+“) 的区别
Further Reading :split(“ “) 和 split(“\s+“) 的区别
[Q&A]什么是自定义字符集?
1・用[]
存放自定义的字符。
2・[]
可存放 .
外的标准字符集, .
仅表示 .
本身。
3・除 ^
和 -
其他特殊符号在 []
中都失去特殊含义。 ^
表示取反, -
表示范围。
小练习
[a5@] 匹配 "a" 或 "5" 或 "@" 之一的字符 验证第1条
[\d.+] 匹配: 数字 或 . 或 + 验证第2条
[^abc] 匹配 "a","b","c" 之外的任意一个字符 验证第3条
[c-k] 匹配 "c"~"k" 之间的任意一个字母 验证第3条
Pattern.compile("[a5@]").matcher("a").matches(); // true
Pattern.compile("[a5@]").matcher("aa").matches(); // false aa为非单字符所以match不上
Pattern.compile("[a5@]").matcher("aa").find(); // true
Pattern.compile("[\\\\]").matcher("\\").matches() // true
[Q&A] 正则表达式[\w]+,\w+,[\w+] 三者有何区别?
[\w]+
\w+
没有区别,都是匹配数字、字母、下划线的多个字符
[\w+]
表示匹配数字、字母、下划线和加号本身字符
[Q&A] [ABC]+,[\w.-+]+ 表达什么?
[ABC]+
匹配"AAABBBCCC
,BACCBACAACBAC
,...
",不一定按固定A…B…C…次序排列。
[\w.\-+]+
匹配[0-9a-zA-Z_]
或.
或-
或 +
字符, 在[]
外+
表示即至少1次或多次。
Pattern.compile("[\\w.\\-+]+").matcher("s").matches() // true
Pattern.compile("[\\w.\\-+]+").matcher(".").matches() // true
Pattern.compile("[\\w.\\-+]+").matcher("-").matches() // true
Pattern.compile("[\\w.\\-+]+").matcher("+").matches() // true
[Ref] 正则表达式[\w]+,\w+,[\w+] 三者区别? [],[ABC]+,[\w./-]+ 表达什么?
贪婪匹配
[Q&A] 什么是贪婪限定符、惰性限定符?
贪婪限定符 | 惰性限定符 | 描述 |
---|---|---|
* | *? | 匹配 >=0 次,相当于 {0,} |
+ | +? | 匹配 >=1 次,相当于 {1,} |
? | ?? | 匹配 0 or 1 次,相当于 {0,1} |
{n} | {n}? | 匹配 =n 次 |
{n,} | {n,}? | 匹配 >=n 次 |
{n,m}, | {n,m}? | 匹配 n<= <=m 次 |
a* "aabab" 匹配 "aa"、""、"a"、""、""
a*? "aabab" 匹配 ""、""、""、""、""、""
# 感觉 a*? 的效果就是 a{0}, 没啥实际意义吧
a+ "aabab" 匹配 "aa"、"a"
a+? "aabab" 匹配 "a"、"a"、"a"
# 感觉 a+? 的效果就是 a{1}, 没啥实际意义吧
a? "aabab" 匹配 "a"、"a"、""、"a"、""、""
a?? "aabab" 匹配 ""、""、""、""、""、""
# 感觉 a?? 的效果就是 a{0}, 没啥实际意义吧
Matcher matcher = Pattern.compile("a*").matcher("aabab");
while (matcher.find()) {
System.out.print(",\"" + matcher.group()+"\"");
}
[a-zA-Z]{2} "abcde" 匹配到 "ab"、"cd"
a{3} "aaabaaaa" 匹配到 "aaa"、 "aaa"
a{3}? "aaabaaaa" 匹配到 "aaa" 、 "aaa"
# 总结:感觉 a{3} 和 a{3}? 没区别
a{3,} "aabaaabaaaa"匹配到"aaa"、"aaaa"
a{3,}? "aabaaabaaaa"匹配到"aaa"、"aaa"
# 总结:感觉a{3,}?的效果就是 a{3}
a{1,3} "aabaaabaaca" 匹配 "aa"、"aaa"、"aa"、"a"
a{2,3}? "aabaaabaaca" 匹配 "aa"、"aa"、"aa"
# 总结:感觉a{2,3}?的效果就是 a{2}
[Q&A] 什么是贪婪匹配, 非贪婪匹配
.*
贪婪模式:使整个匹配成功的前提下使用最多的重复
.*?
非贪婪模式:使整个匹配成功的前提下使用最少的重复 [Ref] 正则表达式(.*?)惰性匹配()
# aabbabb里查找以a开始以b结束的字符串
# a.*b
Matcher matcher = Pattern.compile("a.*b").matcher("aabbab");
while (matcher.find()) {
System.out.println(matcher.group());
}
# aabbab
# a.*?b
Matcher matcher = Pattern.compile("a.*?b").matcher("aabbab");
while (matcher.find()) {
System.out.println(matcher.group());
}
# aab
# ab
字符边界
[Q&A] 什么是字符边界
[Ref] 正则字符边界
匹配模式
[Q&A] 什么是匹配模式
1、IGNORECASE
匹配时忽略大小写。默认情况下,区分大小写。
2、SINGLELINE
单行模式,整个文本看作一个字符串,只有一个开头,一个结尾。
3、MULTILINE
多行模式,每行都是一个字符串,都有开头和结尾。如果需要仅匹配字符串开始和结束位置,可以使用 \A
和 \Z
。
正则匹配忽略大小写
Pattern.compile("^(?i)doc$").matcher("doc").matches() // true
Pattern.compile("^(?i)doc$").matcher("DOC").matches() // true
[Q&A] 选择符
|
表 “或” 关系,匹配左边或者右边
th(e|is|at) 匹配 "the" "this" "that"
捕获组
[Q&A] 捕获组(exp)
1・在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰。
2・获取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到,每一对括号会分配一个编号,从 1 开始自动编号。编号为 0 的是由整个正则表达式匹配的文本 。
参考: Java正则表达式(简介+捕获组+语法+Matcher 类的方法+…干货!!.)
参考: Java正则表达式–Matcher.group函数的用法
参考: matcher.group()方法的使用
String line = "This order was placed for QT123! OK?";
Matcher matcher = Pattern.compile("(\\D*)(\\d+)(.*)").matcher(line);
if (matcher.find()) {
System.out.println("Found value: " + matcher.group(0)); // This order was placed for QT123! OK?
System.out.println("Found value: " + matcher.group(1)); // This order was placed for QT
System.out.println("Found value: " + matcher.group(2)); // 123
System.out.println("Found value: " + matcher.group(3)); // ! OK?
} else {
System.out.println("NO MATCH");
}
[Q&A] 非捕获组(?:exp)
一些表达式中,不得不使用()
,但又不需要保存()
中子表达式匹配的内容,这时可以用非捕获组来抵消使用()
带来的副作用 。
String line = "This order was placed for QT123! OK?";
Matcher matcher = Pattern.compile("(?:\\D*)(?:\\d+)(?:.*)").matcher(line);
if (matcher.find()) {
System.out.println("Found value: " + matcher.group()); // This order was placed for QT123! OK?
} else {
System.out.println("NO MATCH");
}
反向引用
[Q&A] 反向引用
每一对()
会分配一个编号,从 1 开始自动编号。通过反向引用,可以对分组已捕获的字符串进行引用。
[Ref] Java正则表达式之反向引用(Backreferences)
String source = "1234567890, 12345, and 9876543210";
Matcher matcher = Pattern.compile("\\b(\\d{3})(\\d{3})(\\d{4})\\b").matcher(source);
while (matcher.find()) {
System.out.println("Phone: " + matcher.group() + ", Formatted Phone: (" + matcher.group(1) + ") " + matcher.group(2) + "-" + matcher.group(3));
}
Phone: 1234567890, Formatted Phone: (123) 456-7890
Phone: 9876543210, Formatted Phone: (987) 654-3210
String source = "1234567890, 12345, and 9876543210";
Matcher matcher = Pattern.compile("\\b(\\d{3})(\\d{3})(\\d{4})\\b").matcher(source);
String formattedSource = matcher.replaceAll("($1) $2-$3");
(123) 456-7890, 12345, and (987) 654-3210
预搜索
[Q&A] 预搜索(零宽断言)
[Ref] : 关于正则表达式中?=、?!、?<=、?<!、?:的理解与应用
[Ref] : 正则表达式中?=和?:和?!的理解
# 后面是苹果的我喜欢
Pattern.compile("我喜欢(?=苹果)").matcher("我喜欢苹果汁").find()); true
Pattern.compile("我喜欢(?=苹果)").matcher("我喜欢柠檬汁").find()); false
Pattern.compile("我喜欢(?=苹果)").matcher("我喜欢苹果汁").replaceAll("我讨厌")); 我讨厌苹果汁
Pattern.compile("我喜欢(?=苹果)").matcher("我喜欢柠檬汁").replaceAll("我讨厌")); 我喜欢柠檬汁
# 后面不是苹果的我喜欢
Pattern.compile("我喜欢(?!苹果)").matcher("我喜欢苹果汁").find()); false
Pattern.compile("我喜欢(?!苹果)").matcher("我喜欢柠檬汁").find()); true
Pattern.compile("我喜欢(?!苹果)").matcher("我喜欢苹果汁").replaceAll("我讨厌")); 我喜欢苹果汁
Pattern.compile("我喜欢(?!苹果)").matcher("我喜欢柠檬汁").replaceAll("我讨厌")); 我讨厌柠檬汁
# 前面是苹果的汁
Pattern.compile("(?<=苹果)汁").matcher("我喜欢苹果汁").find()); true
Pattern.compile("(?<=苹果)汁").matcher("我喜欢柠檬汁").find()); false
Pattern.compile("(?<=苹果)汁").matcher("我喜欢苹果汁").replaceAll("干")); 我喜欢苹果干
Pattern.compile("(?<=苹果)汁").matcher("我喜欢柠檬汁").replaceAll("干")); 我喜欢柠檬汁
# 前面不是苹果的汁
Pattern.compile("(?<!苹果)汁").matcher("我喜欢苹果汁").find()); false
Pattern.compile("(?<!苹果)汁").matcher("我喜欢柠檬汁").find()); true
Pattern.compile("(?<!苹果)汁").matcher("我喜欢苹果汁").replaceAll("干")); 我喜欢苹果汁
Pattern.compile("(?<!苹果)汁").matcher("我喜欢柠檬汁").replaceAll("干")); 我喜欢柠檬干