代码中使用正则表达式

910 阅读4分钟

1 基础

1.1 学习的意义

正则表达式脱离语言,和数据结构与算法一样,作为程序员的软技能。目前存在的问题:不受重视 优点:

  • 显著的提升代码质量
  • 灵活多变
  • 强大的数据校验支持

1.2 构建

构建正则表达式的方式很多,有以下的构造方法。

var regex1 = /itagn/g;
var regex2 = new RegExp('itagn', 'g');
var regex3 = new RegExp(/itagn/, 'g');
var regex4 = new RegExp(/itagn/g);

1.3 修饰符

常用的修饰符:

g: 全局匹配模式。作用于所有字符串,发现第一个匹配项后不会立即停止
i: 不区分大小写模式。忽略大小写进行匹配
m: 多行匹配模式。支持换行文本匹配

新增的修饰符:

u: Unicode模式。用来处理Unicode大于	\uFFFF的单个字符(超过\uFFFF会被程序员解析为两个字符)
y: 粘连模式。和g一样作为全局匹配,区别是g的下一次匹配不要求位置,但是y下一次匹配要求紧跟这这次匹配项之后
s: dotAll模式。正则表达式中点(.)作为匹配(除换行符\n,回车符\r,行分隔符,段分隔符)任意单个字符,支持点(.)真正匹配所有单个字符

2 匹配规则

2.1 关键词匹配

常用的匹配方式,通常是通过匹配关键词来实现定位

示例1:正则设定手机号格式

var regex = /^(086-)?1[345789]\d{9}$/;
regex.test('15512341234'); // true

示例2:正则将时间格式转换:年/月/日(yyyy/mm/dd)

var date = new Date();
var time = date.toISOString();
var regex = /^(\d{4})-(\d{2})-(\d{2})(.+)$/;
time.replace(regex, '$1/$2/$3'); // "2019/08/23"

2.2 位置匹配

常用的位置匹配就是^(匹配字符串开头)和$(匹配字符串结尾)。
另外还有\b(匹配一个单词边界),\B(匹配非单词边界)

示例1:把字符串中所有单词的首字母大写

var regex = /\b[a-z]/g;
var str = 'i am itagn who is a web developers';
str.replace(regex, word => word.toUpperCase()); // "I Am Itagn Who Is A Web Developers"

示例2:把字符串中所有每超过3个字符的单词就增加一个短横(-)

var regex = /[a-zA-Z]{3}\B/g;
var str = 'i am itagn who is a web developers';
str.replace(regex, word => word + '-'); // "i am ita-gn who is a web dev-elo-per-s"

3 高级用法

3.1 贪婪匹配

贪婪匹配:趋向于最大长度匹配。(默认)
非贪婪匹配:匹配到结果就好。

示例1:贪婪匹配获取数字

'123456789'.match(/\d+/)[0]; // "123456789"

示例2:非贪婪匹配获取数字

'123456789'.match(/\d+?/)[0]; // "1"

3.2 懒惰匹配

上文中的非贪婪匹配就用到了惰性匹配,其特点就是在其他重复量词后面加上限定符(?) 惰性匹配的特点:

  • 重复量词后面添加限定符(?)
  • 惰性匹配会尽可能少的匹配字符,同时必须满足整个匹配模式。

示例1:非惰性匹配惰性匹配

'123412341234'.match(/1(\d+)4/)[0]; // "123412341234"
'123412341234'.match(/1(\d+?)4/)[0]; // "1234"

3.3 先行断言/先行否定断言

先行断言:x只有在y前面才匹配,必须写成/x(?=y)/的形式。
先行否定断言:x只有不在y前面才匹配,必须写成/x(?!y)/的形式。

匹配的结果是x,如通过match方法匹配项会返回x。

示例1:先行断言先行否定断言的用法

/itagn(?=2019)/.test('itagn2019'); // true
/itagn(?=2019)/.test('itagn-2019'); // false

/itagn(?!2019)/.test('itagn2019'); // false
/itagn(?!2019)/.test('itagn-2019'); // true

我们可以发现,这里同时包含了关键词匹配位置匹配,属于正则的高级匹配。 接下来我们可以看看怎么处理业务中的问题。 示例2:通过正则把数字 1234567890 转换成美元 $1,234,567,890

var str = '1234567890';
var regex = /(?!^)(?=(\d{3})+$)/g;
str.replace(regex, ',').replace(/^/, '$'); // "$1,234,567,890"

3.4 后行断言/后行否定断言

后行断言和先行断言正好相反。

后行断言:x只有在y后面才匹配,必须写成/(?<=y)x/的形式。
后行否定断言:x只有不再y后面才匹配,必须写成/(?<!y)x/的形式。

匹配的结果是x,如通过match方法匹配项会返回x。

示例1:后行断言后行否定断言的用法

/(?<=2019)itagn/.test('2019itagn'); // true
/(?<=2019)itagn/.test('2019-itagn'); // false

/(?<!2019)itagn/.test('2019itagn'); // false
/(?<!2019)itagn/.test('2019-itagn'); // true

示例2:通过正则把美元 $123,456,789,000 变成美元 $1234,5678,9000 试着通过先行断言+先行否定断言来处理

var str = '$123,456,789,000';
var regex = /(?!^)(?=(\d{4})+$)/g;
str.replace(/,/g, '').replace(regex, ','); // "$,1234,5678,9000"

由于第一个字符是而不是数字,在这里`先行否定断言`判断字符串初始无效,所以在和数字中间出现了逗号分隔符。
同时也不能把(?!^)改成(?!$),因为匹配到1234,56789,000的时候前面的字符也不是$而是1,所以仍然会在开头添加一个逗号(,)。

var str = '$123,456,789,000';
var regex = /(?!\$)(?=(\d{4})+$)/g;
str.replace(/,/g, '').replace(regex, ','); // "$,1234,5678,9000"

我们发现,我们只需要排除一种情况,就是后面跟着逗号的情况。    
这个时候满足后行断言匹配项(x)在美元符号后面。
试着通过后行否定断言代替先行否定断言

var str = '$123,456,789,000';
var regex = /(?<!\$)(?=(\d{4})+$)/g;
str.replace(/,/g, '').replace(regex, ','); // "$1234,5678,9000"