发布于 2026-01-05 20 阅读
0

JavaScript 正则表达式速查表和示例

JavaScript 正则表达式速查表和示例

这篇博文概述了 JavaScript 支持的正则表达式语法和特性。示例已在 Chrome/Chromium 控制台(版本 81 及以上)上测试通过,并包含其他浏览器和平台所不具备的功能。除非另有说明,否则默认使用 ASCII 字符集。本文节选自我的JavaScript 正则表达式书籍。

定义正则表达式的元素

笔记 描述
MDN:正则表达式 MDN 文档中关于 JavaScript 正则表达式的内容
/pat/ 正则表达式对象
const pet = /dog/ 将正则表达式保存到变量中以便重复使用、提高清晰度等等。
/pat/.test(s) 检查给定的模式是否出现在输入字符串中的任何位置
退货truefalse
i 标记用于忽略字母匹配时的大小写。
g 标记以匹配所有出现情况
new RegExp('pat', 'i') 从字符串构建正则表达式
第二个参数指定标志。
使用反引号字符串${}进行插值
source 用于将正则表达式对象转换为字符串的属性
有助于将一个正则表达式插入到另一个正则表达式中
flags 获取正则表达式对象标志的属性
s.replace(/pat/, 'repl') 搜索和替换方法
s.search(/pat/) 给出比赛的起始位置或-1
s.split(/pat/) 根据正则表达式分割字符串
描述
^ 将匹配范围限制在字符串的开头
$ 将匹配范围限制在字符串末尾。
m 标记与行的开头/结尾^$锚点匹配
\r, \n,\u2028\u2029是行分隔符
使用 DOS 风格文件\r\n可能需要特别注意
\b 将匹配范围限制在单词的开头/结尾。
单词字符:字母、数字、下划线
\B \b凡是不匹配的地方都匹配

^上表中的 `\` 、`\ $` 和`\`\元字符\,因为这些字符具有特殊含义。给字符添加前缀可以移除其特殊含义,使其按字面意思匹配。例如,` \`\^将匹配一个^字符,而不是作为锚点。

特征 描述
pat1|pat2|pat3 多个正则表达式组合成 OR 条件
每个备选方案都可以有独立的锚点。
(pat) 群体模式,也称捕获群体
a(b|c)d 与……相同abd|acd
(?:pat) 非捕获组
(?<name>pat) 命名捕获组
. 匹配除行分隔符以外的任何字符
[] 角色类别,与众多角色中的一个相匹配
贪婪量词 描述
? 比赛01时间
* 比赛0或更多次
+ 比赛1或更多次
{m,n} 比赛m时间n
{m,} 至少匹配m
{n} 精确匹配n次数
pat1.*pat2 pat1介于两者之间的任意数量的字符pat2
pat1.*pat2|pat2.*pat1 两者匹配pat1pat2顺序不限

这里的“贪婪”指的是上述量词会尽可能多地匹配符合正则表达式整体规则的内容。?在贪婪量词后添加 `a` 会将其变为非贪婪量词,即尽可能少地匹配内容。量词可以应用于字面字符、字符组、反向引用和字符类。

角色职业 描述
[ae;o] 匹配以下任意一个字符
[3-7] 字符范围3从到7
[^=b2] 否定集,匹配除“或”=或“b或”之外的其他项2
[a-z-] -应该是首尾呼应,或者使用转义\符进行字面匹配。
[+^] ^不应是首字符或使用转义字符\
[\]\\] ]应该\使用转义\
\w 类似于[A-Za-z0-9_]匹配单词字符
\d [0-9]与匹配数字字符类似
\s 类似于[ \t\n\r\f\v]匹配空白字符
使用\W、、\D\S分别表示它们的反义词
u 启用 Unicode 匹配的标志
\p{} Unicode字符集
\P{} 否定 Unicode 字符集
详情请参阅MDN:Unicode 属性转义。
\u{} 使用代码点指定Unicode字符
环顾四周 描述
环顾四周 允许创建自定义的肯定/否定断言
零宽度锚点,且不属于匹配部分
(?!pat) 负面前瞻断言
(?<!pat) 负面后视断言
(?=pat) 积极展望断言
(?<=pat) 正面回溯断言
允许可变长度的后向断言。
(?!pat1)(?=pat2) 可以按任意顺序并排指定多个断言。
它们标记匹配的位置,而无需消耗字符。
((?!pat).)* 对正则表达式模式取反
匹配部分 描述
m = s.match(/pat/) 假设g未使用标志且正则表达式匹配成功,
返回一个包含匹配部分和 3 个属性的数组
index该属性给出比赛的起始位置。
input属性给出输入字符串s
groups该属性提供命名捕获组的字典
m[0] 对于上述情况,给出整个匹配部分
m[N] 第N个捕获组的匹配部分
s.match(/pat/g) 仅返回匹配的部分,不返回任何属性。
s.matchAll(/pat/g) 返回一个包含详细信息的迭代器
每个匹配部分及其属性
反向引用 给出第N个捕获组的匹配部分
在替换部分使用$1,,,$2等等$3
$&提供整个匹配部分
$`给出匹配部分之前的字符串
$'返回匹配部分之后的字符串
在正则表达式定义中使用\1逗号、\2逗号、逗号等\3
$$ 直接插入$替换部分
$0N 与此相同$N,允许分离反向引用和其他数字。
\N\xhh 允许在正则表达式定义中分离反向引用和数字。
(?<name>pat) 命名捕获组
用于\k<name>正则表达式定义中的反向引用
用于$<name>替换部分的反向引用

