Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

代码中使用正则表达式 #291

Open
itagn opened this issue Sep 22, 2019 · 0 comments
Open

代码中使用正则表达式 #291

itagn opened this issue Sep 22, 2019 · 0 comments

Comments

@itagn
Copy link
Member

itagn commented Sep 22, 2019

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"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant