正则表达式(regex,RE)

本文详细介绍了正则表达式的各种语法特性,包括基本字符匹配、量词、零度断言、捕获组等内容,并提供了JAVA及JavaScript环境下的使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

正则表达式是作用于字符串的一种校验语法,通过特定字符(0-9,A-Z,a-z等)组合而形成的一种具有校验功能的"校验字符串"

1 语法规则

1.1 匹配一个字符(字母大写取反)

        \d匹配数字(0-9)

        \w匹配数字(0-9),字母(A-Z,a-z),下划线(_)

        \s空白符(空格,换行符,制表符)

        \n换行符

        .匹配任意一个字符(不包括换行符\n)    //常用[\s\S]表示所有字符

"2".matches("\\d"); //结果为true
"测".matches("\\D"); //结果为true

"2".matches("\\w"); //结果为true
"A".matches("\\w"); //结果为true
"a".matches("\\w"); //结果为true
"_".matches("\\w"); //结果为true
"测".matches("\\W"); //结果为true

" ".matches("\\s"); //结果为true

"测".matches("."); //结果为true
"\n".matches("."); //结果为false

"\n".matches("[\\s\\S]"); //结果为true

1.2 自定义匹配一个字符([^regex]表示取反)

        将自定义regex放在[ ]中,只要符合其中的一个字符即可

        -为连接符,[A-Z]表示A~Z中的一个

        匹配汉字采用unicode码    //匹配所有汉字[\u4e00-\u9fa5]

"f".matches("[a-z]");  //结果为true
"f".matches("[^a-z]");  //结果为false
"F".matches("[^a-z]");  //结果为true
"2".matches("[^a-z]");  //结果为true

"正".matches("[\u6b63]");  //结果为true
"则".matches("[\u4e00\u9fa5]");  //结果为false
"表".matches("[\u4e00-\u9fa5]");  //结果为true

1,3 量词:规定"一个"表达式出现的次数

        {n}匹配n次

        {m,}至少匹配m次

        {m,n}至少匹配m次,至多匹配n次

        ?匹配0次或1次,相当于{0,1}

        +至少匹配一次,相当于{1,}

        *匹配0次或任意次,相当于{0,}

"123".matches("\\d{3}");  //结果为true
"123".matches("\\d{2}");  //结果为false

"123".matches("\\d{2,}");  //结果为true

"123".matches("\\d{2,4}");  //结果为true

"1".matches("\\d?");  //结果为true

"12345".matches("\\d+");  //结果为true

"12345".matches("\\d*");  //结果为true

        +和*匹配模式都是"贪婪模式(即尽可能地匹配)"

        只要在它们后面加上一个?就可以变为"非贪婪模式(即尽可能地匹配)"

                例: "<h1>一号字体</h1>"用"<.*>"匹配到1处"<h1>一号字体</h1>"

                     "<h1>一号字体</h1>"用"<.*?>"匹配到2处"<h1>一号字体</h1>"

1.4 零度断言

        先解释一下名词:"零度断言"分为"零度"和"断言"

                零度:就是指没有宽度,即向前或向后不占字符

                断言:指明在特定内容之前或之后并满足相应规则的内容,类比生活中常说的"我断定什么",例如"我断定站着一个"

        断言符号:①exp1(?=exp2)  匹配exp1,但同时exp1后面的内容要满足exp2

                        ②exp1(?!exp2)  匹配exp1,但同时exp1后面的内容不满足exp2

                        ③(?<=exp2)exp1  匹配exp1,但同时exp1前面的内容要满足exp2

                        ④(?<!exp2)exp1  匹配exp1,但同时exp1前面的内容不满足exp2

"1regex456apple789".split("[a-z]{5}(?=\\d{3})");  //返回数组[1, 456, 789]
"1regex56apple789".split("[a-z]{5}(?!\\d{3})");  //返回数组[1, 56apple789]
"1regex456apple789".split("(?<=\\d{3})[a-z]{5}");  //返回数组[1regex456, 789]
"1regex456apple789".split("(?<!\\d{3})[a-z]{5}");  //返回数组[1, 456apple789]

1.5 捕获组

        把被"子表达式"匹配到的数据保存在内存中,并按数字编号形成"数字捕获组"或按显式命名形成"命名捕获组",方便后面引用(正则表达式内部引用,正则表达式外部引用)

1.5.1 数字捕获组

        分组规则:从整个正则表达式从左往右找,(第n次出现即捕获组编号就是n,同时和与之对应的)以及两者包含的表达式共同形成n号捕获组,第0组则表示整个正则表达式

