正则表达式
date
Feb 19, 2022
slug
regexp
status
Published
tags
学习笔记
summary
正则表达式引擎将始终返回最左边的
默认匹配,即使另一个或更好的匹配
可以找到。
type
Post
Regex 引擎在内部是如何工作的
- 两种正则表达式引擎:
- 文本导向引擎 =
A
- 正则表达式导向引擎 =
B
- 几乎所有现代正则表达式风格都基于
B
,因为功能强大
A
遍历主题字符串,在前进到字符串中的下一个字符之前尝试正则表达式的 所有排列。文本导向的引擎永远 不会回溯。
一个
B
遍历 regexp
,尝试将 regexp
中的下一个标记与下一个字符匹配。如果找到匹配项,引擎将通过
regexp
和主题字符串前进。如果无法匹配,引擎将 回溯 到
regexp
和主题字符串中的先前位置,在该位置它可以尝试通过正则表达式的不同路径。总是返回最左边的匹配
理解这一点 非常重要:
正则表达式引擎总是返回最左边的匹配,即使稍后可以找到“更好”的匹配。
将正则表达式应用于字符串时,引擎从字符串的第一个字符开始。
它在第一个字符处尝试正则表达式的所有可能排列。
只有在尝试了所有可能性并发现失败时,引擎才会继续处理文本中的第二个字符。
同样,它以完全相同的顺序尝试所有可能的正则表达式排列。
结果是正则表达式引擎返回 最左边 的匹配。
进阶语法
命名捕获: ?<name>
'<div>hello 123<\/div>'.replace(/(?<text>\d+)/, '<em>$<text></em>')
非捕获模式: ?:
var str = 'scq000'.
str.replace(/(scq00)(?:0)/, '$1,$2')
// 返回scq00,$2
// 由于使用了非捕获正则,所以第二个引用没有值,这里直接替换为$2
前向查找: ?=
、?!
// 前向查找:?=
'happy happily'.match(/happ(?=ily)/)
// 匹配到了 happ 开头且 ily 结尾的 happily
// 负前向查找:?!
'happy happily'.match(/happ(?!ily)/)
// 匹配到了开头 happ 且非 ily 结尾的 happy
后向查找: ?<=
、?<!
// 后向查找
'apple people'.match(/(?<=ap)ple/)
// 匹配到了 ple 结尾且前面是 ap 的 apple
// 非后向查找
'apple people'.match(/(?<!ap)ple/)
// 匹配到了 ple 结尾且前面不是 ap 的 people
例子
// 排除特定后缀 /(?<!js|css)$/
// 不包含特定字符 = ^((?!test).)*$
// 千分位
'12345678'.replace(/(\d)(?=(\d{3})+$)/g, '$1,')
/*
(\d) 代表匹配中的回溯引用
(?=(\d{3})+$)
使用 ?= 前向匹配,后面的规则匹配成功,回溯引用字符串才标识
\d{3} 3 个数字
+$ 也就代表当前匹配的数字 后面的数字长度需要时 3 的倍数,才匹配成功
*/
// 支持小数点
// (?:$|\.), ?: 非捕获模式,结尾要么是上面的那样严格的 3的数字的倍数结尾,要么有小数点结尾
'10000000000.23'.replace(/(\d)(?=(\d{3})+(?:$|\.))/g, '$1,')
// \B 匹配非单词边界,前向匹配和替换
/*
'12345678.20'.replace(/\B/g, ',')
'1,2,3,4,5,6,7,8.2,0'
*/
'12345678.20'.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
/*
流程:
每个非单词边界,也就是 '1,2,3,4,5,6,7,8.2,0' 中 每个逗号的位置开始匹配
1. 1 234 567 8.20 // 不成立
2. 12 345 678.20 // 成立
以此类推,匹配每个字符处尝试正则表达式的所有可能排列。
*/
在线测试工具:https://regex101.com/
正则闯关网站:https://regexone.com/problem
正则可视化:https://regexper.com/
官网正则引擎匹配流程详解:https://www.regular-expressions.info/backref.html