正则表达式

  数据/字符串处理是工作中经常能用到的,以前的做法大都是通过百度然后修改别人的代码完成字符串处理,一直想系统的跟正则认识一番,于是有了这篇。

点击《正则表达式》可查看原文哦!
同时非常感谢雪峰大大和鑫大大的文章支持,点击以下链接可查看参考原文。
雪峰大大的 标准对象/RegExp.
鑫大大的 粉丝群第27期JS基础小测答疑文字版

  好的,接下来进入正题啦。

正则表达式定义

  正则表达式是对字符串操作的一种逻辑公式,用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
举个例子:
  '00\d'可以匹配'007',‘008’,其中‘\d’即匹配数字。

语法

元字符

 字 符   描 述  反义字符   描 述
$ 匹配输入字符串的结尾位置
^ 匹配输入字符串的开始位置
. 匹配除换行符 \n 之外的任何单字符
\b 匹配单词边界 \B 匹配不是单词开头或结束的位置
\d 匹配数字 \D 匹配任意非数字的字符
\w 匹配字母,数字,下划线 \W 匹配任意不是字母,数字,下划线 的字符
\s 匹配空格 \S 匹配任意不是空白符的字符
[abc] 匹配包含括号内元素的字符 [^abc] 匹配除了abc以外的任意字符

量词

 字 符   描 述  带?字符   描 述
* 重复至少0次 *? 重复任意次,但尽可能少重复
+ 重复至少1次 +? 重复至少1次,但尽可能少重复
? 重复0次或1次 ?? 重复0次或1次,但尽可能少重复
{n} 重复n次
{n,} 重复至少n次 {n,}? 重复至少n次,但尽可能少重复
{n,m} 重复n-m次 {n,m}? 重复n-m次,但尽可能少重复

特殊字符

 字 符   描 述  字 符   描 述
\cx 匹配由x指明的控制字符。
\f 匹配一个换页符。等价于 \x0c 和 \cL。 ( ) 标记一个子表达式的开始和结束位置。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。 | 指明两项之间的一个选择,或
\r 匹配一个回车符。等价于 \x0d 和 \cM。 [ 标记一个中括号表达式的开始
\s 匹配任何空白字符,包括空格、制表符、换页符等等。 \ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 { 标记限定符表达式的开始。
\t 匹配一个制表符。等价于 \x09 和 \cI。 \v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

举例说明

  • 数字、字母匹配(\d匹配数字,\w匹配任意字母,数字,下划线)
    可用00\d可以匹配007
    \d\d\d可以匹配任意三位数字,如:123
    \w\d\w可以匹配l0l

  • .匹配任意字符,则
    any.可匹配anyaanybanycanyd ......

  • 配合上量词再看看
    \d{3}表示匹配3个数字,例如010
    \d{3,8}表示3-8个数字,例如1234567

  • 再加上我们的范围
    [0-9a-zA-Z\_]可以匹配一个数字、字母或者下划线
    [0-9a-zA-Z\_]+可以匹配至少由一个数字、字母或者下划线组成的字符串,比如a1000_ZPy3000等等
    [a-zA-Z\_][0-9a-zA-Z\_]*可以匹配由字母或下划线开头,后接任意个由一个数字、字母或者下划线组成的字符串,也就是Python合法的变量
    [a-zA-Z\_][0-9a-zA-Z\_]{0, 19}更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)

  • 啊,还有我们的选择字符和定位
    A|B可以匹配A或B,所以(P|p)ython可以匹配Python或者python
    ^表示行的开头,^\d表示必须以数字开头
    $表示行的结束,\d$表示必须以数字结束
    你可能注意到了,py也可以匹配python,但是加上^py$就变成了整行匹配,就只能匹配py

  • 字符串的切割
    最常用的应该就是split切割了,但是当字符串之间不仅仅是单一字符连接,切割就会出现问题,比如下面的例子

     //出现多余空格情况:
        'a b   c'.split(' '); // ['a', 'b', '', '', 'c']
    
    //嗯,无法识别连续的空格,用正则表达式试试:
    'a b   c'.split(/\s+/); // ['a', 'b', 'c']
    //无论多少个空格都可以正常分割。加入,试试:
    
    'a,b, c  d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']
    //再加入;试试:
    
    'a,b;; c  d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd']
    //如果用户输入了一组标签,下次记得用正则表达式来把不规范的输入转化成正确的数组。
    
  • 字符串的分组应用
    除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组(Group)。比如:^(\d{3})-(\d{3,8})$分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:

    var re = /^(\d{3})-(\d{3,8})$/;
    re.exec('010-12345'); // ['010-12345', '010', '12345']
    re.exec('010 12345'); // null
    

    如果正则表达式中定义了组,就可以在RegExp对象上用exec()方法提取出子串来。
    exec()方法在匹配成功后,会返回一个Array,第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串。
    exec()方法在匹配失败时返回null。

    提取子串非常有用。来看一个更凶残的例子:

    var re = /^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$/;
    re.exec('19:05:30'); // ['19:05:30', '19', '05', '30']
    

    这个正则表达式可以直接识别合法的时间。但是有些时候,用正则表达式也无法做到完全验证,比如识别日期:

    var re = /^(0[1-9]|1[0-2]|[0-9])-(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[0-9])$/;   
    

    对于'2-30','4-31'这样的非法日期,用正则还是识别不了,或者说写出来非常困难,这时就需要程序配合识别了。


