正则表达式中的常用字符
特殊字符及其操作
特殊字符 | 说明 |
---|---|
^ | 边界匹配符:匹配一行的开头,不占用字符 |
$ | 边界匹配符:匹配一行的结尾,不占用字符 |
. | 表示任何单个字符 |
? | 前一个字符 0 次或 1 次扩展 |
* | 前一个字符 0 次或 无限次扩展 |
+ | 前一个字符 1 次或 无限次扩展 |
| | 指定两项之间任选一项,例 abc | def 表示 abc、def |
\ | 用于转义下一个字符 |
( ) | 分组标记,可将多个表达式合并成一个子表达式,内部只能使用 | 操作符 |
[ ] | 字符集,对单个字符给出范围 |
{m} | 前一个字符 m 次扩展 |
{m,n} | 前一个字符 m-n 次扩展 |
上述所有的字符为正则表达式中定义的特殊字符,如果要匹配它们字符本身,需要进行转义。特别的在Java中,也是用 \ 来转义,Java中如果要匹配这些特殊字符需要经过两轮转义,即
\\
,所以在Java中要匹配 \ ,需要\\\\
。
^ 和 $ 的用法:
例如:
[a-z]
可以用来匹配字符串任意位置上的小写字母: “…a…”^[a-z]
只能匹配字符串行首的小写字母: “a…”[a-z]$
只能匹配字符串行尾的小写字母: “…a”^[a-z]$
只能匹配只有一个小写字母的字符串行中的小写字母: “a”
public static void main(String[] args) {
// test ^ $
Pattern pattern1 = Pattern.compile("[a-z]");
Matcher matcher1 = pattern1.matcher("12a34");
if (matcher1.find())
System.out.println(matcher1.group()); // 输出 a
else
System.out.println("Not found");
Pattern pattern2 = Pattern.compile("^[a-z]");
Matcher matcher2 = pattern2.matcher("12a34");
if (matcher2.find())
System.out.println(matcher2.group());
else
System.out.println("Not found"); // 输出 Not found
Pattern pattern3 = Pattern.compile("^[a-z]");
Matcher matcher3 = pattern3.matcher("a34");
if (matcher3.find())
System.out.println(matcher3.group()); // 输出 a
else
System.out.println("Not found");
Pattern pattern4 = Pattern.compile("[a-z]$");
Matcher matcher4 = pattern4.matcher("12a34");
if (matcher4.find())
System.out.println(matcher4.group());
else
System.out.println("Not found"); // 输出 Not found
Pattern pattern5 = Pattern.compile("[a-z]$");
Matcher matcher5 = pattern5.matcher("12a");
if (matcher5.find())
System.out.println(matcher5.group()); // 输出 a
else
System.out.println("Not found");
Pattern pattern6 = Pattern.compile("^[a-z]$");
Matcher matcher6 = pattern6.matcher("a1");
if (matcher6.find())
System.out.println(matcher6.group());
else
System.out.println("Not found"); // 输出 Not found
Pattern pattern7 = Pattern.compile("^[a-z]$");
Matcher matcher7 = pattern7.matcher("a");
if (matcher7.find())
System.out.println(matcher7.group()); // 输出 a
else
System.out.println("Not found");
}
方括号表达式对单个字符的限定
- 枚举:[abc] 表示 a、b、c中的任意一个字符
- 范围:[a-z] 表示 a、b、c、…、z中的任意一个字符
- 排除:[^abc] 表示 除了a、b、c的任意一个字符
- 交集:[a-z&&[def]] 表示 a-z和def交集中的任意一个字符
- 并集:[a-c[def]] 表示 a-c和def并集中的任意一个字符,也就是[a-cdef]
预定义字符
预定义子符 | 说明 |
---|---|
\d | 匹配数字,等价于[0-9] |
\D | 匹配非数字 |
\w | 匹配所有的单词字符,等价于[0-9A-Za-z_](注意:包括下划线) |
\W | 匹配所有的非单词字符 |
贪婪匹配和最小匹配
贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下
,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下
,尽可能少的匹配。
贪婪匹配
- 贪婪匹配: 尽可能多的匹配,在第一次匹配成功的前提下,仍向后尝试匹配直至匹配失败终止
- 属于贪婪匹配的的量词,也叫做匹配优先量词,包括:
?
、*
、+
、{m,n}
、{m,}
。
最小匹配(非贪婪匹配)
- 最小匹配:匹配到第一次使表达式成立是即停止匹配
- 在一些使用NFA引擎的语言中,在匹配优先量词后加上
?
,即变成属于非贪婪匹配的量词,也叫做忽略优先量词,包括:??
、*?
、+?
、{m,n}?
、{m,}?
// test 贪婪
String p1= "[a-z]";
String p2= "[a-z]+";
String p3= "[a-z]+?";
Pattern patternT = Pattern.compile(p3);
Matcher matcherT = patternT.matcher("asd");
while (matcherT.find())
System.out.println(matcherT.group());
/*Output:
p1:
a
s
d
p2:
asd
p3:
a
s
d
*/
正则表达式中的环视
环视基础
环视只进行子表达式的匹配,不占有字符,匹配到的内容无论true or false都不保存到最终的匹配结果,是零宽度的,环视匹配的最终结果就是一个位置,所以又叫做断言或预搜索。
环视的作用相当于对所在位置加了一个附加条件,只有满足这个条件,环视子表达式才能匹配成功。
环视分类
环视按照方向划分有顺序和逆序两种,按照是否匹配有肯定和否定两种,组合起来就有四种环视。顺序环视相当于在当前位置右侧附加一个条件,而逆序环视相当于在当前位置左侧附加一个条件。
(?=Expression)
: 顺序肯定,表示 如果所在位置右侧字符能够匹配Expression 则 匹配成功,定位到该位置;(?!Expression)
: 顺序否定,表示 如果所在位置右侧字符不能匹配Expression 则 匹配成功(即排除能匹配Expression的),定位到该位置;(?<=Expression)
: 逆序肯定,表示 如果所在位置左侧字符能够匹配Expression 则 匹配成功,定位到该位置;(?<!Expression)
: 逆序否定,表示 如果所在位置左侧字符不能匹配Expression 则 匹配成功(即排除能匹配Expression的),定位到该位置。
环视的通俗理解
环视只是一个判断条件,它的作用就是通过判断把我们带到想要的位置,也就是说你想得到的匹配 or 不匹配某个Expression的位置。
-
对于
顺序肯定
环视而言:?
代表未知的判断结果(true or false),?=Expression
代表这个结果 等于 当前位置右侧字符匹配 Expression 返回的结果(true or false),并且返回?
的值,即如果当前位置右侧字符匹配 Expression 返回 true,则?=true
,这个时候整个环视表达式为 true,从而定位到当前字符,代表找到了我们想要的位置。 -
对于
顺序否定
环视而言:?
代表未知的判断结果(true or false),?!Expression
代表这个结果 等于 当前位置右侧字符匹配 Expression 返回的结果(true or false)再取反,并且返回?
的值,即如果当前位置右侧字符匹配 Expression 返回 false,则?=true
,这个时候整个环视表达式为 true,从而定位到当前字符,代表找到了我们想要的位置。 -
对于逆序只是对当前位置左侧字符进行判断,其他分析过程完全相同。
环视示例
- 匹配小括号中的内容:
"(?<=\()[^)]+"
- 匹配中括号中的内容:
"(?<=\[)[^]]+"
- 匹配大括号中的内容:
"(?<=\{)[^}]+"
上面正则表达式中第一个小括号里(?<=\()
即逆序肯定环视,其中 Expression 为\(
,因为 (
为特殊字符,所以要先转义。这个环视最终的效果是找到在该字符位置左边为 (
的字符,并返回它的位置,后面的[^)]
代表匹配一个不是)
的字符,换言之即遇到)
就停止,后面的+
代表贪婪匹配,对前面的单个字符进行贪婪匹配,即只要条件满足一直匹配下去直到遇到)
。
// test 逆序肯定
Pattern patternN = Pattern.compile("(?<=\\()[^)]+"); // 注意这里 java 转义要用 //
Matcher matcherN = patternN.matcher("(123 $#%$#^3 adsad)");
if (matcherN.find())
System.out.println(matcherN.group()); // 输出 123 $#%$#^3 adsad
else
System.out.println("Not found");
// test 顺序肯定 -- 注意输出多了个 (
Pattern patternS = Pattern.compile("(?=\\()[^)]+");
Matcher matcherS = patternS.matcher("(123 $#%$#^3 adsad)");
if (matcherS.find())
System.out.println(matcherS.group()); // 输出 (123 $#%$#^3 adsad
else
System.out.println("Not found");
经典正则表达式实例
正则表达式 | 含义 |
---|---|
^[A‐Za‐z]+$ | 由26个字母组成的字符串 |
^[A‐Za‐z0‐9]+$ | 由26个字母和数字组成的字符串 |
^‐?\d+$ | 整数形式的字符串 |
^[0‐9]*[1‐9][0‐9]*$ | 正整数形式的字符串 |
[1‐9]\d{5} | 中国境内邮政编码,6位 |
[\u4e00‐\u9fa5] | 匹配中文字符 |
\d{3}-\d{8}|\d{4}-\d{7} | 匹配国内电话号码 |