ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 基本的元字符 | 元字符 | 说明 | | --- | --- | | `.` | 匹配任意单个字符 | | `|` | 逻辑或操作符 | | `[]` | 匹配字符集合中的一个字符 | | `[^]` | 对字符集合求非 | | `-` | 定义一个区间(例如[A-Z]) | | `\` | 对下一个字符转义 | ## 数量元字符 | 元字符 | 说明 | | --- | --- | | `*` | 匹配前一个字符(子表达式)的0次或多次重复 | | `*?` | `*`的懒惰型版本 | | `+` | 匹配前一个字符(子表达式)的1次或多次重复 | | `+?` | `+`的懒惰型版本 | | `?` | 匹配前一个字符(子表达式)的0次或1次重复 | | `{n}` | 匹配前一个字符(子表达式)的n次重复 | | `{m,n}` | 匹配前一个字符(子表达式)至少m次且至多n次重复 | | `{n,}` | 匹配前一个字符(子表达式)n次或更多次重复 | | `{n,}?` | `{n,}`的懒惰型版本 | | 贪婪型元字符 | 懒惰型元字符 | | --- | --- | | `*` | `*?` | | `+` | `+?` | | `{n,}` | `{n,}?` | 在需要防止过度匹配的场合下,使用“懒惰型”元字符来构造正则表达式。 ## 位置元字符 | 元字符 | 说明 | | --- | --- | | `^` | 匹配字符串的开头 | | `\A` | 匹配字符串的开头 | | `$` | 匹配字符串的结束 | | `\Z` | 匹配字符串的结束 | | `\<` | 匹配单词的开头 | | `\>` | 匹配单词的结束 | | `\b` | 匹配单词边界(开头和结束) | | `\B` | `\b`的反义 | ## 特殊字符元字符 | 元字符 | 说明 | | --- | --- | | `\b` | 退格字符 | | `\c` | 匹配一个控制字符 | | `\d` | 匹配一个任意数字字符 | | `\D` | `\d`的反义 | | `\f` | 换页符 | | `\n` | 换行符 | | `\r` | 回车符 | | `\s` | 匹配一个空白字符 == `[\f\n\r\t\v]` | | `\S` | `\s`的反义 == `[^\f\n\r\t\v]` | | `\t` | 制表符(Tab字符) | | `\v` | 垂直制表符 | | `\w` | 匹配一个任意字母、数字和下划线字符 == `[a-zA-z0-9_]` | | `\W` | `\w`的反义 == `[^a-zA-z0-9_]` | | `\x` | 匹配一个十六进制数字 | | `\0` | 匹配一个八进制数字 | 举例: 1. `\x0A` == `\n` `\x0A`对应于ASCII字符10(换行符) 2. `\011` == `\t` `\011`对应于ASCII字符9(制表符) ## 回溯引用和前后查找 | 元字符 | 说明 | 举例 | | --- | --- |--- | | `()` | 定义一个子表达式 | (pattern):匹配 pattern 并获取这一匹配。 | | `\1` | 匹配第一个子表达式; | | | `\2` | 匹配第二个子表达式,依次类推 | | | `?=` | 向前查找 | (?=pattern)正向肯定预查(look ahead positive assert):在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,`Windows(?=95|98|NT|2000)`能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 | | `?<=` | 向后前查找 | (?&lt;=pattern)反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,`(?&lt;=95|98|NT|2000)Windows`能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。 | | `?!` | 负向前查找 | (?!pattern)正向否定预查(negative assert):在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如`Windows(?!95|98|NT|2000)`能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 | | `?<!` | 负向后查找 | (?&lt;!pattern)反向否定预查,与正向否定预查类似,只是方向相反。例如`(?&lt;!95|98|NT|2000)Windows`能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。 | | `?()` | 条件(if then) | | | `?()|` | 条件(if then else) | | | `?:` | -- | (?:pattern):匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符`| `来组合一个模式的各个部分是很有用。例如, `industr(?:y|ies)` 就是一个比 `industry|industries`更简略的表达式。 | 所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。 ## 大小写转换 | 元字符 | 说明 | | --- | --- | | `\E` | 结束`\L`或`\U`转换 | | `\l` | 将下一个字符转为小写 | | `\L` | 把后面的字符全转换为小写,直到遇到`\E`为止 | | `\u` | 将下一个字符转为大写 | | `\U` | 把后面的字符全转换为大写,直到遇到`\E`为止 | ## 匹配模式 | 元字符 | 说明 | | --- | --- | | `?m` | 分行匹配模式 | ## POSIX字符类 | 字符类 | 说明 | | --- | --- | | `[:alnum:]` | 任何一个字母或数字(等价于`[a-zA-Z0-9]`) | | `[:alpha:]` | 任何一个字母(等价于`[a-zA-Z]`) | | `[:blank:]` | 空格或制表符(等价于`[\t ]`,字母t后是空格) | | `[:cntrl:]` | ASCII控制字符(ASCII0到31,再加上ASCII 127) | | `[:digit:]` | 任何一个数字(等价于`[0-9]`) | | `[:graph:]` | 和`[:print:]`一样,但不包括空格 | | `[:lower:]` | 任何一个小写字母(等价于`[a-z]`) | | `[:print:]` | 任何一个可打印字符 | | `[:punct:]` | 既不属于`[:alnum:]`也不属于`[:cntrl:]`的任何一个字符 | | `[:space:]` | 任何一个空白字符,包括空格(等价于`[f\n\r\t\v ]`,字母v后是空格) | | `[:upper:]` | 任何一个大写字母(等价于`[A-Z]`) | | `[:xdigit:]` | 任何一个十六进制数字(等价于`[a-fA-F0-9]`) | POSIX语法与我们此前见过的元字符不太一样。为了演示POSIX字符类的用法,我们来看一个例子:利用正则表达式从一段HTML代码里把RGB值查找出来: * **文本** <BODY BGCOLOR="#336633" TEXT="#FFFFFF" MARGINWIDTH="0" MARGINHEIGHT="0" TOPMARGIN="0" LEFTMARGIN="0"> * **正则表达式** `#[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]l[[:xdigit:]][[:xdigit:]]` * **结果** ~~~ <BODY BGCOLOR="#336633" TEXT="#FFFFFF" MARGINWIDTH="0" MARGINHEIGHT="0" TOPMARGIN="0"LEFTMARGIN="0"> ~~~ * **分析** 在前一章里使用的模式是重复写出的6个`[0-9A-Fz-f]`字符集合,把那6个`[0-9A-Fz-f]`全部替换为`[[:xdigit:]]`就得到这里的模式。 它们的 匹配结果完全一样。 >[info] 这里使用的模式以`[[`开头,以`]]`结束(两对方括号)。这是使用POSIX字符类所必须的。POSIX字符类必须括在`[:`和`:]`之间,我们使用的POSIX字符类是`[:xdigit:]`(不是`:xdigit:`)。外层的`[`和`]`字符用来定义一个字符集合,内层的`[`和`]`字符是POSIX字符类本身的组成部分。 ## 常见软件和编程语言中的正则表达式 ### grep grep是一种用来对文件或标准输入文本进行文字搜索的Unix工具。根据你具体使用的命令选项,grep支持基本、扩展和Perl正则表达式。 * `-E`:使用扩展正则表达式。 * `-G`:使用基本正则表达式。 * `-P`:使用Perl正则表达式。 注意: * 在默认的情况下,grep将把包含着匹配的各个文本行全部显示出来;如果你只想查看匹配结果,请使用`-o`选项。 * 使用`-v`选项将对整个匹配操作进行求非一只显示不匹配的文本行。 * 使用`-c`选项将只显示匹配的总数而不是此次匹配的细节。 * grep工具只能用来进行搜索操作,不能用来进行替换操作。 即是grep工具不支持替换功能。 ### JavaScript JavaScript 1.x版本在`String`和`RegExp`对象的以下几个方法里实现了正则表达式处理。 * `exec`:一个用来搜索一个匹配的RegExp方法。 * `match`:一个用来匹配一个字符串的string方法。 * `replace`:一个用来完成替换操作的string方法。 * `search`:一个用来测试在某给定字符串里是否存在着一个匹配的String方法。 * `split`:一个用来把一个字符串拆分为多个子串的String方法。 * `test`:一个用来测试在某给定字符串里是否存在着一个匹配的RegExp方法。 JavaScript 2里的正则表达式处理(Mozilla和另外几种比较新的浏览器可以支持)与JavaScript 1.x向后兼容并提供了更多的功能。 JavaScript对正则表达式的支持源自Perl语言,但需要注意以下几个问题: * JavaScript使用命令行选项来管理全局的区分大小写搜索:`g`选项激活全局搜索功能,`i`选项让匹配操作不区分字母的大小写,这两个选项可以组合为`gi`。 * 其他命令行选项(版本4及以后的浏览器支持)包括:`m`,支持多行字符串;`s`,支持单行字符串;`x`,忽略正则表达式模式里的空白字符。 * 在使用回溯引用的时候,`$'`(单引号)将返回被匹配字符串前面的所有东西,$\`\(反引号)将返回被匹配字符串后面的所有东西,`$+`将返回最后一个被匹配的子表达式,`$&`将返回被匹配到的所有东西。 * JavaScript提供了一个名为`RegExp`的全局对象,在执行完一个正则表达式之后,你们可以通过这个对象获得与这次执行有关的信息。 * JavaScript不支持POSIX字符类。 * JavaScript不支持`\A`和`\Z`. ### PHP PHP通过它的PCRE组件提供了与Perl相兼容的正则表达式支持。从PHP 4.2.0版本开始,PCRE组件将自动安装。 下面是PCRE组件提供的一些正则表达式函数: * `preg_grep()`:进行一次搜索,匹配结果将作为数组返回。 * `preg_match()`:进行一次正则表达式搜索,返回第一个匹配。 * `preg_match_all()`:进行一次正则表达式搜索,返回所有的匹配。 * `preg_quote()`:这个函数的输入参数是一个模式,返回值是该模式的转义版本。 * `preg_replace()`:进行一次“搜索并替换”操作。 * `preg_replace_callback()`:进行一次“搜索并替换”操作,但使用一个回调(callback)函数来完成实际替换动作。 * `preg_split()`:把一个字符串拆分为子字符串。 注意: * 在默认的情况下,匹配操作不区分字母的大小写。 如果不想区分字母的大小写,必须使用`i`限定符。 * 在默认的情况下,匹配操作仅限于单行字符串。 如果需要匹配多行字符串,必须使用`m`限定符。 * `preg_replace()`,`preg_replace_callback()`和`preg_split()`函数都支持一个可选的参数,该参数用来给出一个上限值一对字符串进行替换或拆分的最大次数。 * `preg_grep()`和`preg_replace_callback()`是从PHP 4才开始有的,其他函数都是从PHP3开始就被支持的。 * 在PHP4.0.4和更高版本里,回溯引用可以用Perl语言的$语法(例如`$1`)来引用;在较早的版本里必须用`\\`来代替`$`。 * 不支持`\l`,`\u`,`\L`,`\U`,`\Q`和`\v`. ### MySQL MySQL是一个流行的开放源代码数据库软件。MySQL率先提供了正则表达式支持作为一种数据库搜索手段, 这一点我们在其他数据库系统里还没有见过。 MySQL对正则表达式的支持体现在允许在WHERE子句里使用如下格式的表达式: ~~~ SELECT*FROM table WHERE REGEXP "pattern" ~~~ MySQL正则表达式支持很有用,功能也很强大,但它还算不上是一个完备的正则表达式实现。 * 只提供了搜索支持, 不支持使用正则表达式进行替换操作。 * 在默认的情况下,正则表达式搜索不区分字母的大小写。 如果需要区分字母的大小写,必须再增加一个`BINARY`关键字(放在`REGEXP`和模式之间). * 用`[[:<:]]`来匹配一个单词的开头,用`[[:>:]]`来匹配一个单词的结束。 * 不支持向前预测。 * 不支持嵌入条件。 * 不支持八进制字符搜索。 * 不支持`\a`,`\b`,`\e`,`\f`和`\v`. * 不支持回溯引用。 ### Perl Perl可以说是各种正则表达式实现的“祖宗”,其他各种实现几乎都与Perl相兼容。 正则表达式支持是Perl的核心组件之一。 如果需要在Perl脚本里使用正则表达式,只要像下面这样给出一个操作和相应的模式即可。 * `m/pattern/` 匹配给定的模式. * `s/pattern/pattern/`执行一个替换操作。 * `qr/pattern/`返回一个Regex对象供今后使用。 * `split()`把一个字符串拆分为子字符串。 下面是一些与Perl正则表达式有关的注意事项。 * 允许把限定符放在模式的后面。 `\i`用来表明在搜索时不区分字母的大小写; `\g`用来表明进行全局搜索(把所有的匹配都找出来)。 * 在使用“回溯引用”的时候,`$'`将返回被匹配字符串前面的所有东西,$`将返回被匹配字符串后面的所有东西,`$+`将返回最后一个被匹配的子表达式,`$&`将返回整个被匹配字符串。 ### Java Java对正则表达式的支持是从1.4版本开始的,此前的JRE(JavaRuntime Environment,Java运行坏境)版本不支持正则表达式。 >[danger] 版本低于1.4的JRE现在仍被广泛地使用着。 如果你打算部署一个使用了正则表达式的Java应用程序,千万不要忘记检查JRE的版本。 Java语言中的正则表达式匹配功能主要是通过`java.util.regex.Matcher`类和以下这些方法实现的。 * `find()`:在一个字符串里寻找一个给定模式的匹配。 * `lookingAt()`:用一个给定的模式去尝试匹配一个字符串的开头。 * `matches()`:用一个给定的模式去尝试匹配一个完整的字符串。 * `replaceAll()`:进行替换操作,对所有的匹配都进行替换。 * `replaceFirst()`:进行替换操作,只对第一个匹配进行替换。 Matcher类还提供了几个能够让程序员对特定操作做出更细致调控的方法。此外,`java.util.regex.Pattern`类也提供了几个简单易用的包装器方法: * `compile()`:把一个正则表达式编译成一个模式。 * `flags()`:返回某给定模式的匹配标志。 * `matches()`:在功能上等价于刚才介绍的`matches()`方法。 * `pattern()`:把一个模式还原为一个正则表达式。 * `split()`:把一个字符串拆分为子字符串。 Sun公司发布的Java正则表达式支持与Perl语言基本兼容,但要注意以下几点。 * 要想使用正则表达式,必须先用`import java.util.regex.*`语句导入正则表达式组件(这条语句将导入一个完整的软件包。 如果你只需要用到其中的一部分功能, 请用相应的软件包名字替换掉 这条语句里的*)。 * 不支持嵌入条件. * 不支持使用`\E`、`\l`,`\L`,`\u`和`\U`进行字母大小写转换。 * 不支持使用`[\b]`匹配退格符. * 不支持`\z`。 ## 应用举例 ### 北美电话号码 北美地区(美国、加拿大、加勒比海地区大部以及其他几个地区)的电话号码 1. 由一个3位数的区号和一个7位数的号码构成 2. 这7位数字又分成一个3位数的局号和一个4位数的线路号,局号和线路号之间用连字符(`-`)或小数点(`.`)分隔 3. 每位电话号码可以是任意数字,但区号和局号的第一位数字不能是0或1 4. 在书写电话号码的时候,人们往往把区号放在括号里,而且还往往会在区号与实际电话号码之间加上一个连字符(`-`)或小数点(`.`)来分隔它们。 * **文本** J.Doe: 248-555-1234 B.Smith:(313) 555-1234 A.Lee: (810)555-1234 M.Jones: 734.555.9999 * **正则表达式** `[\(.]?[2-9]\d\d[\).]?[ -]?[2-9]\d\d[-.]\d{4}` * **结果** J.Doe: `248-555-1234` B.Smith: `(313) 555-1234` A.Lee: `(810)555-1234` M.Jones: `734.555.9999` ### 中国固定电话号码 1. 区号。以数字0开头的3~5位的号码 2. 电话号码。以不为1开头的7~8位号码 * **文本** 029 88457890 029 8845 7890 (029) 8845 7890 (029) 88457890 029-88457890 029-8845 7890 029-8845-7890 * **正则表达式** `\(?0[1-9]\d{1,3}\)?[-]?[2-9]\d{2,3}[-]\d{4}` ### 美国邮政编码(ZIP) ZIP: Zone Improvement Plan ZIP编码规则 1. 5位数字的ZIP编码 2. 9位数字的ZIP+4编码(ZIP+4编码中的后4位数字与前5位数字之间要用一个连字符隔开). * **文本** 999 1st Avenue,Bigtown,NY,11222 123 High Street,Any City,MI 48034-1234 * **正则表达式** `\d{5}(-\d{4})?` * **结果** 999 1st Avenue,Bigtown,NY,`11222` 123 High Street,Any City,MI `48034-1234` ### 中国邮政编码 编码规则 1. 共6位数字 2. 前两位表示省、市、自治区。其中第二位不为8(港澳前两位为99,其余省市为0-7) 3. 第三位代表邮区,第四位代表县、市,最后两位代表投递邮局。 * **正则表达式** `\d(9|[0-7])\d{4}` ### 加拿大邮政编码 编码规则: 1. 由6个交替出现的字母和数字字符构成,字母不区分大小写。 2. 前3个字符用来给出FSA代码(forward sortation area,地区代码,2个字母中间夹一个数字),第一个字符用来表明省、市或地区(这个字符有18种合法的选择:ABCEGHJKLMNPRSTVXY) 3. 后3个字符用来给出LDU代码(local delivery unit,街道代码,2个数字中间夹一个字母) 4. FSA代码和LDU代码之间通常要用一个空格隔开。 * **文本** 123 4th Street,Toronto,Ontario,M1A 1A1 567 8th Avenue,Montreal,Quebec,H9Z 9Z9 * **正则表达式** `[ABCEGHJKLMNPRSTVXY]\d[A-Z] \d[A-Z]\d` * **结果** 123 4th Street,Toronto,Ontario,`M1A 1A1` 567 8th Avenue,Montreal,Quebec,`H9Z 9Z9` ### 美国社会安全号码(SSN:Social Security Number) 编码规则 1. 由3组以连字符隔开的数字构成: 2. 第1组包含着3位数字, 3. 第2组包含着2位数字, 4. 第3组包含着4位数字。 * **文本** John Smith:123-45-6789 * **正则表达式** `\d{3}-\d{2}-\d{4}` * **结果** John Smith:`123-45-6789` ### 中华人民共和国公民身份证号码 编码规则 1. 15位或者18位 2. 前6位是户口所在地编码,其中第一位是1~8; 3. 此后是出生年月日。出生年份的前两位只能是18、19、20,而且是可选的(兼顾15位),月份 中第一位只能是0或者1,日期的第一位只能是0~3; 4. 最后一位校验码是数字或者X,可选(兼顾15位)。 * **正则表达式** `[1-8]\d{5}((18)|(19)|(20))?\d{2}[0-1]\d[0-3]\d{4}[\dx]?` ### IPV4地址 编码规则 1. 由4个字节构成(这4个字节的取值范围都是0~255)。 2. 通常被写成4组以`.`字符隔开的整数(每个整数由1~3位数字构成)。 3. 每组数字可以是 * 1位或2位数字 * 以`1`开头的3位数字 * 以`2`开头,第2位数字在0~4之间的3位数字 * 以`25`开头,第3位数字在0~5之间的3位数字 * **文本** localhost is 127.0.0.1. * **正则表达式** `(((\d{1,2})1(1\d{2})1(2[0-4]\d)1(25[0-5])).){3}((\d{1,2})1(1\d{2})|(2[0-4]\d)1(25[0-5]))` * **结果** localhost is `127.0.0.1`. ### URL地址 在最简单的情况下,你的URL匹配模式至少应该匹配到以下内容: 1. 协议名(http或https)、 2. 一个主机名、一个可选的端口号 3. 一个文件路径。 * **文本** http://www.forta.com/blog https://www.forta.com:80/blog/index.cfm http://www.forta.com http://ben:password@www.forta.com/ http://localhost/index.php?ab=1&c=2 http://localhost:8500/ * **正则表达式** `https?://[-\w.]+(:\d+)?(/([\w/_.]*)?)?` * **结果** `http://www.forta.com/blog` `https://www.forta.com:80/blog/index.cfm` `http://www.forta.com` `http://ben`:password@www.forta.com/ `http://localhost/index.php?`ab=1&c=2 `http://localhost:8500/` ### 完整的URL地址 下面是一个更完备(也更慢)的URL地址匹配模式,它还可以匹配: 1. URL查询字符串(嵌在URL地址里的变量信息。这些信息与URL地址中的网址部分要用一个`?`隔开) 2. 以及可选的用户登录信息(用户名和口令,两者用`:`隔开最后跟`@`,文本中第4行)。 * **文本** http://www.forta.com/blog https://www.forta.com:80/blog/index.cfm http://www.forta.com http://ben:password@www.forta.com/ http://localhost/index.php?ab=1&c=2 http://localhost:8500/ * **正则表达式** `https?://(\w*:\w*@)?[-\w.]+(:\d+)?(/([\w/_.]*(\?\S+)?)?)?` * **结果** `http://www.forta.com/blog` `https://www.forta.com:80/blog/index.cfm` `http://www.forta.com` `http://ben:password@www.forta.com/` `http://localhost/index.php?ab=1&c=2` `http://localhost:8500/` ### 电子邮件地址 * **文本** My name is Ben Forta,and my email address is ben@forta.com. * **正则表达式** `(\w+\.)*\w+@(\w+\.)+[A-Za-z]+` * **结果** My name is Ben Forta,and my email address is `ben@forta.com`. * **分析** `(\w+\.)*\w+`负责匹配电子邮件地址里的用户名部分(@之前的所有文本):`(\w+\.)*`匹配一些由`.`结束的文本的零次或多次重复出现,`\w+`匹配必不可少的文本(这个组合将匹配ben和ben.forta等)。 `@`匹配@字符本身。 `(\w+\.)`匹配至少一个以`.`结束的字符串 `[A-Za-z]+`匹配顶级域名(com,edu,us或uk,等等)。 合法的电子邮件地址必须在排版格式方面同时满足许多项规定。这个模式不能用来匹配每一种可能的电子邮件地址。 比如说,这个模式会认为ben..forta@forta.com是一个合法匹配(但这显然不是一个合法的电子邮件地址);它不能用来匹配以IP地址做为主机名的电子邮件地址(但这种电子邮件地址是合法的)。 不过,因为绝大多数电子邮件地址都能与这个模式相匹配,所以你不妨先用它试试,如果效果不佳再考虑对之进行改进。 ### HTML注释 HTML页面里的注释必须被放在`<!--`和`-->`标签之间(这两个标签必须至少包含两个连字符,多于两个没有关系)。 在浏览(或调试)Web页面的时候,我们往往需要把所有的注释都找出来。 * **文本** ~~~ <!--Start of page--> <HTML> <!--Start of head--> <HEAD> <TITLE>MV Title</TITLE> <!--Page title--> </HEAD> <!--Body--> <BODY> ~~~ * **正则表达式** `<!-{2,}.*?-{2,}>` * **结果** ~~~ `<!--Start of page-->` <HTML> `<!--Start of head-->` <HEAD> <TITLE>My Title</TITLE> `<!--Page title-->` </HEAD> `<!--Body-->` <BODY> ~~~ * **分析** `<!-{2,}`匹配HTML注释的开始标签,也就是`<!`后面紧跟着两个或更多个连字符的情况。 `.*?`匹配HTML注释的文字部分(注意,这里用的是一个懒惰型元字符)。 `-{2,}>`匹配HTML注释的结束标签. ### JavaScript注释 JavaScript(其他脚本语言如ActionScript和IECMA Script的其他变体等)代码里的注释都以//开头。 正如刚才那个HTML注释的例子所示,把某给定页面里的所有注释全部查找出来是很有用的。 * **文本** ~~~ <SCRIPT LANGUAGE="JavaScript"> // Turn off fields used only by replace function hideReplaceFields(){ document.getElementById('RegExReplace').disabled=true; document.getElementBvId('replaceheader').disabled=true; } // Turn on fields used only by replace function showReplaceFields(){ document.getElementById('RegExReplace').disabled=false; document.getElementById('replaceheader').disabled=false; } ~~~ * **正则表达式** `//.*` * **结果** ~~~ <SCRIPT LANGUAGE="JavaScript"> `// Turn off fields used only by replace` function hideReplaceFields(){ document.getElementById('RegExReplace').disabled=true; document.getElementById('replaceheader').disabled=true; } `// Turn on fields used only by replace` function showReplaceFields(){ document.getElementById('RegExReplace').disabled=false; document.getElementById('replaceheader').disabled=false; } ~~~ * **分析** 这是一个很简单的模式:`//.*`匹配`//`和紧随其后的注释内容。 ### 信用卡号码 **MasterCard卡** 1. 总长为16位数字 2. 第1位是5 3. 第2位是1~5 正则表达式:`5[1-5]\d{14}` **Visa卡** 1. 总长为13位或16位数字 2. 第1位是4 正则表达式:`4\d{12}(\d{3})?` **美国运通卡(Amex)** 1. 总长为15位数字 2. 第1位是3 3. 第2位是4或7 正则表达式:`3[47]\d{13}` **Discover卡** 1. 总长为16位数字 2. 前4位是6011 正则表达式:`6011\d{12}` **Diners Club卡** 1. 总长为14位数字 2. 以300~305、36或38开头 正则表达式:`(30[0-5]|36\d|38\d)\d{11}` * **文本** MasterCard:5212345678901234 Visa1:4123456789012 Visa2:4123456789012345 Amex: 371234567890123 Discover:6011123456789012 Diners Club:38812345678901 * **正则表达式** `(5[1-5]1d14})|(4\d{12}(\d13})?)|(3[47]\d{13})|(6011\d{12})|((30[0-5]|36\d|38\d)\d{11})` * **结果** MasterCard:`5212345678901234` Visa1:`4123456789012` Visa2:`4123456789012345` Amex:`371234567890123` Discover:`6011123456789012` Diners Club:`38812345678901` * **分析** 这个模式用`|`操作符(正则表达式语言中的逻辑或操作符)把前面得到的5个模式结合到了一起。有了它,我们就可以一次完成对5种常见信用卡的号码格式进行检查了。 >[info] 这里使用的模式只能检查信用卡的号码是不是以正确的数字序列开头和是不是有着正确的总长度。 不过,并非所有以4开头的13位数字都是合法的Visa卡号,信用卡号码还必须满 足一个名为`Mod 10`的数学算法(这个算法适用于所有的信用卡类型)。 在对信用卡进行编程处理的时候,`Mod 10`算法是一个必不可少的重要环节,但这项检查不属于正则表达式的工作,因为正则表达式不涉及数学运算。 ## 资源 1. Ben Forta 撰写的 Sams Teach Yourself RegularExpressions in 10 Minutes 。《正则表达式必知必会》https://www.regular-expressions.info。ISBN:978-7-115-37799-9, 索书号TP30/437 2. [[Regular Exprssion Tester]](http://www.forta.com/books/0672325667) 3. [在线工具](http://c.runoob.com/front-end/854)