正则表达式示例

  • test方法
> let sentence = 'This is a sample string'

> /is/.test(sentence)
< true
> /xyz/.test(sentence)
< false

> if (/ring/.test(sentence)) {
      console.log('mission success')
  }
< mission success
Enter fullscreen mode Exit fullscreen mode
  • new RegExp()构造函数
> new RegExp('dog', 'i')
< /dog/i

> new RegExp('123\\tabc')
< /123\tabc/

> let greeting = 'hi'
> new RegExp(`${greeting.toUpperCase()} there`)
< /HI there/
Enter fullscreen mode Exit fullscreen mode
  • 绳索和锚
// string anchors
> /^cat/.test('cater')
< true
> ['surrender', 'newer', 'door'].filter(w => /er$/.test(w))
< ["surrender", "newer"]

// use 'm' flag to change string anchors to line anchors
> /^par$/m.test('spare\npar\nera\ndare')
< true

// escape metacharacters to match them literally
> /b\^2/.test('a^2 + b^2 - C*3')
< true
Enter fullscreen mode Exit fullscreen mode
  • replace方法和词语边界
> let items = 'catapults\nconcatenate\ncat'
> console.log(items.replace(/^/gm, '* '))
< * catapults
  * concatenate
  * cat

> let sample = 'par spar apparent spare part'
// replace 'par' only at the start of word
> sample.replace(/\bpar/g, 'X')
< "X spar apparent spare Xt"
// replace 'par' at the end of word but not whole word 'par'
> sample.replace(/\Bpar\b/g, 'X')
< "par sX apparent spare part"
Enter fullscreen mode Exit fullscreen mode
  • 交替和分组
// replace either 'cat' at start of string or 'cat' at end of word
> 'catapults concatenate cat scat'.replace(/^cat|cat\b/g, 'X')
< "Xapults concatenate X sX"

// same as: /\bpark\b|\bpart\b/g
> 'park parked part party'.replace(/\bpar(k|t)\b/g, 'X')
< "X parked X party"
Enter fullscreen mode Exit fullscreen mode
  • MDN:正则表达式文档提供了escapeRegExp一个函数,可用于自动转义元字符。
    • 另请参阅XRegExp实用程序,它提供了XRegExp.escapeXRegExp.union方法。union 方法具有允许混合使用字符串和正则表达式字面量的附加功能,并且还可以处理反向引用的重新编号。
