正则表达式
正则表达式(Regular Expression、regex或regexp,缩写为RE),描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
1 正则表达式语法
在java语言中,java.util.regex.Pattern类是正则表达式的编译表示形式。 相应的语法规则,在此类的API中定义。
1.1 字符
x 字符x,任意字符代表其本身
\\ 反斜线字符(\)
\t 制表符 ('\u0009')
\n 换行符 ('\u000A')
\r 回车符 ('\u000D')
\f 换页符 ('\u000C')
1.2 字符类
[abc] 匹配a、b 或 c中的一个字符(简单类)
[^abc] 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z中的一个字符,两头的字母包括在内(范围)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]] d、e 或 f(交集)
1.3 预定义字符类
. 匹配任意字符
\d 匹配数字字符,相当于[0-9]
\D 匹配非数字字符,相当于[^0-9]
\s 空白字符,相当于[ \t\n\x0B\f\r] ,匹配所有空白符,包括换行
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9] ,匹配字母、数字、下划线
\W 非单词字符:[^\w]
1.4 边界匹配器(定位符)
^ 行的开头
$ 行的结尾
\b 单词边界 匹配一个位置 0宽度
\B 非单词边界
1.5 限定符
X? X,一次或一次也没有。匹配前面的子表达式X零次或一次。
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次
1.6 捕获组
() 表示捕获分组,() 会把每个分组里的匹配的值保存起来, 多个匹配值可以通过数字 n 来查看(n 是一个数字,表示第 n 个捕获组的内容)。
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C)))
中,存在四个这样的组:
1 ((A)(B(C)))
2 (A)
3 (B(C))
4 (C)
组零始终代表整个表达式。
2 正则表达式的使用(重点)
下面从常见的几个使用场景,简单介绍正则表达式的使用方法。
1、正则表达式的校验功能
String类中的API:
public boolean matches(String regex)
判断此字符串是否与给定的正则表达式匹配
示例:
数据校验 -- 例如校验用户输入的邮箱是否合法
// 通用的邮箱标准:长度不限,可以使用英文(包括大小写)、数字、点号、下划线、减号,首字母必须是字母或数字。
String regex = "^[a-z0-9A-Z]+[-|a-z0-9A-Z._]+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-z]{2,}$";
// 下面四个邮箱都是符合规则的有效数据
String email1 = "xxxyyy@zzz.com.cn";
String email2 = "xxx-yyy@zzz.com";
String email3 = "xxx_yyy@zzz.cn";
String email4 = "88888@qq.com";
System.out.println(email1.matches(regex));
System.out.println(email2.matches(regex));
System.out.println(email3.matches(regex));
System.out.println(email4.matches(regex));
2、正则表达式的替换功能
String类中的API:
public String replaceAll(String regex, String replacement)
将此字符串中匹配给定正则表达式的所有子串替换
参数1表示正则表达式,符合此规则的子串将被替换
参数2表示要要替换每个匹配项的字符串
public String replaceFirst(String regex, String replacement)
将此字符串中匹配给定正则表达式的第一个子串替换
示例:
// 将下面文本中的手机号码全部使用****代替
String str = "张三的电话号码是:13877778888,李四的电话号码是:13966669999,王五的电话号码是:18898765432。";
String regex = "1[3456789]\\d{9}";
String repStr = str.replaceAll(regex, "****");
System.out.println(repStr);
// 输出结果:张三的电话号码是:****,李四的电话号码是:****,王五的电话号码是:****。
// ------------------------------
// 将下面文本中的第一个手机号码使用****代替
String str = "张三的电话号码是:13877778888,李四的电话号码是:13966669999,王五的电话号码是:18898765432。";
String regex = "1[3456789]\\d{9}";
String repStr = str.replaceFirst(regex, "****");
System.out.println(repStr);
// 输出结果:张三的电话号码是:****,李四的电话号码是:13966669999,王五的电话号码是:18898765432。
3、正则表达式的拆分功能
String类中的API:
public String[] split(String regex)
使用指定的正则表达式将此字符串拆分,返回拆分后得到的字符串数组
注意:结尾的空字符串不包含在结果数组中。
例如:
字符串"boo:and:foo",使用正则表达式":"进行拆分,得到{"boo", "and", "foo"}
字符串"boo:and:foo",使用正则表达式"o"进行拆分,得到{"b", "", ":and:f"}
中间连续的两个"o"匹配,拆分出一个空串,而结尾处的两个"o"匹配,得到的空串不会保留。
示例:
String str = "11 22 33 44 55";
// 将上面文本中的有效数据拆分出来,注意:数据中间的空格数量不确定。
String[] strs = str.split("\\s+"); // 按照一个或多个空白字符拆分
System.out.println(Arrays.toString(strs)); // [11, 22, 33, 44, 55]
4、正在表达式的获取功能
在java.util.regex 包主要包括以下三个类:
-
Pattern 类:
Pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
-
Matcher 类:
Matcher 对象是对输入字符串进行解释和匹配操作的引擎(匹配器)。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
-
PatternSyntaxException:
PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
典型使用顺序如下:
Pattern p = Pattern.compile("a*b"); // 将字符串形式的正则表达式编译为Pattern类的实例
Matcher m = p.matcher("aaaaab"); // 创建一个匹配此模式的给定输入的匹配器
boolean b = m.matches(); // 判断输入的字符串是否匹配此模式
在Matcher 类中,有如下三个常用方法:
public boolean matches()
尝试将整个字符串与模式匹配
public boolean find()
尝试查找与模式匹配的输入序列的下一个子序列
public String group()
返回上一个匹配项匹配的输入子序列
示例:
// 将下面文本中的手机号码全部获取出来
String str = "张三的电话号码是:13877778888,李四的电话号码是:13966669999,王五的电话号码是:18898765432。";
// 获取正则表达式模式对象
Pattern pattern = Pattern.compile("1[3456789]\\d{9}");
// 根据模式对象获取匹配器对象
Matcher matcher = pattern.matcher(str);
// 如果可以找到匹配的子串
while (matcher.find()) {
// 获取匹配的子串
String subStr = matcher.group();
System.out.println(subStr);
}
5、捕获组的使用
示例:
// 现得到如下的字符串:
String s = "我..我....我.我...我.要.要...要...要..要...要.学..学.学...学.学.编...编.编..编...编...程程..程..程";
// 请还原出其中的有效信息:我要学编程
// 首先替换掉所有的点
s = s.replaceAll("\\.", "");
// 再匹配其中的叠词(即重复出现的字符),只保留一份
s = s.replaceAll("(.)\\1+", "$1");
// 将任意字符放入组中,\1表示组1(即该字符)再次出现一次或多次;第二个参数$1表示引用组1的内容。
System.out.println(s);
常用正则表达式
汉字:^[\u4e00-\u9fa5]$
英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
Email地址:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
URL:/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
IP 地址:/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
身份证号:var p = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;