正则表达式(一) 基本表达式

定义

正则表达式(Regular Expression)
用某种模式去匹配一类字符串的公式,主要用来描述字符串匹配的工具。

匹配
文本或字符存在不止一个部分满足给定的正则表达式,这是每一个这样的部分都被称为一个匹配
匹配分为以下三种类型:

  1. 形容词性的匹配
    即一个字符串匹配一个正则表达式
  2. 名词性的匹配
    即在文本或字符串里匹配正则表达式
  3. 名词性的匹配
    即字符串中满足给定的正则表达式的一部分

元字符

元字符(Metacharacter)是一类非常特殊的字符,它能够匹配一个位置或字符集合中的一个字符,元字符可以分为两种类型

  • 匹配位置的元字符
  • 匹配字符的元字符

元字符只能匹配一个字符位置,也就是一个匹配的单位是一个字符,而不是一个字符串

匹配位置的元字符

字符 说明
^ 匹配行开始
$ 匹配行结束
\b 匹配单词的开始或结束 不支持中文

测试

  • ^a
    匹配第一个字母为a的一行
  • a$
    匹配最后一个字母为a的一行
  • ^a$
    匹配只有一个字母a的一行
  • \bStr
    匹配以Str为开头的单词
  • ing\b
    匹配以ing为结尾的单词
  • \bString\b
    仅匹配String这个单词

\b字符如何识别哪个是单词呢?
以标点符号或空格分隔的字符串将被识别为单词,而且 \b只能用于英文,不能用于中文

匹配字符的元字符

元字符都是按照单个字符进行匹配

字符 说明
. (点号) 匹配除换行符之外的任意字符
\w 匹配任意单词字符(字母,数字,下划线)
\W 匹配任意非单词字符
\s 匹配任意空白字符(空格,制表符,换行符,中文全角空格)
\S 匹配任意非空白字符
\d 匹配任意数字 0~9的任意一个数字
\D 匹配任意非数字

测试

  • .
    全部字符匹配
  • \w
    匹配了全部的单词字符,除了下划线之外的标点符号和汉字都被排除在外
  • \W
    匹配结果和\w刚好相反,注意那个下划线是属于单词字符的
  • \s
    有2个空格被匹配,注意!这里总共有6个符号被匹配了,除了两个空格还有1~4行末的换行符
  • \S
    除了2个空格和4个换行符,其余字符全部匹配
  • \d
    匹配所有的数字
  • \D
    匹配所有数字之外的字符

元字符组合

仅仅是元字符就可以自由组合来实现不同的匹配效果

  • \w\w
    匹配连续的两个单词字符

  • \w\s
    注意第三行最后匹配的m是和行末的换行符一起匹配成功的

文字匹配

字符类

字符类是一个字符集合,如果该字符集合中的任何一个字符被匹配,则它会找到该匹配项。

  • []
    字符类使用中括号作为标志,字符集合写在中括号里面,意为匹配中括号中的任意一个字符
  • \-
    \-符号不是第一个字符的时候表示定义字符的范围,例如[1-3]表示[123][a-z]表示匹配任意小写字母,如果\-放在第一位,那就仅表示自己,这个范围的顺序和两个字符间的内容是按照ASCII表的顺序决定的,例如[9-1]是违反ASCII表顺序的一个表达式,这会报错
  • ^
    如果放在字符类第一个,表示该字符类的否定,[^123]表示匹配1、2、3之外的所有数字
  • 元字符在字符类中不做任何特殊处理,仅仅表示他们自身

测试

  • [aeiou]
    匹配元音字母
  • [a-z]
    匹配从小写字母az之间的所有字母
  • [^aeiou]
    匹配元音字母之外的所有字符(包括任意符号)
  • [^a-z]
    匹配小写字母az之间的所有字母之外的所有字符
  • [0-9]
    匹配从09之间的任意一个数字
  • [ao-u]
    匹配aou之间的所有字母,可以看到只要在连个字符之间使用连接符-就会判断为一个区间
  • [!-?]
    匹配从!?之间的任意一个符号,可以看到因为是按照ASCII表顺序来判断-连接的字符集合,所以这样写也是没有问题的
  • [a^-]
    匹配字符a^-三个字符,只要^符号不在第一位,-符号不在两个字符中间,那么它们就只表示自身
  • a[no]
    匹配字符串anao,这是字符类和元字符的组合

字符转义

之前介绍的元字符非常好用,但是这又引出了一个问题,如果我们想在正常的表达式里面使用元字符本身这个符号怎么办呢?难道每次都要写在字符类里面吗?
当然不,这里就引出了我们的字符转义

正则表达式定义了一些特殊的元字符,如^$.等。由于这些字符在正则表达式中被解释成其他指定的含义,如果需要匹配这些字符,则需要使用字符转义来解决这个问题。转义字符使用符号\(反斜杠),它可以取消这些字符(如^$.等)在表达式中具有的特殊意义。

  • .
    匹配字符.
  • *
    匹配字符*
  • \
    匹配字符\
  • www\.lanyuanxiaoyao\.com
    匹配字符串www\.lanyuanxiaoyao\.com,网址中的dot符号也是需要转义的

常用转义字符

字符或表达式 说明
\a 响铃(警报) \u0007
\b 在正则表达式中,表示单词的边界;如果在字符类中,则表示退格符\u0008
\t 制表符\u0009
\r 回车符\u000D
\v 垂直制表符\u000B
\f 换页符\u000C
\n 换行符\u000A
\e 回退(ESC)符\u001B
\040 将ASCII字符匹配为八进制数(最多3位)
\x20 使用十六进制表示,形式与ASCII字符匹配
\cC ASCII控制字符,如Ctrl-C
\u0020 使用十六进制表示形式(恰好4位)与Unicode字符匹配

