正则
一、 正则表达式及其作用
在编写处理字符串的程序或者网页时,经常会有查找符合某些复杂规则的字符串的需要,正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
用户很可能使用过Windows中用于文件查找的通配符,也就是*和?。如果想要查找某个目录下的所有的Word文档的话,用户可以搜索*.doc。在这里,*被解释成任意的字符串。和通配符类似,正则表达式也是用来进行文本匹配的工具,只不过比起通配符,它能更精确地描述用户的需求,当然,代价就是更复杂,例如,用户可以编写一个正则表达式用来查找所有一0开头,后面跟着2-3位数字,然后是一个连字符“-”,最后是7位或者8位数字的字符串(如0010-12345678或者0376-7654321)。
总体来说,正则表达式有以下三种作用:
(1)测试字符串的某个模式。例如,可以输入一个字符串进行测试看该字符串中是否存在一个电话号码模式或者一个信用卡模式,这成为数据的有效性检验。
(2)替换文本。可以再文档中使用一个正则表达式来表示特定文字,然后可以将其全部删除或者替换成别的文字。
(3)根据模式匹配从字符串中提取一个子字符串。可以用来在文本或者输入字段中查找特定的文字。
二、 c#测试工具——RegexMatchTracer
三、 正则表达式语法
1. 字符匹配
字符 |
描述 |
模式 |
匹配 |
\d |
匹配数字(0~9) |
\d |
匹配8,不匹配12 |
\D |
匹配非数字 |
\D |
匹配c,不匹配3 |
\s |
匹配空白字符 |
\d\s\d |
匹配3 d,不匹配abc |
\S |
匹配非空字符 |
\S\S\S |
匹配A#4,不匹配3 d |
. |
匹配任意字符 |
.... |
匹配A$ 5,不匹配换行 |
[…] |
匹配括号中任意字符 |
[b-d] |
匹配b、c、d, 不匹配e |
[^…] |
匹配非括号字符 |
[^b-z] |
匹配a,不匹配b-z的字符 |
\w |
与任何单词字符匹配。 |
\w |
"Room#1" 中的 "R"、 "o"、 "m" 和 "1" |
\W |
与任何非单词字符匹配。 |
\W |
"Room#1" 中的 "#" |
2. 字符定位
断言 |
描述 |
模式 |
匹配 |
^ |
匹配必须从字符串或一行的开头开始。 |
^\d{3} |
"567-777-" 中的 "567" |
$ |
匹配必须出现在字符串的末尾或出现在行或字符串末尾的 \n 之前。 |
-\d{4}$ |
"8-12-2012" 中的 "-2012" |
\A |
匹配必须出现在字符串的开头。 |
\A\w{4} |
"Code-007-" 中的 "Code" |
\Z |
匹配必须出现在字符串的末尾或出现在字符串末尾的\n 之前。 |
-\d{3}\Z |
"Bond-901-007" 中的 "-007" |
\z |
匹配必须出现在字符串的末尾。 |
-\d{3}\z |
"-901-333" 中的 "-333" |
\G |
匹配必须出现在上一个匹配结束的地方。 |
\\G\(\d\) |
"(1)(3)(5)[7](9)" 中的 "(1)"、 "(3)" 和 "(5)" |
\b |
匹配必须出现在 \w(字母数字)和 \W(非字母数字)字符之间的边界上(“\b”匹配单词边界,不匹配任何字符。 |
\w |
"Room#1" 中的 "R"、 "o"、 "m" 和 "1" |
\B |
匹配不得出现在 \b 边界上。 |
\Bend\w*\b |
"end sends endure lender" 中的 "ends" 和 "ender" |
3. 分组构造
分组构造 |
描述 |
模式 |
匹配 |
(?= exp) |
零宽度(它只是字符串中的一个位置,而不是实际的字符,如字符串“ab”,在“a”前面,“a”和“b”中间,还有“b”后面,分别有一个“零宽度”,也就是整个字符串有三个零宽度”),“零宽度”后面必须能够匹配exp的内容 。 |
\w+(?=\.) |
"He is. The dog ran. The sun is out." 中的 "is"、 "ran" 和 "out" |
(?! exp) |
零宽度后面必须不能够匹配exp的内容。 |
\b(?!un)\w+\b |
"unsure sure unity used" 中的 "sure" 和 "used" |
(?< =exp) |
零宽度前面必须能够匹配exp的内容。 |
(?<=19)\d{2}\b |
"1851 1999 1950 1905 2003" 中的 "99"、"50"和 "05" |
(?> exp) |
零宽度前面必须不能够匹配exp的内容 。 |
[13579](?>A+B+) |
"1ABB 3ABBC 5AB 5AC" 中的 "1ABB"、 "3ABB" 和 "5AB" |
4. 限定符
限定符 |
描述 |
模式 |
匹配 |
* |
匹配上一个元素零次或多次。 |
\d*\.\d |
".0"、 "19.9"、 "219.9" |
+ |
匹配上一个元素一次或多次。 |
"be+" |
"been" 中的 "bee", "bent" 中的 "be" |
? |
匹配上一个元素零次或一次。 |
"rai?n" |
"ran"、 "rain" |
{ n } |
匹配上一个元素恰好 n 次。 |
",\d{3}" |
"1,043.6" 中的 ",043", "9,876,543,210" 中的 ",876"、 ",543" 和 ",210" |
{ n , m } |
匹配上一个元素至少 n 次,但不多于 m 次。 |
"\d{3,5}" |
"166", "17668", "193024" 中的 "19302" |
5. 备用构造
备用构造 |
描述 |
模式 |
匹配 |
| |
匹配以竖线 (|) 字符分隔的任何一个元素。 |
th(e|is|at) |
"this is the day. " 中的 "the" 和 "this" |
6. 替换
字符 |
描述 |
模式 |
替换模式 |
输入字符串 |
结果字符串 |
$number |
替换按组 number 匹配的子字符串。 |
\b(\w+)(\s)(\w+)\b |
$3$2$1 |
"one two" |
"two one" |
${name} |
替换按命名组 name 匹配的子字符串。 |
\b(?< word1>\w+)(\s)(?< word2>\w+)\b |
${word2} ${word1} |
"one two" |
"two one" |
$$ |
替换字符"$"。 |
\b(\d+)\s?USD |
$$$1 |
"103 USD" |
"$103" |
$& |
替换整个匹配项的一个副本。 |
(\$*(\d*(\.+\d+)?){1}) |
**$& |
"$1.30" |
"**$1.30**" |
一、组的分类
正则中的组有捕获组和非捕获组,而捕获组又分为普通的捕获组和命名捕获组,分别为
捕获组:(exp)
命名捕获组:(? <name>
exp)
非捕获组:(?:exp)
二、组的作用
1、捕获组的作用
捕获组的作用是将正则表达式exp匹配到的内容保存到组里,供以后使用
比如这样一个字符串:
<a href="http://bbs.csdn.net" title="测试">
CSDN </a>
我想得到网址,而它符合的规则是在 <a...> 标签内,那就可以这样做
string test ="<a href=/"http://bbs.csdn.net/" title=/"测试/">CSDN</a>"; Match m = Regex.Match(test, @"<a/s*href=""([^""]*)""[^>]*>", RegexOptions.IgnoreCase); if (m.Success) MessageBox.Show(m.Groups[1].Value);
上面的正则表达式匹配到了
<a href="http://bbs.csdn.net" title="测试"> ,而我们想得到网址,表达式其它部分只是为了保证取到的网址是在 <a...> 标签内的,所以这里用到的捕获组,把匹配到的网址保存到捕获组里,然后用m.Groups[1].Value得到这个捕获组所匹配到的内容
m.Groups[1].Value是一种对捕获的引用方式,还有另外一种引用方式m.Result("$1"),效果是一样的
普通捕获组是用1,2,3...这样的自然数对捕获组进行引用的
而命名捕获组可以不用去数捕获组的序号,直接通过捕获组的命称对它进行引用
捕获组分组命名及序号排序
普通捕获组是按“(”从左到右出现的先后顺序以自然数1,2,3...进行命名的
命名捕获组就是以(? <name> exp)中的name进行命名的
但是要注意一点,在表达式匹配成功的前提下,$0在任何情况下都表示整个表达式所匹配到的内容,m.Groups[0].Value表示整个表达式匹配到的内容,可以简写为m.Value
四、 常用正则
匹配中文字符的正则表达式: [\u4e00-\u9fa5]
匹配双字节字符(包括汉字在内):[^\x00-\xff]
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*评注:表单验证时很实用
匹配国内电话号码:\d{3}-\d{8}|\d{4}-\d{7}
评注:匹配形式如 0511-4405222 或 021-87888822
匹配中国邮政编码:[1-9]\d{5}(?!\d)
评注:中国邮政编码为6位数字
匹配身份证:\d{15}|\d{18}
评注:中国的身份证为15位或18位
匹配ip地址:\d+\.\d+\.\d+\.\d+
匹配特定数字:
^[1-9]\d*$ //匹配正整数
^-[1-9]\d*$ //匹配负整数
^-?[1-9]\d*$ //匹配整数
^[1-9]\d*|0$ //匹配非负整数(正整数 + 0)
^-[1-9]\d*|0$ //匹配非正整数(负整数 + 0)
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ //匹配正浮点数
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ //匹配负浮点数
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ //匹配浮点数
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ //匹配非正浮点数(负浮点数 + 0)