regex 总结

regex 可以说时候最最基础的码农必备生存技能

cheatsheet

Character classes

symbol meaning
. any char except for line breakers
\w \d \s word, digit, whitespace
\W \D \S NOT word, digit, whitespace
[abc] any of a, b, c
[^abc] not a, b, c
[a-g] character between a & g

Anchors

symbol meaning
^abc$ start / end of the string
\b word boundary
\B NOT word boundary

Escaped characters

symbol meaning
. * \ escaped special characters
\t \n \r tab, linefeed, carriage return
\u00A9 unicode escaped ©

Groups and Look-around

symbol meaning
(abc) capture group
\1 back-reference to group #1
(?:abc) non-capturing group
(?=abc) positive lookahead
(?!abc) negative lookahead

Quantifiers and Alternations

symbol meaning
a* a+ a? 0 or more, 1 or more, 0 or 1
a{5} a{2,} exactly five, two or more
a{1,3} between one & three
a+? a{2,}? match as few as possible (lazy match)
ab|cd match ab or cd

Substitution

symbol meaning
$& match
$1 capture group
$` before match
$’ after match
$$ escaped $
\n escaped chars

Look ahead

"<a href="http://google.com">Google</a>"

positive lookahead:

/google(?=<)/gi => 'Look ahead and match those who are followed with a `<`'

$& => 'Google'

negative lookahead:

/google(?!<)/gi => 'Look ahead and match those who are NOT followed with a `<`'

$& => 'google'

Backtracking and Greediness

这两个概念是 regex 中最核心的概念。重点在于在写通配符号的时候一定要注意这个坑 否则很可能会导致非常严重的性能问题(尤其是服务器端)

Backtracking

regex /\b([01]+b|\d+|[\da-f]+h)\b/ 的 matching 图解如下

backtracking1

假设现在match ‘123’ 字符串 那么 regex 会经过如下步骤

  1. 找到 boundary 并记录之
  2. 试图匹配 branch1 ([01]+b)
  3. 看到数字 3 匹配失败 返回 boundary —> backtracking!!!
  4. 试图匹配 branch2 (\d+)
  5. 成功 匹配 branch2 输出结果 (注意这里 branch3 不会被执行)

通配符 (+ * ? {}) 的 backtracking 问题

/^.*x/

假设 matching 字符串 ‘abcxe’

  1. .* 会将这个字符串匹配掉
  2. 发现需要一个 ‘x’ 在句尾 (坑爹啊!!!)
  3. 回拨一个字符(匹配 ‘abcx’) 并记录它 —> backtracking!!!
  4. .* 又一次会将整个 ‘abcx’ 都匹配掉
  5. 回拨一个字符(匹配 ‘abc’) 并记录它 —> backtracking
  6. 终于匹配到

Greedy

正是由于 backstracking 算法的的存在 通配符 ‘* + ? {}’ 被形容为 ‘greedy’

这会造成一个非常直观的现象

some testing string @hanslee with some sentence at the back.

/(@.+)\b/ig

$1 => @hanslee with some sentence at the back

/(@.+?)\b/ig

$1 => @hanslee

可以看到在第一种 matching 中由于 backtracking, 通配符 + 会将 @hanslee后面的所有文字都包括进来

这是由于 backtracking 一直是发生在 通配符 + 将整个字符串都匹配之后一个字符一个字符向前查找的

而在通配符后面加上一个 ‘?’ 则是告诉 regex 引擎,不要让通配符 greedy 地去吃掉整个字符串。在匹配的过程中 ‘+’ 通配符应当遵循最少适配原则

所以加上了 ? 的通配符终于表现得和地球人比较类似了。

参考: