为什么需要正则呢?
将给定的数字转化成千分位的格式,如把“10000”转化为“10,000”
// js逻辑写法
function transform(num) {
num = (num + '').split('')
ı
var temp = []
var count = 0;
for (var len = num.length, i = len - 1; i >= 0; i--) {
temp.unshift(num[i])
count+=1
if(count % 3 === 0 && i != 0) {
temp.unshift(',')
}
}
return temp.join('')
}
// 正则写法
function transform(num) {
num = num + '';
return num.replace(/(?=(?!\b)(\d{3})+$)/g, ',');
}
-
定义方式
var reg = /(?=(?!\b)(\d{3})+$)/g // 对象字面量声明 /pattern/flag
var reg = new RegExp('(?=(?!\\b)(\\d{3})+$)', 'g') // 构造函数声明正则,其实就是去掉了两边的 / 而且里面的每个 \ 都要转义
-
打印方式
-
RegExp 对象
方法
test() 返回 true 或者 false
exec() 返回一个类数组,其实是个对象,返回的结果中的
"0"
项是完全匹配的字符串,一般没什么用,但"1"
项会返回捕获分组的结果就很有用属性
source 返回当前正则表达式对象的模式文本的字符串不包含 // 和 标志位
ignoreCase 标志位 i 忽略大小写
global 标志位 g 全局匹配 用 string.match() 可以拿出所有匹配的字符串
multiline 标志位 m 有换行符
\n
可以匹配多行
-
基本语法
开头
^ 匹配字符串的开始 $ 匹配字符串的结束 量词
? 等价于{ 0, 1 },表示出现或者不出现 + 等价于{ 1, } ,表示出现至少一次 * 等价于{ 0, } ,表示出现任意次,有可能不出现 { m } 等价于{ m, m },表示出现m次 { m, } 表示至少出现m次 常见简写
\w 匹配字母或数组或下划线的字符 [0-9a-zA-Z_] 英文:word \W 匹配不是字母,数字,下划线的字符 [^ 0-9a-zA-Z] \d 匹配数字 [0-9] 英文:digit \D 匹配非数字的字符 [^ 0-9] \s 匹配任意空白符 [ \t\v\n\r\f] 英文:space \S 匹配不是空白符的字符 [^ \t\v\n\r\f] \b 匹配单词的开始或结束的位置 \B 匹配不是单词开头或结束的位置 [abc]
一个字符集abc,匹配包含abc中任意的字符
[^xyz]
一个否定字符集,匹配不包含abc中任意的字符
[\d\D]
、[\w\W]
、[\s\S]
和[^]
匹配任意字符 其他
\b \W和\w 的边界 \B \w
与\w
、\W
与\W
、^
与\W
,\W
与$
之间的位置?=p 字符 p
前面的位置?!p 非字符 p
前面的位置
-
贪婪匹配和惰性匹配
var regex = /\d{2,5}/g; var string = "123 1234 12345 123456"; console.log( string.match(regex) ); // => ["123", "1234", "12345", "12345"]
其中正则
/\d{2,5}/
,表示数字连续出现2到5次。会匹配2位、3位、4位、5位连续数字。但是其是贪婪的,它会尽可能多的匹配。你能给我6个,我就要5个。你能给我3个,我就3要个。反正只要在能力范围内,越多越好。
我们知道有时贪婪不是一件好事(请看文章最后一个例子)。而惰性匹配,就是尽可能少的匹配:
var regex = /\d{2,5}?/g; var string = "123 1234 12345 123456"; console.log( string.match(regex) ); // => ["12", "12", "34", "12", "34", "12", "34", "56"]
其中/\d{2,5}?/
表示,虽然2到5次都行,当2个就够的时候,就不在往下尝试了。通过在量词后面加个问号就能实现惰性匹配,因此所有惰性匹配情形如下:
{m,n}? {m,}? ?? +? *?
-
多选分支
一个模式可以实现横向和纵向模糊匹配。而多选分支可以支持多个子模式任选其一。
具体形式如下:
(p1|p2|p3)
,其中p1
、p2
和p3
是子模式,用|
(管道符)分隔,表示其中任何之一。例如要匹配"good"和"nice"可以使用
/good|nice/
。测试如下:var regex = /good|nice/g; var string = "good idea, nice try."; console.log( string.match(regex) ); // => ["good", "nice"]
但有个事实我们应该注意,比如我用
/good|goodbye/
,去匹配"goodbye"字符串时,结果是"good":var regex = /good|goodbye/g; var string = "goodbye"; console.log( string.match(regex) ); // => ["good"]
而把正则改成
/goodbye|good/
,结果是:var regex = /goodbye|good/g; var string = "goodbye"; console.log( string.match(regex) ); // => ["goodbye"]
也就是说,分支结构也是惰性的,即当前面的匹配上了,后面的就不再尝试了。
-
常用例子
匹配邮箱的正则
var str = 'https://qq.com/' var reg = /^https?:\/\/q{2}\.com\/$/g console.log(reg.test(str)) // true console.log(str.match(reg)) // ["https://qq.com/"] console.log(reg.exec(str)) // ["https://qq.com/", index: 0, input: "https://qq.com/", groups: undefined]
匹配日期
比如yyyy-mm-dd格式为例。
要求匹配:
2017-06-10分析:
年,四位数字即可,可用
[0-9]{4}
。月,共12个月,分两种情况01、02、……、09和10、11、12,可用
(0[1-9]|1[0-2])
。日,最大31天,可用
(0[1-9]|[12][0-9]|3[01])
。正则如下:
var regex = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/; console.log( regex.test("2017-06-10") ); // => true
匹配id
要求从
<div id="container" class="main"></div>提取出id="container"。
可能最开始想到的正则是:
var regex = /id=".*"/ var string = '<div id="container" class="main"></div>'; console.log(string.match(regex)[0]); // => id="container" class="main"
因为
.
是通配符,本身就匹配双引号的,而量词*
又是贪婪的,当遇到container后面双引号时,不会停下来,会继续匹配,直到遇到最后一个双引号为止。解决之道,可以使用惰性匹配:
var regex = /id=".*?"/ var string = '<div id="container" class="main"></div>'; console.log(string.match(regex)[0]); // => id="container" var regex = /id=".*?"/ var string = '<div id="container" id="test" class="main"></div>'; console.log(string.match(regex)); // => ["id="container"","id="test""]
数字的千位分隔符表示法
比如把"12345678",变成"12,345,678"。
可见是需要把相应的位置替换成","。
思路是什么呢?
- 弄出最后一个逗号
使用
(?=\d{3}$)
就可以做到:var result = "12345678".replace(/(?=\d{3}$)/g, ',') console.log(result); // => "12345,678"
- 弄出所有的逗号
因为逗号出现的位置,要求后面3个数字一组,也就是
\d{3}
至少出现一次。此时可以使用量词
+
:var result = "12345678".replace(/(?=(\d{3})+$)/g, ',') console.log(result); // => "12,345,678"
- 匹配其余案例
写完正则后,要多验证几个案例,此时我们会发现问题:
var result = "123456789".replace(/(?=(\d{3})+$)/g, ',') console.log(result); // => ",123,456,789"
因为上面的正则,仅仅表示把从结尾向前数,一但是3的倍数,就把其前面的位置替换成逗号。因此才会出现这个问题。
怎么解决呢?我们要求匹配的到这个位置不能是开头。
我们知道匹配开头可以使用
^
,但要求这个位置不是开头怎么办?easy,
(?!^)
,你想到了吗?测试如下:var string1 = "12345678", string2 = "123456789"; reg = /(?!^)(?=(\d{3})+$)/g; var result = string1.replace(reg, ',') console.log(result); // => "12,345,678" result = string2.replace(reg, ','); console.log(result); // => "123,456,789"
4.2.4 支持其他形式
如果要把"12345678 123456789"替换成"12,345,678 123,456,789"。
此时我们需要修改正则,把里面的开头
^
和结尾$
,替换成\b
:var string = "12345678 123456789", reg = /(?!\b)(?=(\d{3})+\b)/g; var result = string.replace(reg, ',') console.log(result); // => "12,345,678 123,456,789"
其中
(?!\b)
怎么理解呢?要求当前是一个位置,但不是
\b
前面的位置,其实(?!\b)
说的就是\B
。因此最终正则变成了:
/\B(?=(\d{3})+\b)/g
。
参考文章: