# 正则表达式

  • 参考: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方法无效,匹配总是从字符串的第一个字符开始
  • 返回第一个满足条件的匹配结果在整个字符串中的位置。如果没有任何匹配,则返回-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' 前面是匹配部分,后面是断言部分,替换的只有匹配部分