# 正则表达式
- 参考:https://mp.weixin.qq.com/s/0CV6jIufuiwMwmPgRv0Zzw
- https://wangdoc.com/javascript/stdlib/regexp.html
# 常用
- \b 单词边界, . 任意字符, * 任意个字符,+ 至少一个字符, () 分组$1 $2 $3
- \d 数字, {3} 量词, []表示或者,^ 开头, $ 结尾
#
- 正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
- javaScript通过内置对象RegExp支持正则表达式
# 实例化
- 两种方法实例化RegExp对象,等价,都新建了一个内容为bis的正则表达式对象
- 字面量,以斜杠表示开始和结束,var reg=/\bis\b/g;
- 构造函数 var reg = new RegExp('\bis\b', g)
# 实例属性
- RegExp.prototype.ignoreCase,是否设置了i修饰符,默认false
- RegExp.prototype.global,是否设置了g修饰符,默认false
- RegExp.prototype.multiline,是否设置了m修饰符,默认false
- RegExp.prototype.flags:返回一个字符串,包含了已经设置的所有修饰符
- RegExp.prototype.lastIndex,返回一个整数,表示下一次开始搜索的位置。该属性可读写,但是只在进行连续搜索时有意义(非全局搜索时不生效)
- RegExp.prototype.source, 返回正则表达式的字符串形式(不包括反斜杠)
- 以上属性均为只读,不可修改
# 实例方法
# RegExp.prototype.test(str)
- 表示当前模式是否能匹配参数字符串,匹配返回true,否则返回false
# RegExp.prototype.exec(str)
- 用来返回匹配结果
- 若没有匹配的文本返回null,若有返回结果数组:
- 调用非全局搜索时执行exec()时,结果数组如下:
- 第一个元素是与正则表达式相匹配的文本
- 第二个元素是匹配文本中的第一个分组
- 第三,第四以此类推
- index 模式匹配成功的开始位置(从0开始计数)
- input 存放被检索的字符串string
# 字符串对象与正则相关的4个方法
# String.prototype.match()
- 字符串的match方法与正则对象的exec方法非常类似,
- 匹配成功返回一个数组,匹配失败返回null
- 但正则表达式带有g修饰符时,则该方法与正则对象的exec方法行为不同,会一次性返回所有匹配成功的结果
- 且设置正则表达式的lastIndex属性,对match方法无效,匹配总是从字符串的第一个字符开始
# String.prototype.search()
- 返回第一个满足条件的匹配结果在整个字符串中的位置。如果没有任何匹配,则返回-1。不执行全局匹配,总是从字符串的开始进行检索
# String.prototype.replace()
- 替换匹配的值,它接受两个参数,第一个是正则表达式,表示搜索模式,第二个是替换的内容。
- 正则表达式如果不加g修饰符,就替换第一个匹配成功的值,否则替换所有匹配成功的值
//消除字符串首尾两端的空格
var str = ' #id div.class ';
str.replace(/^\s+|\s+$/g, '') //// "#id div.class"
- replace方法的第二个参数可以使用美元符号$,用来指代所替换的内容。
- $&:匹配的子字符串。
- $`:匹配结果前面的文本。
- $':匹配结果后面的文本。
- $n:匹配成功的第n组内容,n是从1开始的自然数。
- $$:指代美元符号$。
'hello world'.replace(/(\w+)\s(\w+)/, '$2 $1')
// "world hello"
'abc'.replace('b', '[$`-$&-$\']')
// "a[a-b-c]c"
- 作为replace方法第二个参数的替换函数,可以接受多个参数。其中,第一个参数是捕捉到的内容,第二个参数是捕捉到的组匹配(有多少个组匹配,就有多少个对应的参数)。此外,最后还可以添加两个参数,倒数第二个参数是捕捉到的内容在整个字符串中的位置(比如从第五个位置开始),最后一个参数是原字符串。下面是一个网页模板替换的例子
var prices = {
'p1': '$1.99',
'p2': '$9.99',
'p3': '$5.00'
};
var template = '<span id="p1"></span>'
+ '<span id="p2"></span>'
+ '<span id="p3"></span>';
template.replace(
/(<span id=")(.*?)(">)(<\/span>)/g,
function(match, $1, $2, $3, $4){
return $1 + $2 + $3 + prices[$2] + $4;
}
);
// "<span id="p1">$1.99</span><span id="p2">$9.99</span><span id="p3">$5.00</span>"
# String.prototype.split()
# 修饰符
- g,global全文搜索,若不添加,搜索到第一个匹配停止
- i,ignore case,忽略大小写,默认大小写敏感
- m, 多行搜索
# 元字符
- 正则表达式由两种基本字符类型组成
- 字面量字符
- 元字符
- 元字符是正则表达式中由特殊含义的非字母字符
- *, +,?, $, ^, ., |, , (), [], {}
- 一般情况下,正则表达式一个字符对应字符串一个字符
# 点字符(.)
- 点字符(.)匹配除回车(\r)、换行(\n) 、行分隔符(\u2028)和段分隔符(\u2029)以外的所有字符,但一个点只匹配一个字符
# 边界字符
- ^开始,$结束,\b单词边界, \B非单词边界
# 选择符(|)
- 竖线符号(|)在正则表达式中表示“或关系”
- 选择符会包括它前后的多个字符,比如/ab|cd/指的是匹配ab或者cd,而不是指匹配b或者c。如果想修改这个行为,可以使用圆括号
/a( |\t)b/.test('a\tb') // true
//a和b之间有一个空格或者一个制表符
# 转义符
- 正则表达式中,需要反斜杠转义的,一共有12个字符:^、.、[、$、(、)、|、*、+、?、{和\。
- 需要特别注意的是,如果使用RegExp方法生成正则对象,转义需要使用两个斜杠,因为字符串内部会先转义一次
(new RegExp('1\+1')).test('1+1')
// false
(new RegExp('1\\+1')).test('1+1')
// true
# 字符类
- 字符类(class)表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内[]
# 脱字符(^)
- 如果方括号内的第一个字符是[^],则表示除了字符类之中的字符,其他字符都可以匹配。比如,[^xyz]表示除了x、y、z之外都可以匹配
- 如果方括号内没有其他字符,即只有[^],就表示匹配一切字符,其中包括换行符。相比之下,点号作为元字符(.)是不包括换行符的
- 注意,脱字符只有在字符类的第一个位置才有特殊含义,否则就是字面含义
# 连字符(-)
- 某些情况下,对于连续序列的字符,连字符(-)用来提供简写形式,表示字符的连续范围。- [abc]可以写成[a-c],
- [0123456789]可以写成[0-9],
- 同理[A-Z]表示26个大写字母
- 当连字号(dash)不出现在方括号之中,就不具备简写的作用,只代表字面的含义,所以不匹配字符b。只有当连字号用在方括号之中,才表示连续的字符序列
- 字符类[1-31],不代表1到31,只代表1到3
# 预定义类
正则表达式提供预定义类匹配常见的字符类
. 任意字符,除回车和换行之外的所有的字符,[^\r\n]
\d 数字字符,[0-9]
\D 非数字字符,[^0-9]
\s 空白字符, \S 非空白字符
\w 匹配任意的字母、数字和下划线,[a-zA-Z0-9_]
\W 除所有字母、数字和下划线以外的字符, [^a-zA-Z_0-9]
正则表达式遇到换行符(\n)就会停止匹配
var html = "<b>Hello</b>\n<i>world!</i>";
/.*/.exec(html)[0]
// "<b>Hello</b>"
/[\S\s]*/.exec(html)[0]
// "<b>Hello</b>\n<i>world!</i>"
//点字符(.)不匹配换行符,而[\S\s]指代一切字符
# 量词
- ?出现0次或1次, {0,1}
- + 出现1次或多次(至少一次){1,}
- * 出现0次或多次(任意次){0,}
- {n} 恰好重复n次
- {n,m} 出现n到m次
- {n,} 至少出现n次
- 量词默认匹配紧挨着的字符,若要匹配一个单词,可使用分组
# 贪婪模式与非贪婪模式
正则表达式默认会尽可能多的匹配,即贪婪模式
而非贪婪模式则是尽可能少的匹配,即一旦匹配成功便不再尝试
在量词后加?即开启非贪婪模式
‘123456789’.match(/\d{3,6}?/g) => ['123','456','789']
非贪婪模式的加号(+?),匹配一个就停止
非贪婪模式的星号(*?),匹配0个就停止
非贪婪模式的问号(??),匹配0个就停止
# 分组
- 使用括号表示分组匹配,使量词作用于分组,而非紧挨着的字符
- 正则表达式的exec方法,配合循环,才能读到每一轮匹配的组捕获
var str = 'abcabc';
var reg = /(.)b(.)/g;
while (true) {
var result = reg.exec(str);
if (!result) break;
console.log(result);
}
// ["abc", "a", "c"]
// ["abc", "a", "c"]
- 正则表达式内部,还可以用\n引用括号匹配的内容,n是从1开始的自然数,表示对应顺序的括号
/(.)b(.)\1b\2/.test('abcabc') //true
/y(..)(.)\2\1/.test('yabccab') //true
/y((..)\2)/1/.test('yabababab')
- 括号还可以嵌套,\1指向外层括号,\2指向内层括号
# 反向引用
- 用$1到$n,来代表我们捕获的分组,也叫分组捕获
# 忽略分组
- 如果不希望捕获某些分组,只要在分组内加上?:即可
- (?:byron).(ok)这样分组byron就被忽略了
# 前瞻
- 正则表达式从文本头部向文本尾部开始解析,文本尾部方向,称为“前”
- 前瞻就是正则表达式在匹配到规则的时候,向前检查是否符合断言
- 后顾/后瞻,方向相反,js不支持后瞻
- 符合和不符合特定断言称为肯定/正向匹配和否定/负向匹配
- 正向前瞻, exp(?=assert)
- 负向前瞻, exp(?!assert)
- 正向后顾, exp(?<=assert) js不支持后顾
- 负向后顾, exp(?<!assert) js不支持后顾
- ‘a23’.replace(/\w(?=\d)/g, 'X') => 'X23' 前面是匹配部分,后面是断言部分,替换的只有匹配部分