限定符

这是一个重要的知识点
限定符用于指定允许特定字符或字符集自身重复出现的次数。

字符或表达式 说明
{n} 重复n次
{n,} 重复至少n次
{n,m} 重复至少n次,最多m次
* 重复至少0次,等同于{0,}
+ 重复至少1次,等同于{1,}
? 重复0次或1次,等同于{0,1}
\*? 尽可能少地使用重复的第1个匹配
+? 尽可能少地使用重复但至少使用1次
?? 使用0次重复(如果有可能)或1次重复
{n}? 等同于{n}
{n,}? 尽可能少地使用重复,但至少使用1次
{n,m}? 介于n次和m次之间,尽可能少地使用重复

测试

  • a{3}
  • a{2,}
  • a{2,3}
  • ab+
  • ab?
  • ab*
  • ab+?
  • ab??
  • ab*?

贪婪模式与懒惰模式

如果在限定符*+?{n}{n,}{n,m}之后再添加一个字符 ? ,则表示 尽可能少地重复字符?之前的限定符号的重复次数,这种匹配方式称为懒惰匹配,与之相对的,如果没有字符 ? ,仅仅使用单个限定符*+?{n}{n,}{n,m}的匹配,就称为贪婪匹配
看起来好像很复杂,但是理解历来并不难,即懒惰匹配模式只匹配最短符合表达式的字符串,贪婪匹配模式只匹配最长符合表达式的字符串。
这里的贪婪模式和懒惰模式在不同的教程或者说明里面都有不同的叫法,所以可以理解意思就行了,大同小异

测试

  • 贪婪模式 a.*b
    可以看到这里只有一个匹配,就是整个字符串,因为这是最长的匹配
  • 懒惰模式 a.?b
    这里一旦发现一个匹配立刻就完成当前的匹配,然后从下一个字符开始新的匹配,所以这里会有4个匹配

字符的运算

替换

替换使用字符|来表示,表示如果某一个字符串匹配了表达式中字符|左边或者右边的规则,那么这个字符串就匹配了这个表达式
|表示“或”的意思,这个符号和代码中的“逻辑或”相同,比较好理解
匹配是根据左边优先的原则,即从左往右,当左边的表达式不满足的时候,才会去尝试右边的表达式

测试

  • a|b
    可以看到不管是字符a还是b都可以匹配这个表达式,它等同于[ab]


分组

分组又被称为子表达式,即把一个正则表达式的全部或部分分成一个或多个组,分组使用()来表示,括号中的表达式就是一个组,一个组就是一个整体
要注意和字符类[]区分开来,[123]是表示匹配字符123,而(123)就是匹配123这个字符串

反向引用

组号
当一个正则表达式被分组之后,默认从左到右每一个分组都会自动被赋予一个组号,以左括号(为分界从1开始自增,第一个组的组号是1,第二个组的组号是2,以此类推,在后面的表达式,使用\组号的方式来引用前面的组,例如\b(\w)\1\b这个表达式中,后面的\1就是对前面(\w)组的引用
自定义组号
分组不止会自动使用数字作为组号,还可以手动命名,形式为(?<name>)(?<word>\w)(?'word'\w)都是把\w+匹配到的字母保存到名为word的分组,自定义命名的分组使用\k<name>的方式使用 ,如\b(?<word>\w)\k<word>\b是匹配连续的相同的两个字母的单词
反向引用
提供了查找重复字符组的简便方法,可以认为是再次匹配同一个字符组的快捷指令
反向引用引用的是前面的表达式匹配到的字符串,而不是前面的表达式
例如,\b(\w)\1\b 这个表达式中的\1表示的是前面\w匹配到的字符,前面匹配到字母a那么\1处也必须替换为字母a,而不是任意一个字母 所以这个表达式匹配的是两个完全相同的字母 而如果是\b(\w)\w\b 则是表示两个允许不相同的字母

字符 说明
(expression) 匹配字符串expression,并将匹配到的文本保存到自动命名的分组里
(?<name>expression) 匹配字符串expression,并将匹配的文本以name进行命名。该名称不能包含标点符号,不能以数字开头
(?:expression) 匹配字符串expression,不保存匹配的文明,也不给此组分配组号
(?=expression) 匹配字符串expression前面的位置
(?!expression) 匹配后面不是字符串expression的位置
(?<=expression) 匹配字符串expression后面的位置
(?<!expression) 匹配前面不是字符串expression的位置
(?>expression) 只匹配字符串expression一次

测试

  • (ab)
    ab就是一个整体看待,和单独的字符串ab没有区别
  • (?<word>ab)\k<word>
    ab这个组命名为word,然后在后面调用前面命名的这个组匹配的字符,即这个表达式相当于(ab)ab
  • (?:a)(b)\1
    前面的组被取消命名,所以自动命名从(b)开始,所以后面的\1匹配的是(b)
  • b(?=a)
    这个表达式的意思是,匹配字符b,这个字符b的后面紧跟着一个a
  • b(?!a)
    这个表达式的意思是,匹配字符b,这个字符b的后面不是a
  • (?<=a)b
    这个表达式的意思是,匹配字符b,这个字符b的前面是a
  • (?<!a)b
    这个表达式的意思是,匹配字符b,这个字符b的前面不是a
  • (?>a)b

参考

  1. 王蕾. 神奇的匹配 正则表达式求精之旅[M]. 北京:电子工业出版社, 2014.
  2. 文中使用的正则表达式测试工具:正则表达式测试工具在线调试与分享-Zjmainstay
  3. 文中使用的正则表达式可视化生成工具:Regulex JavaScript Regular Expression Visualizer.

每天都是 Debug 的一天

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345