概述
正则和断言
前言:正则是断言的一种,所谓断言就是判断对错的东西
文章目录
- 正则和断言
- 1.常用正则表达式
- 1.1校验数字的表达式
- 1.2校验字符的表达式
- 1.3特殊需求表达式
- 2.正则基本语法
- 2.1常见符号介绍
- 3.正则高级语法,断言的写法
- 3.1分组的引入
- 3.2捕获组
- 3.3非捕获组
- **1、非捕获组(?:Pattern)**
- **2、零宽度断言**
- **3、模式修正符**
- **4、(?>Pattern)等同于侵占模式**
- 4.Group 分组
- **1、数组下标访问**
- **2、命名访问**
1.常用正则表达式
1.1校验数字的表达式
数字:^[0-9]*$
n位的数字:^d{n}$
至少n位的数字:^d{n,}$
m-n位的数字:^d{m,n}$
零和非零开头的数字:^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
带1-2位小数的正数或负数:^(-)?d+(.d{1,2})?$
正数、负数、和小数:^(-|+)?d+(.d+)?$
有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
非零的正整数:^[1-9]d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^+?[1-9][0-9]*$
非零的负整数:^-[1-9][]0-9"*$ 或 ^-[1-9]d*$
非负整数:^d+$ 或 ^[1-9]d*|0$
非正整数:^-[1-9]d*|0$ 或 ^((-d+)|(0+))$
非负浮点数:^d+(.d+)?$ 或 ^[1-9]d*.d*|0.d*[1-9]d*|0?.0+|0$
非正浮点数:^((-d+(.d+)?)|(0+(.0+)?))$ 或 ^(-([1-9]d*.d*|0.d*[1-9]d*))|0?.0+|0$
正浮点数:^[1-9]d*.d*|0.d*[1-9]d*$ 或 ^(([0-9]+.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数:^-([1-9]d*.d*|0.d*[1-9]d*)$ 或 ^(-(([0-9]+.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数:^(-?d+)(.d+)?$ 或 ^-?([1-9]d*.d*|0.d*[1-9]d*|0?.0+|0)$
1.2校验字符的表达式
汉字:^[u4e00-u9fa5]{0,}$
英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
长度为3-20的所有字符:^.{3,20}$
由26个英文字母组成的字符串:^[A-Za-z]+$
由26个大写英文字母组成的字符串:^[A-Z]+$
由26个小写英文字母组成的字符串:^[a-z]+$
由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
由数字、26个英文字母或者下划线组成的字符串:^w+$ 或 ^w{3,20}$
中文、英文、数字包括下划线:^[u4E00-u9FA5A-Za-z0-9_]+$
中文、英文、数字但不包括下划线等符号:^[u4E00-u9FA5A-Za-z0-9]+$ 或 ^[u4E00-u9FA5A-Za-z0-9]{2,20}$
可以输入含有^%&',;=?$"等字符:[^%&',;=?$x22]+
禁止输入含有~的字符:[^~x22]+
1.3特殊需求表达式
Email地址:^w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$
域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
InternetURL:[a-zA-z]+://[^s]* 或 ^http://([w-]+.)+[w-]+(/[w-./?%&=]*)?$
手机号码:^(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])d{8}$ (由于工信部放号段不定时,所以建议使用泛解析 ^([1][3,4,5,6,7,8,9])d{9}$)
电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^((d{3,4}-)|d{3.4}-)?d{7,8}$
国内电话号码(0511-4405222、021-87888822):d{3}-d{8}|d{4}-d{7}
18位身份证号码(数字、字母x结尾):^((d{18})|([0-9x]{18})|([0-9X]{18}))$
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]w{5,17}$
强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
日期格式:^d{4}-d{1,2}-d{1,2}
一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
钱的输入格式:
1. 有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$
2. 这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
3. 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
4. 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
5. 必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$
6. 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
7. 这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
8. 1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\.[x|X][m|M][l|L]$
中文字符的正则表达式:[u4e00-u9fa5]
双字节字符:[^x00-xff]
(包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
空白行的正则表达式:ns*r
(可以用来删除空白行)
HTML标记的正则表达式:<(S*?)[^>]*>.*?</1>|<.*? />
(网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
首尾空白字符的正则表达式:^s*|s*$或(^s*)|(s*$)
(可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
腾讯QQ号:[1-9][0-9]{4,}
(腾讯QQ号从10000开始)
中国邮政编码:[1-9]d{5}(?!d)
(中国邮政编码为6位数字)
IP地址:d+.d+.d+.d+
(提取IP地址时有用)
IP地址:((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))
(由@飞龙三少 提供,感谢共享)
2.正则基本语法
2.1常见符号介绍
预定义字符类
符号 | 说明 |
---|---|
. | 任何字符(与行结束符可能匹配也可能不匹配) |
d | 数字:[0-9] |
D | 非数字: [^0-9] |
s | 空白字符:[ tnx0Bfr] |
S | 非空白字符:[^s] |
w | 单词字符:[a-zA-Z_0-9] |
W | 非单词字符:[^w] |
| 转义字符,比如"“匹配”" ,“{“匹配”{”。 |
数量词
符号 | 说明 |
---|---|
* | 等价于{0,} 匹配0至多个在它之前的字符。例如正则表达式“zo*”能匹配“z”以及“zoo”;正则表达式“.*”意味着能够匹配任意字符串。 |
+ | 等价于{1,} 匹配前面的子表达式一次或多次。例如正则表达式9+匹配9、99、999等。 |
? | 等价于{0,1} 匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 或 “does” 中的"do" 。此元字符还有另外一个用途,就是表示非贪婪模式匹配,后边将有介绍 |
{n} | 匹配确定的 n 次。例如,“e{2}”不能匹配“bed”中的“d”,但是能匹配“seed”中的两个“e”。 |
{n,} | 至少匹配n次。例如,“e{2,}”不能匹配“bed”中的“e”,但能匹配“seeeeeeeed”中的所有“e”。 |
{n,m} | 最少匹配 n 次且最多匹配 m 次。“e{1,3}”将匹配“seeeeeeeed”中的前三个“e”。 |
边界匹配符号
符号 | 说明 |
---|---|
^ | 行的开头 |
$ | 行的结尾 |
b | 单词边界 |
B | 非单词边界 |
A | 输入的开头 |
G | 上一个匹配的结尾 |
Z | 输入的结尾,仅用于最后的结束符(如果有的话) |
z | 输入的结尾 |
其他常见符号
[]的使用--或 | 说明 |
---|---|
[] | 匹配括号中的任何一个字符 |
[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 (交集) |
[a-z&&[^bc]] | a 到 z ,除了 b 和 c :[ad-z] (减去) |
[a-z&&[^m-p]] | a 到 z ,而非 m 到 p :[a-lq-z] (减去) |
**()的使用 -- 组** | |
() | 将 () 之间括起来的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域,这个元字符在字符串提取的时候非常有用。捕获组可以通过从左到右计算其开括号来编号。 |
(d) | 第一组 |
((A)(B(C))) | 第一组 ((A)(B©)) 第二组 (A) 第三组(B©) 第四组© |
3.正则高级语法,断言的写法
3.1分组的引入
对于要重复单个字符,非常简单,直接在字符后卖弄加上限定符即可,例如 a+ 表示匹配1个或一个以上的a,a?表示匹配0个或1个a。这些限定符如下所示:
X ? | X ,一次或一次也没有 |
---|---|
X * | X ,零次或多次 |
X + | X ,一次或多次 |
X { n } | X ,恰好 n 次 |
X { n ,} | X ,至少 n 次 |
X { n , m } | X ,至少 n 次,但是不超过 m 次 |
但是我们如果要对多个字符进行重复怎么办呢?此时我们就要用到分组,我们可以使用小括号"()"来指定要重复的子表达式,然后对这个子表达式进行重复,例如:(abc)? 表示0个或1个abc 这里一 个括号的表达式就表示一个分组 。
分组可以分为两种形式,捕获组和非捕获组。
3.2捕获组
捕获组可以通过从左到右计算其开括号来编号 。例如,在表达式 (A)(B©) 中,存在四个这样的组:
0 | (A)(B©) |
---|---|
1 | (A) |
2 | (B©) |
3 | © |
组零始终代表整个表达式
之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用(反向引用) 在表达式中使用,也可以在匹配操作完成后从匹配器检索。
Back 引用 是说在后面的表达式中我们可以使用组的编号来引用前面的表达式所捕获到的文本序列。注意:反向引用,引用的是前面捕获组中的文本而不是正则,也就是说反向引用处匹配的文本应和前面捕获组中的文本相同,这一点很重要。
【例】(["']).*1
其中使用了分组,1就是对引号这个分组的引用,它匹配包含在两个引号或者两个单引号中的所有字符串,如,“abc” 或 " ’ " 或 ’ " ’ ,但是请注意,它并不会对" a’或者 'a"匹配。原因上面已经说明,Back引用只是引用文本而不是表达式。
分组举列
先来看第一个作用,对于IP地址的匹配,简单的可以写为如下形式:
d{1,3}.d{1,3}.d{1,3}.d{1,3}
但仔细观察,我们可以发现一定的规律,可以把.d{1,3}看成一个整体,也就是把他们看成一组,再把这个组重复3次即可。表达式如下:
d{1,3}(.d{1,3}){3}
再来看第二个作用,就拿匹配
<title>.*</title>
可以看出,上边表达式中有两个title,完全一样,其实可以通过分组简写。表达式如下:
<(title)>.*</1>
对于分组而言,整个表达式永远算作第0组,在本例中,第0组是<(title)>.*</1>,然后从左到右,依次为分组编号,因此,(title)是第1组。
注意:
用1这种语法,可以引用某组的文本内容,但不能引用正则表达式。
例如刚刚的IP地址正则表达式为d{1,3}(.d{1,3}){3},里边的d{1,3}重复了两次,如果利用后向引用简化,表达式如下:
(d{1,3})(.1){3}
经过实际测试,会发现这样写是错误的,为什么呢?
后向引用,引用的仅仅是文本内容,而不是正则表达式!
也就是说,组中的内容一旦匹配成功,后向引用,引用的就是匹配成功后的内容,引用的是结果,而不是表达式。
因此,(d{1,3})(.1){3}这个表达式实际上匹配的是四个数都相同的IP地址,比如:123.123.123.123。
3.3非捕获组
以 (?) 开头的组是纯的非捕获 组,它不捕获文本 ,也不针对组合计进行计数。就是说,如果小括号中以?号开头,那么这个分组就不会捕获文本,当然也不会有组的编号,因此也不存在Back 引用。
我们通过捕获组就能够得到我们想要匹配的内容了,那为什么还要有非捕获组呢?原因是捕获组捕获的内容是被存储在内存中,可供以后使用,比如反向引用就是引用的内存中存储的捕获组中捕获的内容。而非捕获组则不会捕获文本,也不会将它匹配到的内容单独分组来放到内存中。所以,使用非捕获组较使用捕获组更节省内存。在实际情况中我们要酌情选用。
1、非捕获组(?:Pattern)
它的作用就是匹配Pattern字符,好处就是不捕获文本,不将匹配到的字符存储到内存中,从而节省内存。
【例】匹配indestry或者indestries
我们可以使用indestr(y|ies)或者indestr(?:y|ies)
【例】(?:a|A)123(?:b)可以匹配a123b或者A123b
非捕获组有很多种形式,其中包括:零宽度断言和模式修正符
2、零宽度断言
(?= X ) | X ,通过零宽度的正 lookahead | 字符串:product_path 正则:(product)(?=_path) 结果:product |
---|---|---|
(?! X ) | X ,通过零宽度的负 lookahead | 字符串:product_path 正则:(product)(?!_url) 结果:product字符串:product_path 正则:(product)(?!_path) 结果:空 |
(?<= X ) | X ,通过零宽度的正 lookbehind | 字符串:name:wangfei 正则:(?<=name:)(wangfei) 结果:wangfei |
(?<! X ) | X ,通过零宽度的负 lookbehind | 字符串:name:angelica 正则:(?<!nick_name:)(angelica) 结果:angelica字符串:name:angelica 正则:(?<!name:)(angelica) 结果:空 |
这四个非捕获组用于匹配表达式X,但是不包含表达式的文本。
(?=X ) | 零宽度正先行断言。仅当子表达式 X 在此位置的右侧匹配时才继续匹配。也就是说要使此零宽度断言起到我们想要的效果的话,就必须把这个非捕获组放在整个表达式的右侧。例如,/w+(?=/d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。 |
---|---|
(?!X) | 零宽度负先行断言。仅当子表达式 X 不在此位置的右侧匹配时才继续匹配。例如,例如,/w+(?!/d) 与后不跟数字的单词匹配,而不与该数字匹配 。 |
(?<=X) | 零宽度正后发断言。仅当子表达式 X 在此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。 |
(?<!X) | 零宽度负后发断言。仅当子表达式 X 不在此位置的左侧匹配时才继续匹配。例如,(?<!19)99 与不跟在 19 后面的 99 的实例匹配 |
上面都是理论性的介绍,这里就使用一些例子来说明一下问题:
【例1】正则表达式 (?<!4)56(?=9)
含义:查找56,要求前面不能是4,后面必须是9。因此,可以匹配如下文本 5569 ,与4569不匹配。
【例2】提取字符串 da12bka3434bdca4343bdca234bm中包含在字符a和b之间的数字,但是这个a之前的字符不能是c;b后面的字符必须是d才能提取。
显然,这里就只有3434这个数字满足要求。那么我们怎么提取呢?
首先,我们写出含有捕获组的正则表达式:[^c]adbd 然后我们再将其变为非捕获组的正则表达式:(?<=[^c]a)d(?=bd)
3、模式修正符
以(?)开头的非捕获组除了零宽度断言之外,还有模式修正符。
正则表达式中常用的模式修正符有i、g、m、s、x、e等。它们之间可以组合搭配使用。
(?imnsx-imnsx: ) 应用或禁用子表达式中指定的选项。例如,(?i-s: ) 将打开不区分大小写并禁用单行模式。关闭不区分大小写的开关可以使用(?-i)。有关更多信息,请参阅正则表达式选项。
【例1】(?i)ab
表示对(?i)后的所有字符都开启不区分大小写的开关。故它可以匹配ab、aB、Ab、AB
【例2】(?i:a)b
它表示只对a开启不区分大小写的开关。故它可以匹配ab和Ab。不能匹配aB和AB。
4、(?>Pattern)等同于侵占模式
匹配成功不进行回溯,这个比较复杂,与侵占量词“+”可以通用,比如:d++ 可以写为 (?>d+)。
【例】将一些多位的小数截短到三位小数:d+.dd[1-9]?d+
在这种条件下 6.625 能进行匹配,这样做没有必要,因为它本身就是三位小数。最后一个“5”本来是给 [1-9] 匹配的,但是后面还有一个 d+ 所以,[1-9] 由于是“?”可以不匹配所以只能放弃当前的匹配,将这个“5”送给 d+ 去匹配,如果改为:
d+.dd[1-9]?+d+
的侵占形式,在“5”匹配到 [1-9] 时,由于是侵占式的,所以不会进行回溯,后面的 d+ 就匹配不到任东西了,所以导致 6.625 匹配失败。
这种情况,在替换时就有效了,比如把数字截短到小数点后三位,如果正好是三位小数的,就可以不用替换了,可以提高效率,侵占量词基本上就是用来提高匹配效率的。
把 d+.dd[1-9]?+d+ 改为 d+.dd(?>[1-9]?)d+ 这样是一样的。
【补充】js获取分组内容的方法:(可参考JS正则实例)
1、 arr[n] = str.match(reg); 或者 arr[n] = reg.exec(str);
返回的匹配数组arr[n]中,arr[0]表示整个匹配,arr[1],arr[2]…分别表示各个分组的匹配结果
2、通过RegExp对象的静态属性来获取
RegExp.1,RegExp.1,RegExp.2…RegExp.$9 分别表示匹配到的第一个分组至第九个分组的内容
例:
var str = "adfasd324232sdfas";
alert(str);
var reg = new RegExp("([a-z]*)(\d*)([a-z]*)");
var arr = str.match(reg);
alert(arr[0] + "===" + arr[1] + "===" + arr[2] + "===" + arr[3]);
alert(RegExp.$1 + "-----" + RegExp.$2 + "----" + RegExp.$3);
4.Group 分组
在一个正则表达式中,如果要提取出多个不同的部分(子表达式项),需要用到分组功能。
在 C# 正则表达式中,Regex 成员关系如下,其中 Group 是其分组处理类。
Regex –> MatcheCollection (匹配项集合)
–> Match (单匹配项 内容)
–> GroupCollection (单匹配项中包含的 “(分组/子表达式项)” 集合)
–> Group ( “(分组/子表达式项)” 内容)
–> CaputerCollection (分组项内容显示基础?)
–> Caputer
Group 对分组有两种访问方式:
1、数组下标访问
在 ((d+)([a-z]))s+ 这个正则表达式里总共包含了四个分组,按照默认的从左到右的匹配方式,
Groups[0] 代表了匹配项本身,也就是整个整个表达式 ((d+)([a-z]))s+
Groups[1] 代表了子表达式项 ((d+)([a-z]))
Groups[2] 代表了子表达式项 (d+)
Groups[3] 代表了子表达式项 ([a-z])
string text = "1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11Q 12J 13K 14L 15M 16N ffee80 #800080";
Response.Write(text + "<br/>");
string strPatten = @"((d+)([a-z]))s+";
Regex rex = new Regex(strPatten, RegexOptions.IgnoreCase);
MatchCollection matches = rex.Matches(text);
//提取匹配项
foreach (Match match in matches)
{
GroupCollection groups = match.Groups;
Response.Write(string.Format("<br/>{0} 共有 {1} 个分组:{2}<br/>"
, match.Value, groups.Count, strPatten));
//提取匹配项内的分组信息
for (int i = 0; i < groups.Count; i++)
{
Response.Write(
string.Format("分组 {0} 为 {1},位置为 {2},长度为 {3}<br/>"
, i
, groups[i].Value
, groups[i].Index
, groups[i].Length));
}
}
/*
* 输出:
1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11Q 12J 13K 14L 15M 16N ffee80 #800080
1A 共有 4 个分组:((d+)([a-z]))s+
分组 0 为 1A ,位置为 0,长度为 3
分组 1 为 1A,位置为 0,长度为 2
分组 2 为 1,位置为 0,长度为 1
分组 3 为 A,位置为 1,长度为 1
....
*/
2、命名访问
利用 (?子表达式) 定义分组别名,这样就可以利用 Groups[“xxx”] 进行访问分组/子表达式内容。
string text = "I've found this amazing URL at http://www.sohu.com, and then find ftp://ftp.sohu.comisbetter.";
Response.Write(text + "<br/>");
string pattern = @"b(?<protocol>S+)://(?<address>S+)b";
Response.Write(pattern.Replace("<", "<").Replace(">", ">") + "<br/><br/>");
MatchCollection matches = Regex.Matches(text, pattern);
foreach (Match match in matches)
{
GroupCollection groups = match.Groups;
Response.Write(string.Format(
"URL: {0}; Protocol: {1}; Address: {2} <br/>"
, match.Value
, groups["protocol"].Value
, groups["address"].Value));
}
/*
* 输出
I've found this amazing URL at http://www.sohu.com, and then find ftp://ftp.sohu.comisbetter.
b(?<protocol>S+)://(?<address>S+)b
URL: http://www.sohu.com; Protocol: http; Address: www.sohu.com
URL: ftp://ftp.sohu.comisbetter; Protocol: ftp; Address: ftp.sohu.comisbetter
*/
参考文献:
https://blog.csdn.net/ZYS10000/article/details/120929810
https://www.cnblogs.com/Mustr/p/6060242.html
https://www.cnblogs.com/zhaoshujie/p/10103315.html
https://www.cnblogs.com/zhaoshujie/p/9594690.html
最后
以上就是愉快手机为你收集整理的正则和断言正则和断言的全部内容,希望文章能够帮你解决正则和断言正则和断言所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复