> function escapeRegExp(string) {
    return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&')
  }

> function unionRegExp(arr) {
    return arr.map(w => escapeRegExp(w)).join('|')
  }

> new RegExp(unionRegExp(['c^t', 'dog$', 'f|x']), 'g')
< /c\^t|dog\$|f\|x/g
Enter fullscreen mode Exit fullscreen mode
  • 点元字符和量词
// matches character '2', any character and then character '3'
> '42\t33'.replace(/2.3/, '8')
< "483"
// 's' flag will allow line separators to be matched as well
> 'Hi there\nHave a Nice Day'.replace(/the.*ice/s, 'X')
< "Hi X Day"

// same as: /part|parrot|parent/g
> 'par part parrot parent'.replace(/par(en|ro)?t/g, 'X')
< "par X X X"

> ['abc', 'ac', 'abbc', 'xabbbcz'].filter(w => /ab{1,4}c/.test(w))
< ["abc", "abbc", "xabbbcz"]
Enter fullscreen mode Exit fullscreen mode
  • match方法
// entire matched portion
> 'abc ac adc abbbc'.match(/a(.*)d(.*a)/)[0]
< "abc ac adc a"
// matched portion of 2nd capture group
> 'abc ac adc abbbc'.match(/a(.*)d(.*a)/)[2]
< "c a"
// get location of matching portion
> 'cat and dog'.match(/dog/).index
< 8

// get all matching portions with 'g' flag
// no properties or group portions
> 'par spar apparent spare part'.match(/\bs?par[et]\b/g)
< ["spare", "part"]

// useful for debugging purposes as well before using 'replace'
> 'that is quite a fabricated tale'.match(/t.*?a/g)
< ["tha", "t is quite a", "ted ta"]
Enter fullscreen mode Exit fullscreen mode
  • matchAll方法
// same as: match(/ab*c/g)
> Array.from('abc ac adc abbbc'.matchAll(/ab*c/g), m => m[0])
< ["abc", "ac", "abbbc"]
// get index for each match
> Array.from('abc ac adc abbbc'.matchAll(/ab*c/g), m => m.index)
< [0, 4, 11]

// get only capture group portions as an array for each match
> let s = 'xx:yyy x: x:yy :y'
> Array.from(s.matchAll(/(x*):(y*)/g), m => m.slice(1))
< (4) [Array(2), Array(2), Array(2), Array(2)]
  0: (2) ["xx", "yyy"]
  1: (2) ["x", ""]
  2: (2) ["x", "yy"]
  3: (2) ["", "y"]
  length: 4
  __proto__: Array(0)
Enter fullscreen mode Exit fullscreen mode
  • 替换部分中的函数/字典
> function titleCase(m, g1, g2) {
        return g1.toUpperCase() + g2.toLowerCase()
  }
> 'aBc ac ADC aBbBC'.replace(/(a)(.*?c)/ig, titleCase)
< "Abc Ac Adc Abbbc"

> '1 42 317'.replace(/\d+/g, m => m*2)
< "2 84 634"

> let swap = { 'cat': 'tiger', 'tiger': 'cat' }
> 'cat tiger dog tiger cat'.replace(/cat|tiger/g, k => swap[k])
< "tiger cat dog cat tiger"
Enter fullscreen mode Exit fullscreen mode
  • split方法
// split based on one or more digit characters
> 'Sample123string42with777numbers'.split(/\d+/)
< ["Sample", "string", "with", "numbers"]
// include the portion that caused the split as well
> 'Sample123string42with777numbers'.split(/(\d+)/)
< ["Sample", "123", "string", "42", "with", "777", "numbers"]

// split based on digit or whitespace characters
> '**1\f2\n3star\t7 77\r**'.split(/[\d\s]+/)
< ["**", "star", "**"]

// use non-capturing group if capturing is not needed
> '123handed42handy777handful500'.split(/hand(?:y|ful)?/)
< ["123", "ed42", "777", "500"]
Enter fullscreen mode Exit fullscreen mode
  • 与普通/非捕获/命名捕获组进行反向引用
// remove consecutive duplicate words separated by space
// use \W+ instead of space to cover cases like 'a;a<-;a'
> 'aa a a a 42 f_1 f_1 f_13.14'.replace(/\b(\w+)( \1)+\b/g, '$1')
< "aa a 42 f_1 f_13.14"

// add something around the entire matched portion
> '52 apples and 31 mangoes'.replace(/\d+/g, '($&)')
< "(52) apples and (31) mangoes"

// duplicate first field and add it as last field
> 'fork,42,nice,3.14'.replace(/,.+/, '$&,$`')
< "fork,42,nice,3.14,fork"

// use non-capturing groups when backreferencing isn't needed
> '1,2,3,4,5,6,7'.replace(/^((?:[^,]+,){3})([^,]+)/, '$1($2)')
< "1,2,3,(4),5,6,7"

// named capture groups, same as: replace(/(\w+),(\w+)/g, '$2,$1')
> 'good,bad 42,24'.replace(/(?<fw>\w+),(?<sw>\w+)/g, '$<sw>,$<fw>')
< "bad,good 24,42"
Enter fullscreen mode Exit fullscreen mode
  • 环视示例
// change 'foo' only if it is not followed by a digit character
// note that end of string satisfies the given assertion
// note that 'foofoo' has two matches
> 'hey food! foo42 foot5 foofoo'.replace(/foo(?!\d)/g, 'baz')
< "hey bazd! foo42 bazt5 bazbaz"

// change whole word only if it is not preceded by : or --
> ':cart apple --rest ;tea'.replace(/(?<!:|--)\b\w+/g, 'X')
< ":cart X --rest ;X"

// extract digits only if it is preceded by - and followed by , or ;
> '42 foo-5, baz3; x83, y-20; f12'.match(/(?<=-)\d+(?=[;,])/g)
< ["5", "20"]

// words containing all vowels in any order
> let words = ['sequoia', 'questionable', 'exhibit', 'equation']
> words.filter(w => /(?=.*a)(?=.*e)(?=.*i)(?=.*o).*u/.test(w))
< ["sequoia", "questionable", "equation"]

// replace only 3rd occurrence of 'cat'
> 'cat scatter cater scat'.replace(/(?<=(cat.*?){2})cat/, 'X')
< "cat scatter Xer scat"

// match if 'do' is not there between 'at' and 'par'
> /at((?!do).)*par/.test('fox,cat,dog,parrot')
< false
Enter fullscreen mode Exit fullscreen mode

调试和可视化工具

随着正则表达式变得越来越复杂,一旦出现问题,调试起来就会非常困难。从头开始逐步构建正则表达式,并用输入字符串进行测试,对于解决问题大有裨益。为了辅助这个过程,您可以使用各种在线正则表达式工具

regex101是一个很受欢迎的正则表达式测试网站。首先,你需要选择 JavaScript 版本。然后,你可以添加正则表达式、输入字符串、选择标志以及可选的替换字符串。匹配的部分会被高亮显示,并在单独的窗格中提供解释。此外,它还提供快速参考和其他功能,例如分享、代码生成器、测试等等。

正则表达式101示例

另一个有用的工具是jex:regulex,它可以将你的正则表达式转换为铁路图,从而提供可视化的帮助来理解模式。

正则表达式示例

JavaScript 正则表达式书籍

访问我的代码仓库learn_js_regexp,了解我撰写的关于 JavaScript 正则表达式的书籍详情。这本电子书使用了大量示例,从基础概念讲解,并包含练习题来检验你的理解。本文中的速查表和示例均基于本书内容。

文章来源:https://dev.to/learnbyexample/javascript-regular-expressions-cheatsheet-and-examples-4jg7