共计 4013 个字符,预计需要花费 11 分钟才能阅读完成。
在平时的工作中经常会碰到正则,然而我发现,每次都遗记该怎么去写,所以在这里略微温习总结一下
先看题
/* 题目一 */
var str1 = '123456765464153513566'
// 宰割数字每三个以一个逗号划分(从后往前)
// 如 1234 -> 1,234
/* 题目二 */
var str2 = "get-element-by-id"
// 将 - 的命名形式改为小驼峰
// 冀望后果 getElementById
/* 题目三 */
var str3 = 'getElementById'
console.log(str3.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase())
// 写出运行后果
看完这三个题目,你是否有想法,上面颁布答案
// 题目一
console.log(str1.replace(/(\d)(?=(\d{3})+$)/g,'$1,'))
// 123,456,765,464,153,513,566
// 题目二
console.log(str2.replace(/-\w/g, ($0) => {return $0.slice(1).toUpperCase()}))
// getElementById
// 题目三
// get-element-by-id
如果你的答案全副正确,那么请疏忽上面的内容
温习
简略的匹配规定
- 如想在
apple
这个单词里找到a
这个字符,就间接用/a/
这个正则就能够了 - 如果想匹配
*
, 须要应用\
来本义去掉其原本的含意,正则就能够写成/\*/
- 有一些字符本不是特殊字符,应用本义符号就会让它领有非凡的含意
特殊字符 | 正则表达式 | 记忆形式 |
---|---|---|
换行符 | n | new line |
换页符 | f | form feed |
回车符 | r | return |
空白符 | s | space |
制表符 | t | tab |
垂直制表符 | v | vertical tab |
回退符 | [b] | backspace, 之所以应用 [] 符号是防止和 b 反复 |
匹配多字符
- 汇合的定义形式是应用中括号
[
和]
, 如/[123]/
这个正则就能同时匹配 1,2,3 三个字符。用/[0-9]/
就能匹配所有的数字,/[a-z]/
则能够匹配所有的英文小写字母 - 同时匹配多个字符的简便正则表达式:
匹配区间 | 正则表达式 | 记忆形式 |
---|---|---|
除了换行符之外的任何字符 | . | 句号, 除了句子结束符 |
单个数字, [0-9] | d | digit |
除了[0-9] | D | not digit |
包含下划线在内的单个字符,[A-Za-z0-9_] | w | word |
非单字字符 | W | not word |
匹配空白字符, 包含空格、制表符、换页符和换行符 | s | space |
匹配非空白字符 | S | not space |
反复匹配
- 元字符
?
代表了匹配一个字符或 0 个字符, 例匹配color
和colour
这两个单词, 就能够写为/colou?r/
- 元字符
*
用来示意匹配 0 个字符或无数个字符, 例匹配color
和colouuuuuur
就能够写为/colou*r/
- 元字符 + 实用于要匹配同个字符呈现 1 次或屡次的状况。
color
和colour
这两个单词,若应用/colou+r/
来匹配,就只能匹配到colour
-
匹配特定的次数,能够应用元字符
{
和}
用来给反复匹配设置准确的区间范畴。如a
我想匹配 3 次, 那么我就应用/a{3}/
这个正则,或者说a
我想匹配至多两次就是用/a{2,}/
这个正则。- {x}: x 次
- {min, max}:介于 min 次到 max 次之间
- {min,}: 至多 min 次
- {0, max}:至少 max 次
总结
| 匹配规定 | 元字符 |
| :—–:| :—-: |
| 0 次或 1 次 | ? |
| 0 次或无数次 | * |
| 1 次或无数次 | + |
| 特定次数 | {x}, {min, max} |
地位边界
- 单词边界
\b
, 例The cat scattered his food all over the room.
匹配出所有的单词cat
,就能够写成/\bcat\b/g
- 字符串边界,元字符
^
用来匹配字符串的结尾。而元字符$
用来匹配字符串的开端。
边界总结:
边界和标记 | 正则表达式 | 记忆形式 |
---|---|---|
单词边界 | b | boundary |
非单词边界 | B | not boundary |
字符串结尾 | ^ | – |
字符串结尾 | $ | – |
多行模式 | m 标记 | multiple of lines |
疏忽大小写 | i 标记 | ignore case, case-insensitive |
全局模式 | g 标记 | global |
子表达式
分组
所有以 (
和 )
元字符所蕴含的正则表达式被分为一组,每一个分组都是一个 子表达式
,它也是形成高级正则表达式的根底。
回溯援用
回溯援用(backreference)指的是前面局部援用后面曾经匹配到的子字符串。你能够把它设想成是变量,回溯援用的语法像\1
, \2
,…., 其中 \1
示意援用的第一个子表达式,\2
示意援用的第二个子表达式,以此类推。而 \0
则示意整个表达式。
// 例如
// 匹配上面字符串中两个间断的单词
// Hello what what is the first thing, and I am am scq000.
var str4 = 'Hello what what is the first thing, and I am am scq000.'
console.log(str4.match(/\b(\w+)\s\1/g))
用 $1
, $2
… 来援用要被替换的字符串
var str = 'abc abc 123';
str.replace(/(ab)c/g,'$1g');
// 失去后果 'abg abg 123'
如果咱们不想子表达式被援用,能够应用非捕捉正则 (?:regex) 这样就能够避免浪费内存。
var str = 'scq000'.
str.replace(/(scq00)(?:0)/, '$1,$2')
// 返回 scq00,$2
// 因为应用了非捕捉正则,所以第二个援用没有值,这里间接替换为 $2
var str4 = 'scq000 scq001'
console.log(str4.replace(/(scq00)(?:0)/, '$1,$2'))
// 返回 scq00,$2 scq001
前向查找
前向查找 (lookahead) 是用来限度后缀的。但凡以 (?=regex)
蕴含的子表达式在匹配过程中都会用来限度后面的表达式的匹配。例如 happy
happily
这两个单词,我想取得以 happ
结尾的副词,那么就能够应用 /happ(?=ily)/
来匹配, 就能够匹配到单词 happily
的happ
前缀。如果我想过滤所有以 happ
结尾的副词,那么也能够采纳 负前向查找 的正则 /happ(?!ily)/
,就会匹配到happy
单词的 happ
前缀。
后向查找
后向查找 (lookbehind) 是通过指定一个子表达式,而后从合乎这个子表达式的地位登程开始查找合乎规定的字串。举个简略的例子:apple
和 people
都蕴含 ple
这个后缀,那么如果我只想找到 apple
的 ple
,该怎么做呢?咱们能够通过限度 app 这个前缀,就能惟一确定 ple
这个单词了。
var str4 = 'apple people';
console.log(str4.replace(/(?<=ap)ple/,'-'))
// 失去后果 'ap- people'
// 阐明匹配到的是单词 apple 的 ple
(?<=regex)
的语法就是 后向查找 ,regex
指代的子表达式会作为限度项进行匹配,匹配到这个子表达式后,就会持续向后查找。另外一种限度匹配是利用(?<!regex)
语法,这里称为 负后向查找。与正前向查找不同的是,被指定的子表达式不能被匹配到。于是,在下面的例子中,如果想要查找 apple
的ple
也能够写成/(?<!peo)ple
总结
| 回溯查找 | 正则 |
| :—–:| :—-: |
| 援用 | 0,1,2 和 $0, $1, $2 |
| 非捕捉组 | (?:) |
| 前向查找 | (?=) |
| 前向负查找 | (?!) |
| 后向查找 | (?<=) |
| 后向负查找 | (?<!) |
逻辑解决
- 在正则外面,默认的正则规定都是 与的关系
- 在
[
和]
外部应用的^
示意非的关系 - 子表达式匹配的非关系就要用到后面介绍的前向负查找子表达式
(?!regex)
或后向负查找子表达式(?<!regex)
- 或关系,通常给子表达式进行归类应用。比方,我同时匹配 a,b 两种状况就能够应用
(a|b)
这样的子表达式。
解析结尾的题目
到这里正则差不多曾经温习了一遍,咱们当初再去看后面的三道题
题目一
/* 题目一 */
var str1 = '123456765464153513566'
// 宰割数字每三个以一个逗号划分(从后往前)
// 如 1234 -> 1,234
console.log(str1.replace(/(\d)(?=(\d{3})+$)/g,'$1,'))
// 123,456,765,464,153,513,566
解析:\d
示意单个数字,(?=(\d{3})+$)
是一个前向查找,\d{3})+$
示意匹配 3 位数字一次或者屡次并且以三位数字结尾。连在一起看就是,匹配一个数字,数字前面的数字位数是 3 的倍数,所以匹配到的数字是 3, 6, 5, 4, 3, 3
, 而后替换为$1,
,故3
替换为 3,
、6
替换为6,
….
题目二
/* 题目二 */
var str2 = "get-element-by-id"
// 将 - 的命名形式改为小驼峰
// 冀望后果 getElementById
console.log(str2.replace(/-\w/g, ($0) => {return $0.slice(1).toUpperCase()}))
解析:首先 /-\w/g
的意思是匹配所有后面是-
的单个字符
, 匹配的后果是-e, -b, -i
, 而后取其第二位(也就是将-
截取掉),再转换为大写
题目三
/* 题目三 */
var str3 = 'getElementById'
console.log(str3.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase())
// 写出运行后果
// 答案:get-element-by-id
解析: ([a-z])([A-Z])
的意思就是匹配两个字母,并且第一个是小写,第二个是大写,所以匹配到的后果是 tE, tB, yI
, 因为()
代表分组, 故 $1
代表的是匹配到的小写字母,$2
代表的是匹配到的大写字母
参考:正则表达式不要背