正则表达式(一)

 

  一、 什么是正则表达式
Windows/Dos 下我们用通配符 (wildcard) * ? 来查找文件,和通配符类似,正则表达式也是用来进行文本匹配的工具,只不过比起通配符,它能更精确地描述你的需求。
正则表达式也是用来进行文本匹配的工具,所以本文里多次提到了在字符串里搜索 / 查找,意思是在给定的字符串中,寻找与给定的正则表达式相匹配的部分。有可能字符串里有不止一个部分满足给定的正则表达式,这时每一个这样的部分被称为一个匹配。匹配在本文里可能会有三种意思:一种是形容词性的,比如说一个字符串匹配一个表达式;一种是动词性的,比如说在字符串里匹配正则表达式;还有一种是名词性的,就是上面说到的“ 字符串中满足给定的正则表达式的一部分 ”。
二、 入门
/b 是正则表达式规定的一个特殊代码,也叫元字符,代表着单词的开头或者结尾,也就是单词的分界处 , 它只匹配一个位置。
如果你要找的是 hi 后面不远处跟着一个 Lucy, 应该用 /bhi/b.*/Lucy/b
* 也是元字符,匹配除了换行符以外的任意字符,不过它代表的不是字符,也不是位置,而是数量。它指定 * 前面的内容以可以联系重复出现任意次以使整个表达式得到匹配。因此, .* 连在一起就意味着任意数量的不包含换行的字符。现在 /bhi/b.*/Lucy/b 的意思就很明显了:先是一个单词 hi, 然后是任意个字符(但不能是换行),最后是 Lucy 这个单词。
0/d/d-/d/d/d/d/d/d/d/d 匹配这样的字符串:以 0 开头,然后就是两个数字,然后是一个连字号“ - ”,最后是 8 个数字。
/d 是一个新的元字符,匹配任意的数字( 0 9 )。 - 不是元字符,只匹配它本身——连字号。也可以简写成: 0/d{2}-/d{8} 。这里 /d 后面的 {2} ({8}) 意思是前面 /d 必须连续重复匹配 2 次( 8 次)。
1 元字符
上节已经介绍了几个元字符 /b , . , * ,还有 /d ,当然还有更多的元字符可用,如 /s 匹配任意的空白符,包括空格,制表符( Tab ),换行符,中文全角空格等。 /w 匹配字母或数字或下划线或汉字等。
下面举几个例子:
/ba/w*/b 匹配以字母 a 开头的单词——先是某个单词开始处( /b , 然后是字母 a , 然后是任意数量的字母或数字( /w* , 最后是单词结束处( /b
       /d+ 匹配 1 个或更多连续的数字。这里 + 是和 * 类似的元字符,不同的是 * 匹配重复任意次(可能是 0 ),而 + 则匹配重复 1 次或更多次。
           /b/w{6}/b 匹配刚好 6 个字母 / 数字的单词。

1. 常用的元字符
代码
说明
.
匹配除换行符以外的任意字符
/w
匹配字母或数字或下划线或汉字
/s
匹配任意的空白符
/d
匹配数字
/b
匹配单词的开始或结束
^
匹配字符串的开始
$
匹配字符串的结束

元字符 ^ 以及 $ /b 有点类似,都匹配一个位置。 ^ 匹配你要用来查找的字符串的开头, $ 匹配结尾。这两个代码在验证输入的内容时非常有用,比如一个网站要求你填写的 QQ 号必须为 5 位到 12 位数字时,可以使用: ^/d{5,12}$
2 字符转义
如果你想查找元字符本身的话,就会出问题。这时就必须使用 / 来取消这些字符的特殊意义。因此,应该使用 / /* ,如果要查找 / 本身,就用 //
例如: www/.unibetter/.com 匹配 www.unibetter.com
c://Windows 匹配 c:/Windows
3 重复
你已经看过了前面的 * + {2} {5,12} 这几个匹配重复的方式了。下面是正则表达式中所有的限定符。

2. 常用的限定符
代码 / 语法
说明
*
重复零次或更多次
+
重复一次或更多次
?
重复零次或一次
{n}
重复n次
{n,}
重复n次或更多次
{n,m}
重复n到m次

下面是一些使用重复的例子:
Windows/d+ 匹配 Windows 后面跟 1 个或更多数字
13/d{9} 匹配 13 后面跟 9 个数字(中国手机号)
^/w+ 匹配一行的第一个单词(或整个字符串的第一个单词,具体匹配哪个得看选项设置)
4 字符类
如何 匹配没有预定义元字符的字符集合 ( 比如元音字母 a,e,i,o,u)?
很简单,只需要在中括号中列出它们就行了,像 [aeiou] 就匹配任何一个英文元音字母, [.?!] 匹配标点符号。
也可以指定一个字符范围,像 [0-9] 代表的含义与 /d 就是完全一致的:一位小数,同理 [a-z0-9A-Z] 也完全等用于 /w( 如果只考虑英文的话 )
下面是一个更复杂的表达式: /(?0/d{2}[ ) -]?/d{8}
这个表达式可以匹配几个格式的电话号码, (010)88886666 ,或 022-22334455 ,或 02912345678 ,但它也能匹配 010)12345678 (022-87654321 这样的“不正确”的格式 。下文讲给出解决这个问题的答案。
5 反义
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时就需要反义:

3. 常用的反义代码
代码 / 语法
说明
/W
匹配任意不是字母,数字,下划线,汉字的字符
/S
匹配任意不是空白符的字符
/D
匹配任意非数字的字符
/B
匹配不是单词开头或结束的位置
[^x]
匹配除了x以外的任意字符
[^aeiou]
匹配除了 aeiou 这几个字母以外的任意字符

例子: /S+ 匹配不包含空白符的字符串
<a[^>]+> 匹配用尖括号括起来的以 a 开头的字符串
6 替换
正则表达式里的替换指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用 | 把不同的规则分隔开。举例说明:
0/d{2}-/d{8}|0/d{3}-/d{7} 这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号, 8 位本地号(如 025-12345678 ),一种是 4 位区号, 7 位本地号( 0510-4567891 )。
/(/0d{2}/)[-]?/d{8}|0/d{2}[-]?/d{8} 这个表达式匹配的结果例如 (025)-12345678 025-12345678 02512345678
/d{5}-/d{4}|/d{5} 这个表达式用于匹配美国的邮政编码。美国编码规则是 5 位数字,或者用连字号间隔的 9 位数字。这个例子还说明一个问题:使用替换时,顺序是很重要的。如果改成 /d{5}|/d{5}-/d{4} 的话,那么就只会匹配 5 位的邮政编码以及 9 位邮编的前 5 位。因为匹配替换时,将会从左到右地测试每个分支条件,如果满足了某个分支的话,就不会去管其它的替换条件了。
7 分组
上面讲到如果想重复多个字符,可以用小括号来指定子表达式(也叫做分组),然后就可以指定这个子表达式的重复次数了。
(/d{1,3}/.){3}/d{1,3} 是一个简单的 IP 地址匹配表达式。分析: /d{1,3} 匹配 1 3 位的数字, (/d{1,3}/.){3} 匹配三位数字加上一个英文句号 ( 这个整体也就是这个分组 ) 重复 3 次,最后再加上一个 1 3 位的数字( /d{1,3} )。
但它也将匹配 256.300.888.999 这种不可能存在的 IP 地址( IP 地址中每个数字都不能大于 255 )。因为正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的 IP 地址: ((2[0-4]/d|25[0-5]|[01]?/d/d?)/.){3}(2[0-4]/d|25[0-5]|[01]?/d/d?)
2[0-4]/d|25[0-5]|[01]?/d/d? 进行分析:有三种匹配替换 2[0-4]/d 1 2 [0-4] 0 4 中的任意一位数字, /d 0-9 任意数字; 25[0-5] 前两位是 25 [0-5] 0 5 中任意数; [01]?/d/d? 01 重复 1 次或者 0 次, /d 0-9 任意数字, /d? 任意数字重复 1 次或者 0 次。
8 后向引用
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一次出现的分组的组号为 1 ,第二次为 2 ,以此类推。
后向引用 用于重复搜索前面某个分组匹配的文本。例如, /1 代表分组 1 匹配的文本。举例说明:
/b(/w+)/b/s+/1/b 可以用来匹配重复出现的单词,像 go go,kitty kitty 。首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字( /b(/w+)/b ),然后是 1 个或几个空白符( /s+ ),最后是前面匹配的那个单词( /1 )。
你也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法: (?<Word>/w+) 或者 (? 'Word'/w+) ) , 这样就把 /w+ 的组名指定为 Word 了。要反向引用这个分组捕获的内容,你可以使用 /k<Word> , 所以上一个例子也可以写成这样: /b(?<Word>/w+)/b/s+/k<Word>/b
使用小括号的时候,还有很多特定用途的语法。下面列出了最常用的一些:

4. 分组语法
捕获
(exp)
匹配 exp, 并捕获文本到自动命名的组里
(?<name>exp)
匹配 exp, 并捕获文本到名称为 name 的组里,也可以写成 (?'name'exp)
(?:exp)
匹配 exp, 不捕获匹配的文本,也不给此分组分配组号
零宽断言
(?=exp)
匹配 exp 前面的位置
(?<=exp)
匹配 exp 后面的位置
(?!exp)
匹配后面跟的不是 exp 的位置
(?<!exp)
匹配前面不是 exp 的位置
注释
(?#comment)
这种类型的组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

我们已经讨论了前两种语法。第三个 (?:exp) 不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面。
9 、零宽断言
接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像 /b ,^,$ 那样用于指定一个位置,这个位置应该满足一定的条件(断言),因此它们也被称为零度断言。举例说明:
(?=exp) 也叫零度宽正预测先行断言,它断言自身出现的位置的后面能匹配表达式 exp 。比如 /b/w+(?=ing/b) , 匹配以 ing 结尾的单词的前面部分(除了 ing 以外的部分),如查找 I'm singing while you're dancing. 时,它会匹配 sing danc
(?<=exp) 也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配的表达式 exp 。比如 (?<=/bre)/w+/b 会匹配以 re 开头的单词的后半部分(除 re 以外的部分),例如在查找 reading a book 时,它匹配 ading
例如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分 :
((?<=/d)/d{3})*/b, 用它对 1234567890 进行查找时结果是 234567890
下面这个例子同时使用了这两种断言: (?<=/s)/d+(?=/s) 匹配以空白符间隔的数字(不包括这些空白符)。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值