捕获组正则表达式匹配内容
0(\d{4})-(\d{2}-(\d\d))2022-08-21
1(\d{4})2022
2(\d{2}-(\d\d))08-21
3(\d\d)21
Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2}-(\\d\\d))");
Matcher matcher = pattern.matcher("2022-08-21");
while (matcher.find()) {
	System.out.println(matcher.group(0));
	System.out.println(matcher.group(1));
	System.out.println(matcher.group(2));
	System.out.println(matcher.group(3));
}

//2022-08-21
//2022
//08-21
//21

1.5.2 命名捕获组

        语法规则:(?<name>regex)

                例: (?<hour>(0[1-9]|1\d|2[0-3])):(?<minute>([0-5]\d)):(?<second>([0-5]\d))

捕获组正则表达式匹配内容
0

((0[1-9]|1\\d|2[0-3])):(([0-5]\\d)):(([0-5]\\d))

16:14:22
hour((0[1-9]|1\\d|2[0-3]))16
munite(([0-5]\\d))14
second(([0-5]\\d))22
Pattern pattern = Pattern.compile("(?<hour>(0[1-9]|1\\d|2[0-3])):(?<minute>([0-5]\\d)):(?<second>([0-5]\\d))");
Matcher matcher = pattern.matcher("16:14:22");
while (matcher.find()) {
	System.out.println(matcher.group(0));
	System.out.println(matcher.group("hour"));
	System.out.println(matcher.group("minute"));
	System.out.println(matcher.group("second"));
}

//16:14:22
//16
//14
//22

1.5.3 非捕获组

        博主个人认为叫"失效捕获组"更为贴切,因为它会让原本的捕获组失效

        语法规则:(?:regex)

                例: (?:\d{4})-(\d{2}-(\d\d))

捕获组正则表达式匹配内容
0(\d{4})-(\d{2}-(\d\d))2022-08-21
1(\d{2}-(\d\d))08-21
2(\d\d)21
Pattern pattern = Pattern.compile("(?:\\d{4})-(\\d{2}-(\\d\\d))");
Matcher matcher = pattern.matcher("2022-08-21");
while (matcher.find()) {
	System.out.println(matcher.group(0));
	System.out.println(matcher.group(1));
	System.out.println(matcher.group(2));
}

//2022-08-21
//08-21
//21

1.5.4 捕获组的引用

        捕获组引用的是捕获的"内容",即匹配结果,而不是子表达式本身

1.5.4(1) 外部引用

        通过Matcher对象的group(int)group(name)方法可以获取对应的捕获组,并返回捕获组匹配后的数据

1.5.4(2) 内部引用

        在正则表达式内部进行的引用也可以叫做"反向引用"

        数字捕获组反向引用\n

        命名捕获组反向引用\k<name>或\k'name'

"33a55".matches("(\\d)\\1[a-z]+(\\d)\\1");  //返回false
"33a53".matches("(\\d)\\1[a-z]+(\\d)\\1");  //返回true

//regex中两个\1指的都是编号为1的捕获组

        反向引用使用场景:

                例: 查找一串字母中成对出现的字母

Pattern pattern = Pattern.compile("([a-z])\\1");
Matcher matcher = pattern.matcher("aaabbcdlkkkkkjbcc");
while (matcher.find()) {
	System.out.println(matcher.group());
}

//aa
//bb
//kk
//kk
//cc

                例: 号码中是否有6位连续相同的数字

Pattern pattern = Pattern.compile("(\\d)(?=\\1{5})");
Matcher matcher = pattern.matcher("25235235234");
System.out.println(matcher.find());  //不存在

Pattern pattern = Pattern.compile("(\\d)(?=\\1{5})");
Matcher matcher = pattern.matcher("26666667891");
System.out.println(matcher.find());  //存在

1.5.4(3) 正则替换

        数字捕获组用$n指代,命名捕获组用${name}指代

"123abc456def789".replaceAll("(\\d+)([a-z]+)", "$1换");  //123换456换789

"123abc456def789".replaceAll("(?<one>\\d+)(?<two>[a-z]+)", "${two}换");  //abc换def换789

1.6 修饰符

        JS环境的修饰符不写在正则表达式里,而写在表达式之外,指定额外的匹配策略

1.6.1 字母大小写

        JAVA环境: (?i)的表达式字母不区分大小写,(?i)不算捕获组

        JS环境: 表达式外添加i

"ABC".matches("(?i)abc");  //返回true
"aBC".matches("a(?i)bc");  //返回true
"abc".matches("a((?i)b)c");  //返回true

1.6.2 全局匹配

        JS环境: 表达式外添加g修饰符可以查找字符串中所有的匹配项,不加g则只查找第一次匹配项

'a1bk3u4f'.match(/\d/);  //返回["1"]
'a1bk3u4f'.match(/\d/g);  //返回["1","3","4"]

