不同开发语言、不对软件在引入正则表达式时都会根据需要进行重新定义或者做一些扩展,这在一定程度上增加了可用性,但不同形式的书写方式、表达方式、定义方式,也给正则表达式的使用人员,尤其是初学者带来了实质性困难。本文从正则表达式的通用基本语法出发,抛开各种特定的开发环境或者软件使用环境,力图让初学者能够真正理解和掌握正则表达式,从而一法通万法,达到在任意场合下都能够随心使用的目的。
一、基本语法:
1、/表达式/ "/.../"是正则表达式定界符,表示从"/"开始到另一个"/"结束,其范围内的表达式为正则表达式。 //JavaScript 定义正则表达式变量时遵循严格的正则表达式定界符,如匹配年、月、日的表达式变量 var regex=/\d{4}-\d{2}-\d{2}/;Java、C++、VBS 中则直接使用英文双引号,如 regex="\d{4}-\d{2}-\d{2}"。
2、^ 正则表达式起始符,匹配行的开头。
3、$ 正则表达式结束符,匹配行的结尾。
**^$**结合使用示例:^test$ //表示以 test 开头,并以 test 结尾的字符串,即独占一行的 test 字符串
不使用 **^$**示例:test //表示含有 test 的任意字符串
4、. 匹配任意单个字符。
5、\d 匹配任意一个数字。
6、\D 匹配(任意一个)非数字(字符)。
7、\s 匹配空白字符,包括空格、制表符、换页符等,等价于 [ \f\n\r\t\v]。
8、\S 匹配任意非空白字符,等价于 [^ \f\n\r\t\v]。
9、\w 匹配所有的单词字符(包括字母 [A-Za-z],数字 [0-9],下划线 ),等价于 [A-Za-z0-9]。
10、\W 匹配所有非单词字符,等价于 [^A-Za-z0-9_]。
其他特殊的匹配字符还有:
\f 匹配一个换页符,等价于 \x0c 和 \cL。
\n 匹配一个换行符,等价于 \x0a 和 \cJ。
\r 匹配一个回车符,等价于 \x0d 和 \cM。
\t 匹配一个制表符,等价于 \x09 和 \cI。
\v 匹配一个垂直制表符,等价于 \x0b 和 \cK。
\b 匹配一个单词边界,即指单词和空格间的位置。例如, 'er\b' 可以匹配 "never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非单词边界。如 'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\0mnn 八进制数 0mnn 所表示的字符。
\xhh 十六进制值 0xhh 所表示的字符。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?) ,[\u4e00-\u9fa5] 匹配所有中文字符。
11、* 匹配前面的子表达式/元素任意次(零次或多次 ≥0)。如,it* 能匹配 "i"、"it" 以及 "itt"。 * 等价于{0,}。
12、+ 匹配前面的子表达式/元素出现 1 次或多次(≥1)。如,it+ 能匹配 "it" 以及 "itt"。 + 等价于{1,}。
13、? 匹配前面的子表达式/元素出现 0 次或 1 次。如,i(t)? 能匹配 "i" 以及 "it"。 ? 等价于{0,1}。
14、{} 用于标记前面子表达式/元素的出现频度。
{n} 匹配前面的子表达式/元素重复 n 次。其中 n 为非负整数。
{n,} 匹配前面的子表达式/元素重复至少 n 次。n 同上。
{n,m} 匹配前面的子表达式/元素重复至少 n 次,至多 m 次。其中 n、m 为非负整数,且 n<m。
15、[] 匹配中括号表达式中的任意一个字符。如 "[Abc]" 能匹配 "A"、"b" 以及 "c" 字符。
16、() 称为分组或模式,小括号表达式中的所有字符及顺序必须完全匹配。如 "(Abc)" 则表示匹配含有 "Abc" 的任意字符串。
一个正则表达式中可以同时出现多个 "(pattern)" 分组,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0...$9 获取分组对象。
17、| 逻辑或,在含有复杂匹配条件的正则表达式中经常出现。
18、\ 转义字符,在正则表达式中 "."、"*"、"?"、"^"、"$"、"+"、"{}"、"[]"、"()"、"\d"、"\D"、"\w"、"\W"、"\"、"|"等字符已经有特殊的含义,当需要将上述字符当作普通字符作为子表达式的一部分时,需要使用 "\" 进行转义。如 "\*" 表示普通字符 "*" 号。
二、较复杂条件下的正则表达式编写示例:
普通的字符类匹配,本文就不再一一举例了,可以通过下载本站分享的一款正则表达式小工具进行练习:./正则助手.7z。
本次以编写匹配 IPv4 点分十进制地址的正则表达式为例,详细拆解较复杂条件下该如何逐步编写正则表达式,最后再进行拼接组装解决实际问题的。
步骤 1:分析 IPv4 地址特征:
(1)地址范围为 0.0.0.0-255.255.255.255;
(2)4 段数字,每段数值范围均为 0-255。
步骤 2:数值拆解:
(1)0-255 可拆分为 3 段,0-99,100-199,200-255
步骤 3:从最特殊最复杂段开始编写正则表达式 //参照路由最长匹配原则
(1)上述 3 段数值,很显然 200-255 是最为特殊的一段
(2)匹配 200-255 的子表达式可写成:(2[0-5]{2})
步骤 4:逐步编写次特殊次复杂段子表达式,直至匹配所有分段数值的子表达式都编写完成:
(1)匹配 100-199 的子表达式可写出:(1[0-9]{2})
(2)匹配 0-99 的子表达式可写为:([0-9]{1,2})
步骤 5:初步拼接组装子表达式: //按子表达式编写先后顺序,最早编写的放置在最左侧,优先进行匹配;子表达式间用 "|" 逻辑或符号进行连接。
(1)拼接匹配 0-255 数值的正则表达式:(((2[0-5]{2})|(1[0-9]{2}))|([0-9]{1,2}))
步骤 6:根据 IPv4 点分十进制数规律,完成最终正则表达式编写:
(1)3 个 .0-255 可以表示为:(\.(((2[0-5]{2})|(1[0-9]{2}))|([0-9]{1,2}))){3} // "\."表示把"."转义成普通字符".",{3} 重复 3 次,对应 IPv4 地址后 3 段。
(2)IPv4 地址正则表达式完成体:(((2[0-5]{2})|(1[0-9]{2}))|([0-9]{1,2}))(\.(((2[0-5]{2})|(1[0-9]{2}))|([0-9]{1,2}))){3}
步骤 7:验证
写了几个 IPv4 地址段进行测试,完全匹配上了,数值超过 255 的则忽略。
P1.匹配 IPv4 地址正则表达式实例测试
贴一下,网络搜索到的关于匹配 IPv4 地址的正则表达式:
((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}
对比一下,网络搜到的现成品还是很精简的,但是理解起来非常抽象,脑细胞估计得死一地......我还是宁愿用我的那一长串的正则表达式,毕竟它有规律可循,套公式般的,完全可以复制到其他任何复杂场景下去解决问题。
好了,关于通用正则表达式基本语法和怎么处理一些较复杂条件的匹配使用示例就到此结束了,如果您也感兴趣,或者有好的学习方法、办法,欢迎留言讨论呀~