正则表达式入门

前言

俩件事促使我写这篇文章。一则之前面试面试到了正则,发现不甚熟悉。二则这些天看jQuery源码,一些正则看的有点费劲。

准备

先说些题外话。什么是正则表达式?其实正则表达式也叫规则表达式。个人感觉后者比较贴切。也很纳闷Regular Expression为什么会翻译成正则表达式。知道的朋友可以告知下。
其实这个正则就是字符串匹配工具,它描述了字符串的规则。无论是初学者还是老司机相信写起来都费劲,因为是火星文啊有木有。那为什么要学习这个火星文呢?那自然是好处大大啊。
举个栗子。前俩天解单时有个情况是需要对location.hash解析出#后面的第一个字符串(不包括/)。譬如

//"#/notebooks/17855961"解析出来的得是notebooks
// “#notebooks/17855961”解析出来的得是notebooks
function parseHash(str) {
    var hashArr = str.split('/');
    var res;
    if (hashArr[0] === '#') {
        res = hashArr[1];
    } else {
        res = hashArr[0].substring(1);
    }
    return res;
}
function parseHash(str) {
    var reg = /(?<=^(?:#\/|#))[^\/]+?(?=\/)/;
    return str.match(reg)[0];
}

其实,不用正则也是可以的,当然你得像上面一样写一大串代码。

基础

元字符

其实就是正则里具有特殊含义的字符。就比如\d代表数字。
常用元字符

代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始(值得注意的是,它在[]里面指的是非,在外面指的是字符串开始,还可以用在零宽断言)
$ 匹配字符串的结束

反义词

常用反义词
可以看得出好些就是元字符大写就是其对应的负面。每一对可匹配全部。譬如\w\W

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

限定符

什么是限定符呢?举个栗子吧。街上很多人。这个呢可以是元字符,而这个许多就是限定符。和元字符或者表达式模式结合使用
常用限定符

代码/语法 说明
* 重复零次或更多次(相当于{0,})
+ 重复一次或更多次(相当于{1,})
? 重复零次或一次(相当于{0,1})
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

转义

如果有时候你要匹配譬如.、*时会发现不能匹配,这是因为它们在正则里有其特殊含义(元字符等)。此时就需要转义。即.和*。
eg. https:\\baidu.com就是https:\baidu.com(瞎写o(╯□╰)o)

类与组以及分支

比如\d匹配数字,已经圈死为数字类。但是比如现在我想匹配自定义的类别,比如我想看看有没有1、2、3之中任何字符那就是[123]。比如[0-9]其实和/d一样。[]就是类,但是可以发现它只是单个字符,所以也就是字符类。
但是现在我想匹配多字符,那就是组了。比如我要匹配yellow、green、red。(yellow|green|red)。这()就是组,后面接限定符可以重复这个组,用法和元字符类似。|就是分支,也就是或的意思。
这里可能有点乱。给个小栗子总结下:
怎么匹配国内的手机号呢?咋们先想想手机号的规则。

  1. 手机号一共11位数字
  2. 前两位只能是13、14、15、18
  3. 有座机的朋友应该知道打外省的手机号需要加拨0(至少我小时候是这样子的_
    自然而然就得出答案:0?(13|14|15|18)[0-9]{9}
    自此,差不多可以应付大多数工作上简单的情况(工作上真心用得少,以为你会发现你用的复杂还怕别人看的痛苦,注释都不好写( ˇˍˇ )。更郁闷的是过几天自己都看不懂)

进阶

现在开始讲些难些的,用于应付阅读源码。

反向引用、捕获组/非捕获组

先举个小例子。比如给定一个字符串,我想先匹配一下一个不定的单词,然后此单词之后得跟着相同的单词。可能有点绕。就是比如前面匹配到了pz,那么紧跟着也得是pz,即pz pz。如果匹配到的时ap,那么紧跟着的也得是ap,即ap ap。
这时候就需要反向引用了。先写前面的匹配,即\b(\w+)\b\s+,之后怎么写呢?很简单:\b(\w+)\b\s+\1\b。这里的\1就是对前面的那个组的引用。
为什么时\1呢?其实每个组都是会分配到一个组号。整个正则表达式匹配到的为分组0,然后从左往右扫,依次分组1、2递增。注意,顺序看(,不要被数学里的表达式优先级给带入坑。比如:(1(2)(3)),顺序如此1、2、3,并非是2、3、1这个顺序
有个情况需要注意的是,正则不是某个语言独有的,所以不同语言的支持情况可能有差异。
PS: JS是不支持给组自定义分配组号的,C#就可以。有兴趣的可以了解了解。对了,若是有自定义组号,分配组号时会扫描俩遍。第一遍是给未自定义组号的组分配组号,第二遍给自定义的组分配组号。
如果组过多的话我不想某些组被捕获,那么可以使用?:。即捕获组为(exp),非捕获组为(?:exp)。非捕获组是不会被分配组号的。也不被捕获文本。(字符串match返回值不包括非捕获组)

代码/语法 说明
(exp) 捕获组:匹配exp,会被分配组号的,被捕获文本
(?:(exp) 非捕获组:匹配exp,不会被分配组号的,也不被捕获文本

有图有真相时间(给本小节所说证明一下)


捕获组

非捕获组

零宽断言(zero-width assertion)

先行断言、先行否定断言(JS支持)


好吧,这就是我第一次知道这货的表情。什么鬼?已经很难明白了,现在连命名都这样子?怎么活。好吧,不急,其实这货意义就是指定位置应该满足指定的条件。还是很无语?


  1. 比如匹配小数的整数部分,即:/\d+(?=.)/。
    (?=exp)就是正预测先行断言,也叫先行断言,只匹配exp前面的位置,断言自身位置后面跟着exp

    可以看见的是先行断言是不会被匹配到的,这就是零宽。它只是告诉你是否匹配成功,它不消费任何字符。
  2. 除了先行断言,还有先行否定断言,也就是负预测先行断言。这货是先行断言的否定,看名字就看得出来。
    比如匹配后面没有小数点的数字,即:/\d+(?!.)/g
    (?!exp)就是负预测先行断言,也叫先行否定断言,只匹配后面没有exp的位置,断言自身后面没有exp

后行断言、后行否定断言(目前不支持,但将支持)

其实也不能说不支持,至少此时我试了下我的Chrome(版本 62.0.3202.94)是支持的,不过Firefox是不支持的。

  1. 比如要匹配小数的小数部分,即/\d+(?<=.)/
    (?<=exp)就是后行断言,也叫正回顾后发断言,只匹配前面有exp的位置,断言自身前面有exp
  2. 比如匹配前面没有小数点的数字,即:/(?<!exp)\d+/
    (?<!exp)就是后行否定断言,也叫负回顾后发断言,只匹配前面没有exp的位置,断言自身前面没有exp

正则的性情(贪婪模式、懒惰模式)

正则默认情况下是贪婪的。就比如爬过小说的朋友应该知道。不是所有的网站都是通过API请求数据填充网页的。很多网站是服务端渲染,爬的时候就只能获取到整个HTML网页。这时候就需要使用正则把html标签去掉。
有了上面的知识你很快就会写出来: /<.+>/g。字符串replace方法替换成空格即可。很遗憾,这个是不行的,为什么呢?因为正则贪婪

<main>
    <header>斗破苍穹</header>
    <article>炎帝</article>
    <footer>五帝破空</footer>
</main>
//这里会匹配到整个html,因为你会发现整个html也符合你写的这个表达式呀

这时候机智的你可能会想到,<>里面是不能有<>的,那我可以这样子:/<[^<>]+>/g。
是的,的确可行。但是你至少得想到这个特殊情况吧,难道以后每次都得想下,很是麻烦啊。其实有简便的方法,那就是限定符后面加个?。即:/<.+?>/g,这就是懒惰模式
很好理解,就是匹配到就不继续了。?本来就是代表0-1嘛(强行解释一波O(∩_∩)O哈哈~)


PS: 所以有*?、+?、??、{n, m}?、{n, }?。是没有{n}?滴

修饰符

为什么修饰符放在最后说呢?因为它最不起眼。最简单。
就是加在正则最后面。

修饰符 描述
i ignoreCase执行对大小写不敏感的匹配。
g global执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)

有兴趣可以自行看下多行模式,这里不提。

RegExp对象

既然是前端,自然得来点前端的

属性

其实上面的修饰符也是RegExp属性,比如

/\d/g.ignoreCase  // false
/\d/g.global // true

与修饰符无关的主要有俩

  1. source,返回正则表达式字符串形式
/^\d\\\.[0-9]$/g.source // "^\d\\\.[0-9]$"
  1. lastIndex,返回下一次开始搜索的位置,它是可读写的,注意只有带g修饰符才有意义


方法

  1. test
    返回true or false,表示当前表达式能否匹配当前字符串
  2. exec
    匹配到的话以数组形式返回结果,成员是每一个匹配到的串,否则返回null

后记

最后来个考试。从jQuery拷了个正则解读下

/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/

我看懂了,你们呢?

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

推荐阅读更多精彩内容

  • 注:本篇文章只为方便查看,特此保留,如有冒犯,敬请谅解!!! 本文目标 30分钟内让你明白正则表达式是什么,并对它...
    阿杰Alex阅读 1,449评论 0 10
  • 正则表达式到底是什么东西?字符是计算机软件处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等...
    狮子挽歌阅读 2,104评论 0 9
  • 所有加粗的元字符的双引号均为了方便表示,所有的正则表达式均在 ‘’ ——单引号中 “/b”:元字符,代表单词的开始...
    哎呀_落锦繁华阅读 187评论 0 0
  • 什么是正则表达式呢? 正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一...
    chenxiaoer阅读 401评论 0 1
  • 金是最先从震惊中反应过来的人。 他走到一具断头的尸体处,由于人早就死亡,所以颈部只有少量流血,伤口就像传言一样,是...
    永恒天火阅读 189评论 0 0