目录
一、正则表达式简介
正则表达式是用字符串描述的一个匹配规则,使用正则表达式可以快速判断给定的字符串是否符合匹配规则。Java 标准库 java.util.regex 内建了正则表达式引擎。
常见问题:
如何判断字符串是否有效电话号码 :例如 010-1234567 ,123ABC456,13537611000等。
示例
没有使用正则表达式粗略代码
boolean isValidMobileNumber(String s) {
// 是否是11位?
if (s.length() != 11) {
return false;
}
// 每一位都是0~9:
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c < '0' || c > '9') {
return false;
}
}
return true;
}
使用正则表达式
boolean isValidMobileNumber(String s) {
return s.matches("\\d{11}");
}
由此可见,使用正则表达式,不必编写复杂的代码来判断,只需要一个字符串表达式的正则规则即可。
二、匹配规则
字符 | 说明 |
\ | 转义字符,正则表达式需要使用\\匹配 |
^ | 匹配输入字符串开始位置 |
$ | 匹配字符串结尾的位置 |
* | 零次或者多次匹配前面字符串或者子表达式 |
+ | 一次或多次的字符串或子表达式 |
? | 零次或一次匹配前面的字符或子表达式 |
{n} | n是非负整数,正好匹配n次 |
{n,} | n是非负整数,至少匹配n次 |
{n,m} | n和m是非负整数,n<=m 。匹配至少n次,至多m次 |
. | 匹配单个字符,除“\r\n” |
x|y | 匹配x或者y |
[xyz] | 匹配包含xyz任何一个字符 |
[^xyz] | 匹配不包含xyz任何一个字符 |
[a-z] | 匹配a~z范围字符 |
\b | 匹配一个字边界 |
\B | 匹配非字边界 |
\d | 匹配数字。等效于[0-9] |
\D | 匹配非数字。等效于[^0-9] |
\f | 匹配换页符 |
\n | 匹配换行符 |
\r | 匹配回车键 |
\s | 匹配任何空白字符,包括空格、制表符、换页符。 |
\S | 匹配任何非空白字符 |
\t | 制表符匹配 |
\w | 匹配大小些字母、数字、下划线 |
\W | 非\w |
正则表达式规则是从左到右按规则匹配。对于正则表达式 “abc” 来说不能匹配“ab”,"Abc" ,“abcd”等其他字符串,只能匹配“abc”。
正则表达式有特殊字符,那就需要用\转义。例如a\&, 其中\&就是匹配特殊字符&的。
java中正则表达式是一个字符串。
示例
public class Main {
public static void main(String[] args) {
abc();
a();
}
private static void a() {
String regex = "a\\&"; 对应的正则是a\&
System.out.println("a&".matches(regex));// true
System.out.println("a&&".matches(regex));//false
}
private static void abc() {
String regex = "abc";
System.out.println("abc".matches(regex));// true
System.out.println("abcd".matches(regex));//false
System.out.println("Abc".matches(regex));//false
}
}
2.1、匹配任意一个字符
正则表达式的 . 可以匹配一个任意字符。
例如正则表达式 a.c可以匹配abc, a&c,acc 等。但是不能匹配ac,a&&c等,因为 . 匹配一个字符且限一个字符。
2.2、匹配常用字符
用\w可以匹配一个字母、数字、下划线。
例如 java\w 可以匹配 javac 、java_、java10。但是\w是不匹配#、空格。
2.3、匹配空格字符
用\s匹配一个空格字符。
例如 \s 匹配 "a c"中的空格字符。
2.4、匹配非数字
用\d可以匹配一个数字,而\D则匹配一个非数字。
例如\D可以匹配A或者#非数字字符。
2.5、重复匹配
可以使用 *,+,?,{n}, {n,},{n,m}等。
*匹配任意个字符,包括0 个字符。
例如A\d*可以匹配 A,A0,A3834
+匹配至少一个字符。
?匹配0个或一个字符。
2.6、匹配开头和结尾
用正则表达式进行多行匹配时,用^表示开头,$表示结尾。
例如 ^A\d{2}$, 匹配 "A01"、"A58"
2.7、匹配指定范围
可以使用 [...]指定范围。
例如 [1-9]{6} 可以匹配 123456、654321。
2.8、匹配分组
可以把一个子规则括起来实现分组。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String regex = "(\\d{3,4})\\-(\\d{6,8})";
Pattern p = Pattern.compile(regex);
String str = "010-12345678";
Matcher m = p.matcher(str);
if (m.matches()) {//判断是否匹配成功过
String g = m.group();
System.out.println(g);
String g0 = m.group(0); // "010-12345678" ,0表示整个字符串
String g1 = m.group(1);// "010" 1表示匹配第1个字符串
String g2 = m.group(2);// "12345678" 2表示匹配第2个字符串
System.out.println(g0);
System.out.println(g1);
System.out.println(g2);
}
}
}
如果匹配成功过, m.group() 与g0 是一样的值,就是匹配的整个字符串。
2.9、非贪婪匹配
先来看给示例,判断数字末尾0的个数。例如
"123000" : 3个0
"10100" : 2个0
"1001" : 0个0
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("(\\d+)(0*)");
Matcher matcher = pattern.matcher("1230000");
if (matcher.matches()) {
System.out.println("group1=" + matcher.group(1)); // "1230000"
System.out.println("group2=" + matcher.group(2)); // ""
}
}
}
打印第二子子串的是空字符串""。
期望结果
input | \d+ | 0* |
123000 | "123" | "000" |
10100 | "101" | "00" |
101 | "101" | "" |
但是实际结果
input | \d+ | 0* |
123000 | "123" | "" |
10100 | "101" | "" |
101 | "101" | "" |
因为正则表达式默认使用贪婪匹配:任何一个规则,尽可能多地向后匹配,因此 \d+ 会把0包含进来。
要让 \d+ 尽量少匹配,让0* 尽量多匹配,就必须让 \d+ 使用非贪婪匹配。在规则 \d+ 后面加个 ? 表示非贪婪匹配。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("(\\d+?)(0*)");// 非贪婪
Matcher matcher = pattern.matcher("1230000");
if (matcher.matches()) {
System.out.println("group1=" + matcher.group(1)); // "123"
System.out.println("group2=" + matcher.group(2)); // "0000"
}
}
}
示例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("(\\d??)(9*)");// 非贪婪
Matcher matcher = pattern.matcher("9999");
if (matcher.matches()) {
System.out.println("group1=" + matcher.group(1)); // ""
System.out.println("group2=" + matcher.group(2)); // "9999"
}
}
}
(\\d??)(9*) 中 \d? 匹配0个或1个数字,后面第二 ?表示非贪婪匹配。因此 字符串 "9999",匹配到两个子串分别是 "" 和 "9999"。对于 \d? 来说可以匹配1个9, 也可以匹配0个9。但是因为后面?表示非贪婪匹配,它就会尽可能少匹配,结果是匹配了0个9。
2.10、分割字符串
使用 string.split() 可以分割字符串。
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String strArr[] = "a b c".split("\\s");
System.out.println(Arrays.asList(strArr)); // [a, b, c]
}
}
2.11、搜索字符串
使用 Matcher 对象后,不需要调用 matches() 方法(因为匹配整个字符串肯定返回false),而是反复调用 find() 方法,在整个字符串中搜索能匹配上\\wo\\w规则的字串。并打印出来。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String s = "the quick brown fox jumps over the lazy dog.";
Pattern p = Pattern.compile("\\wo\\w");
Matcher m = p.matcher(s);
while(m.find()) {
String sub = s.substring(m.start(), m.end());
System.out.println(sub);
}
}
}
2.12、替换字符串
可以使用字符串可以直接调用 string.replaceAll() , 第一个参数是正则表达式,第二个参数是待替换的字符串。
public class Main {
public static void main(String[] args) {
String s = "the quick brown fox jumps over the lazy dog.";
String r = s.replaceAll("\\s([a-z]{4})\\s", " <b>$1</b> ");
System.out.println(r);
}
}