1.6.3 多行匹配

        JS环境: 表达式外添加m修饰符可以匹配多行

1.7 其它符号

1.7.1 分隔符

        符合|前的表达式符合|后的表达式,通常将|前后的表达式约束在( )中

"D123".matches("[A-Z]\\d{3}|\\d{4}");  //"D123"或"1234"符合
"D1234".matches("[A-Z](\\d{3}|\\d{4})");  //"D123"或"D1234"符合

1.7.2 分组

        写在( )中的表达式称为子表达式,子表达式是一个整体(即一个分组),其后的量词是对这个整体起作用

"regexx".matches("regex{2}");  //结果为true
"regexregex".matches("(regex){2}");  //结果为true

1.7.3 定位符

        ^表示开头和$表示结尾,通常将^和$配合使用

                例: "<h1>一号字体</h1>"用"<.*?>"匹配到2处"<h1>一号字体</h1>"

                      "<h1>一号字体</h1>"用"^<.*?>$"匹配到1处"<h1>一号字体</h1>"

        \b表示单词边界,\B表示非单词边界

                例: "this is a island"用"is"匹配到3处"this is a island"

                      "this is a island"用"\bis"匹配到2处"this is a island"

                      "this is a island"用"is\b"匹配到2处"this is a island"

                      "this is a island"用"\bis\b"匹配到1处"this is a island"

1.7.4 特殊字符

        如果想匹配特殊字符($  (  )  *  +  .  [  ?  \  ^  {  |),需要在特殊字符前加上转义符\

                例: 想匹配?,因为?是特殊字符,因此要写成\?,而\在字符串中也代表转义符,因此写法应该是\\?

"?".matches("\?");  //写法错误
"?".matches("\\?");  //结果为true

                例: 同理,想匹配\,应该写成\\,如果正则参数写在字符串中,则应该写成\\\\

"\\".matches("\\");  //写法错误
"\\".matches("\\\\");  //结果为true

2 使用环境

2.1 JAVA环境

        str.matches(regex)   str完全匹配regex   本质是Pattern.matches(regex,str)

        str.replaceFirst(regex,str2)   将str中第一次满足regex的内容替换为str2   本质是Matcher.replaceFirst(replacement)

        str.replaceAll(regex)   将str中所有满足regex的内容替换为str2   本质是Matcher.replaceAll(replacement)

        str.split(regex)   以regex为分隔,返回String[ ]   //①如果原字符串为”空字符串”,返回的数组长度为1,数组第一个元素为”空字符串” ②如果字符串第一个字符满足regex分隔,那么返回的数组第一个元素是”空字符串”   本质是Pattern.compile(regex).split(str)

"23456f".matches("\\d+");  //返回false
"12ab33db56cf".replaceFirst("\\d+", "换");  //返回"换ab33db56cf"
"12ab33db56cf".replaceAll("\\d+", "换");  //返回"换ab换db换cf"
Arrays.toString("12ab33db56cf333".split("\\d+"));  //返回[, ab, db, cf]

2.2 JavaScript环境

        创建正则表达式对象RegExp: 将正则写在/regex/中,修饰符写在/regex/外

var reg = /regex/gim;

        reg.test(str)   字符串中是否有符合正则的内容(有一个即可,无需完全匹配),返回boolean

                // 如果想"完全匹配",可以加上定位符^和$,例/^\d{3}$/

var reg = /\d/;
reg.test('阿发123');  //返回true

        str.search(reg)   搜索字符串中第一次符合reg的位置(从0开始),没有返回-1

'abecbbf'.search(/BB/i);  //返回4

        str.match(reg)   搜索字符串中符合reg的内容,并以数组的形式返回,没有就返回null

'a1bk3u4f'.match(/\d/);  //返回["1"]
'a1bk3u4f'.match(/\d/g);  //返回["1","3","4"]

        str.replace(reg,str2)   查找str中符合reg的内容,并用str2替换

'我是湖北的,湖北汉族人'.replace(/湖北/,'中国');  //返回"我是中国的,湖北汉族人"
'我是湖北的,湖北汉族人'.replace(/湖北/g,'中国');  //返回"我是中国的,中国汉族人"

        str.split(reg)   以str中符合reg的内容为分割,返回数组

'1ab23df65sf23'.split(/\d+/);  //返回[ "", "ab", "df", "sf", "" ]

        str.trim()   去掉str首尾空格

3  用法示例

账户金额    ^\d{1,3}(,\d{3})*.\d{2}$    例:5,231,247.08

电话号码    ^(13[0-9]|14[01456789]|15[012356789]|16[0256789]|17[0-9]|18[0-9]|19[012356789])\d{8}$    例:15176767856

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值