断言匹配的不是文本,而是位置。
常见的断言有三种:单词边界,行起始/结束位置,环视。

单词边界

在文本处理中,经常会进行单词替换,比如将一段文本中的row替换成line。
替换前:The row we are looking for is row 10.
替换后:The line we are looking for is line 10.
不过,这样的替换也可能造成错误
替换前:Tomorrow I will wear a brown shirt in row 10.
替换后:Tomorline I will wear a blinen shirt in line 10.
为了解决这个问题,必须要有办法确定是单词row,而不是字符串row,为此,正则提供了单词边界,记为\b。它匹配的是位置(单词边界),而不是字符。\b能够匹配的是在这样的位置:一边是单词字符,另一边不是单词字符。单词字符是指\w(0-9a-zA-Z_)能匹配的字符。

  1. 'Tomorrow I will wear a brown shirt in row 10'.replace(/\brow\b/,'line')
  2. // Tomorrow I will wear a brown shirt in line 10

与\b对应的是\B,指非单词边界。因此[\b\B]也能够表达任意字符。

行起始/结束位置

  • ^默认情况下这只能匹配整个字符串的开始位置,如果指定多行模式,则可以匹配字符串内部文本行的开始位置
  • $默认情况下这只能匹配整个字符串的结束位置,如果指定多行模式,则可以匹配字符串内部文本行的结束位置
  • 即便字符串末尾有换行符,$也只能匹配字符串的结束位置,而不会匹配末尾换行符之前的位置。所以进行验证的时候,可以放心的在表达式里使用^和$ ```javascript /^1/.test(‘1\n2’) // true /^2/.test(‘1\n2’) // false /^2/m.test(‘1\n2’) // true

/2$/.test(‘1\n2’) // true /1$/.test(‘1\n2’) // false /1$/m.test(‘1\n2’) // true

  1. <a name="1911e"></a>
  2. # 环视
  3. 单词边界匹配的是这样的位置:一边是单词字符,一边不是单词字符。从另一个角度来看,它能进行这样的判断:在某个位置向左/向右看,必须出现或不能出现某类字符。正则表达式提供了环视,在它旁边的文本需要满足某种条件,而且本身并不匹配任何字符。
  4. | 名字 | 记法 | 判断方向 |
  5. | --- | --- | --- |
  6. | 肯定顺序环视(positive lookahead) | (?=regexp) | 向右 |
  7. | 否定顺序环视(negative lookahead) | (?!regexp) | 向右 |
  8. | 肯定逆序环视(positive lookbehind ES2017+) | (?<=regexp) | 向左 |
  9. | 否定逆序环视(negative lookbehind ES2017+) | (?<!regexp) | 向左 |
  10. 例如,对于字符串'12345',4种环视能匹配的位置<br />![WechatIMG4099.jpeg](https://cdn.nlark.com/yuque/0/2020/jpeg/176641/1601782725985-5ca76517-5d0f-4bfe-b1ab-1b202046d23a.jpeg#height=375&id=i7o6F&margin=%5Bobject%20Object%5D&name=WechatIMG4099.jpeg&originHeight=375&originWidth=636&originalType=binary&size=21008&status=done&style=none&width=636)<br />例如,格式化金额显示1234567->1,234,567
  11. ```javascript
  12. // 我们需要把逗号添加到这样的位置:左侧是数字字符,右侧的数字字符串的长度是3的倍数,这里的数字字符串要是整个数字字符串,而不能是它的某一个子串,也就是要一直匹配到右侧不能再有数字字符的位置。
  13. '1234567'.replace(/(?<=\d)(?=(\d{3})+(?!\d))/g,',') // 1,234,567

观察这个例子可以发现,出现了环视的 嵌套 和 并列 两种组合结构