以下内容参见鑫大大博客内容:

  • 中英文之间需要增加空格
    首先,我们的思路应该是“中文”、“英文”、“空格”,于是我们可得到 /(中文+英文+|英文+中文+)/g 这样的符号表达
    转换成正则符号即: /([\u4e00-\u9fa5]+[A-Za-z]+|[A-Za-z]+[\u4e00-\u9fa5]+)/g
    其中[\u4e00-\u9fa5]表示中文字符匹配;[A-Za-z]表示全部的英文字母。斜杠后面的g表示全局匹配,<font color="#a00">除了g,还有i和m。其中i表示不区分大小写,m表示支持多行匹配。</font>
    这里的括号和加号可化简,则最终可表达为: 
    /[\u4e00-\u9fa5][a-z]|[a-z][\u4e00-\u9fa5]/gi

  • 全角标点与其他字符之间不加空格
    这里如果直接用正则表达式,会显得冗余且不易懂,故使用RegExp对象简化

    // 全角标点字符们  
    var strPunct = '!()【】『』「」《》“”‘’;:,。?、';  
    // 使用管道符连接  
    var regPunct = strPunct.split('').join('|');  
    // 此时的正则表达式  
    new RegExp('['+ regPunct +'] +| +['+ regPunct +']', 'g');  
    

    这样就显得简洁多了
    其中,空格使用普通空格字符进行匹配的,而不是\s,这样可以避免把换行符也过滤掉了

  • 不重复使用标点符号
    这里的标点指中文标点,因为英文标点不重复,有些不切实际,例如空字符串'',就是合法的重复标点。
    使用正则表达式:

    /(\~|\`|\!|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?|\!|\·|\【|\】\「\」|\;|\:|\“|\”|\,|\《|\。|\》|\、|\?)\1+/g  
    

    使用RegExp对象简化:

    new RegExp(`(${regPunct})\\1+`, 'g')
    

    这样就是不使用重复中文标点了。
    其中,这里的\1有必要好好说下。\1表示捕获匹配,表示捕获第一个分组括号中匹配的值,你可以理解为代称。在正则表达式中,每一个分组括号()都自带一个看不见的序号,从前往后依次是分组一,分组二,分组三……
    这里的\1就表示匹配的第一个标点,后面跟了个+则表示,这里重复标点2个或多个都匹配。
    捕获分组不仅存在于正则表达式中,当我们使用replace方法进行正则替换的时候,也存在与替换方法中,使用美元符号$外加数字表示,例如前后空格过滤trim()方法的简易polyfill:

    if (!''.trim) {
        String.prototype.trim = function () {
          // $1表示第一个()中匹配的值
          return this.replace(/^\s*(.*?)\s*$/, '$1');
        };
    }
    

    其中'1'并不是替换成字符串1意思,而是替换成第一个()中匹配的值,在这里表示首尾空格以外的值。 如果我们需要对捕获分组内容进行额外处理,可以把第二个参数作为function处理,例如:

    this.replace(/^\s*(.*?)\s*$/, function (matches, $1) {
        // matches表示完整匹配内容(包括前后空格)
        // $1则表示第一个()中匹配的值 
        // 此时就可以对$1进行处理,返回我们需要的值
    })
    
  • 破折号前后需要增加一个空格
    这个比较简单,可直接获得:

    /\S——|——\S/g
    
  • 使用全角中文标点
    正则表达式

    /([^A-Za-z][\~|\`|\!|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?][^A-Za-z])/g
    

    使用RegExp对象处理:

    var strPunctHalf = '!()[]"\';:,.?';
    // 不同于全角字符,半角字符需要加转义
    var regPunctHalf = strPunctHalf.split('').join('|\\');
    // 此时的正则表达式
    new RegExp(`[\u4e00-\u9fa5][a-z]*( *[${regPunctHalf}] *)|( *[${regPunctHalf}] *)[a-z]*[\u4e00-\u9fa5]`, 'gi');
    
  • 数字使用半角
    /[\uFF10-\uFF19]+/g

  • 遇到完整的英文整句,其內容使用半角标点
    正则表达式

    /(\「[A-Za-z\s\~|\`|\!|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]*[\!|\·|\;|\:|\“|\”|\,\。|\、|\?][^\」]*\」)|(\《[A-Za-z\s\~|\`|\!|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]*[\!|\·|\;|\:|\“|\”|\,\。|\、|\?][^\》]*\》)/g
    

    RegExp对象处理:

    new RegExp(`([a-z]+[${regPunct}|\\s])+[a-z]*([${regPunct}|\\s][a-z]+)+`, 'gi')
    

  正则表达式的介绍就先到这里啦,怎么样,动手使用吧~~~

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

推荐阅读更多精彩内容