数据/字符串处理是工作中经常能用到的,以前的做法大都是通过百度然后修改别人的代码完成字符串处理,一直想系统的跟正则认识一番,于是有了这篇。
点击《正则表达式》可查看原文哦!
同时非常感谢雪峰大大和鑫大大的文章支持,点击以下链接可查看参考原文。
雪峰大大的 标准对象/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.
可匹配anya
、anyb
、anyc
、anyd
......配合上量词再看看
\d{3}
表示匹配3个数字,例如010
\d{3,8}
表示3-8个数字,例如1234567
再加上我们的范围
[0-9a-zA-Z\_]
可以匹配一个数字、字母或者下划线
[0-9a-zA-Z\_]+
可以匹配至少由一个数字、字母或者下划线组成的字符串,比如a100
,0_Z
,Py3000
等等
[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意思,而是替换成第一个()中匹配的值,在这里表示首尾空格以外的值。 如果我们需要对捕获分组内容进行额外处理,可以把第二个参数作为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')
正则表达式的介绍就先到这里啦,怎么样,动手使用吧~~~