正则表达式
参考:
- https://www.jb51.net/tools/zhengze.html
- https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/regular-expression-language-quick-reference
Js 中正则表达式的定义
- 构造函数方式
var reg = new RegExp('a','gi')
var str = '012a'
console.log(str.search(reg))
- 第一个参数是正则的内容,第二个参数是修饰符;
- 修饰符通常有三种,i,g,m;
- i (IgnoreCase)表示的含义是忽略大小写进行匹配;
- g ()表示全局匹配即匹配到第一个之后不停止继续匹配;
- m (Multiline)表示多行匹配即遇到换行后不停止匹配继续直到被匹配字符串结束。
- 字面量方式
var reg = /a/gi
Js 中能使用正则表达式的方法有哪些?
String
- replace
该方法用来将字符串中的某些子串替换为需要的内容,接受两个参数,第一个参数可以为正则或者子字符串,表示匹配需要被替换的内容,第二个参数为被替换的新的子字符串。如果声明为全局匹配则会替换所有结果,否则只替换第一个匹配到的结果。
代码语言:javascript复制'abcabc'.replace(/a/,'A')
'abcabc'.replace(/a/g,'A')
'abcabc'.replace(/a/gi,'S')
- search
用来查找第一次匹配的子字符串的位置,如果找到就返回一个 number 类型的 index 值,否则返回-1,它返回的只是第一次匹配的位置。
代码语言:javascript复制console.log('hello world!'.search(/l/g))
- split
该方法主要用来将一个字符串拆分成一个数组,它接受一个正则或者子字符(串)作为参数,返回一个数组
代码语言:javascript复制let str = 'a|b|c'
console.log(str.split('|'))
let str2 = 'a|b c**d'
let arr = str2.split(/||s |**/)
console.log(arr)
- match
该方法接受一个正则作为参数,用来匹配一个字符串,它的输出结果在不是全局匹配的情况下和 exec 方法的结果一致即一个数组并带有额外的属性,如果采用全局匹配,则不返回任何和其被匹配字符串相关的信息,只返回匹配的结果。
代码语言:javascript复制var str = "hello javascript!"
var reg1 = /a/
console.log(str.match(reg1))
var reg2 = /a/g
console.log(str.match(reg2))
// 小括号问题
var str2 = 'abcabc'
var reg3 = /(b)c/
console.log(str2.match(reg3))
var reg4 = /(b)c/g
console.log(str2.match(reg4))
RegExp
- test
该方法用来测试某个字符串是否与正则匹配,匹配就返回 true,否则返回 false。
代码语言:javascript复制var reg = /abc/
var str = 'abc'
console.log(reg.test(str))
- exec
该方法属于一个比较复杂的方法,它接受一个字符串,返回的是一个数组,数组中第 0 个元素是匹配的子字符串,第二个元素是正则中的第一个子分组匹配的结果(如果有子分组,即正则中存在用圆括号括起来的分组),第三个是正则中第二个子分组匹配的结果(如果有第二个子分组)...以此类推,如果没有正则子分组,那么该数组长度仅仅为 1,就是匹配到的那个子字符串。同时,返回的这个数组同时还是一个对象,它拥有两个属性,分别为 index 表示当前匹配到的子字符串所处的位置,input 属性表示被匹配的原始字符串。最后,该方法中的正则对象如果不是全局匹配,即没有 g 修饰符,则每次调用只会从字符串开头处匹配第一个结果,且每次调用结果都是一样的。只有指定为全局匹配,才能够按照从左往右依次去匹配,每次调用匹配一个结果,正则对象的 lastIndex 属性前进到本次匹配的末尾位置,下回再调用的时候,会从 lastIndex 处开始匹配而不是从头匹配
代码语言:javascript复制var reg = /abc/g
var str = 'abcdefgabcefg'
var arr = reg.exec(str)
while(arr){
console.log(arr)
arr = reg.exec(str)
}
- compile
该方法的作用是能够对正则表达式进行编译,被编译过的正则在使用的时候效率会更高,适合于对一个正则多次调用的情况下,如果对一个正则只使用一两次,那么该方法没有特别显著的效应。
接受的参数也是一个正则。
代码语言:javascript复制var reg=/[abc]/gi;
console.log(reg.test('a'));
reg=/[cde]/gi;
console.log(reg.test('a'));
reg.compile(reg);
console.log(reg.test('a'));
被编译的正则和没有编译的正则在测试结果上没有任何区别,只是多次调用的效率上会更高一些。
正则工具
- 在线工具 regular expressions regulex
- 图表工具 regexper
- window 环境
RegexBuddy 使用手册
- mac 环境
正则入门
正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义
元字符
常用元字符
元字符 | 描述 |
---|---|
. | 匹配除换行符(“n”和"r")以外的任意字符 |
w | 匹配字母或数字或下划线或汉字 |
s | 匹配任意的空白符 |
d | 匹配数字 |
b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,“\n”匹配n。“n”匹配换行符。序列“\”匹配“”而“(”则匹配“(”。即相当于多种编程语言中都有的“转义字符”的概念。 |
限定元字符
元字符 | 描述 |
---|---|
* | 匹配任意次 |
| 匹配至少一次或更多次 |
? | 匹配零次或一次 |
{n} | 匹配 n 次 |
{n,} | 匹配 n 次或更多次 |
{n,m} | 匹配 n 次到 m 次 |
字符集
元字符 | 描述 |
---|---|
a-z | 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符 |
1-9 | 数字范围,匹配指定范围内的任意数字。例如,"1-9"可以匹配 1 到 9 范围内的任意数字 |
x | 匹配 x |
分支分组元字符
元字符 | 描述 |
---|---|
() | 将( 和 ) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存 9 个),它们可以用 1 到9 的符号来引用 |
| | 将两个匹配条件进行逻辑“或”(Or)运算。例如正则表达式(him | her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。 |
反义
元字符 | 描述 |
---|---|
W | 匹配任意不是字母,数字,下划线,汉字的字符 |
S | 匹配任意不是空白符的字符 |
D | 匹配任意非数字的字符 |
B | 匹配不是单词开头或结束的位置 |
[^x] | 配除了 x 以外的任意字符 |
[^aeiou] | 匹配除了 aeiou 这几个字母以外的任意字符 |
后向引用
元字符 | 描述 |
---|---|
(exp) | 匹配 exp,并捕获文本到自动命名的组里 |
(?<name>exp) | 匹配 exp,并捕获文本到名称为 name 的组里,也可以写成(?'name'exp) |
(?:exp) | 匹配 exp,不捕获匹配的文本,也不给此分组分配组号 |
零宽断言
元字符 | 描述 |
---|---|
(?=exp) | 匹配 exp 前面的位置 |
(?<=exp) | 匹配 exp 后面的位置 |
(?!exp) | 匹配后面跟的不是 exp 的位置 |
(?<!exp) | 匹配前面不是 exp 的位置 |
负向零宽断言
注释
(?#comment)
贪婪与懒惰
元字符 | 描述 |
---|---|
*? | 重复任意次,但尽可能少重复 |
? | 重复 1 次或更多次,但尽可能少重复 |
?? | 重复 0 次或 1 次,但尽可能少重复 |
{n,m}? | 重复 n 到 m 次,但尽可能少重复 |
{n,}? | 重复 n 次以上,但尽可能少重复 |
平衡组/递归匹配
有时我们需要匹配像( 100 * ( 50 15 ) )这样的可嵌套的层次性结构,这时简单地使用(. )则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如( 5 / ( 3 2 ) ) ),那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢?
为了避免(和(把你的大脑彻底搞糊涂,我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把 xx <aa aa> yy 这样的字符串里,最长的配对的尖括号内的内容捕获出来?
这里需要用到以下的语法构造:
- (?'group') 把捕获的内容命名为 group,并压入堆栈(Stack)
- (?'-group') 从堆栈上弹出最后压入堆栈的名为 group 的捕获内容,如果堆栈本来为空,则本分组的匹配失败
- (?(group)yes|no) 如果堆栈上存在以名为 group 的捕获内容的话,继续匹配 yes 部分的表达式,否则继续匹配 no 部分
- (?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败