正则表达式

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
 

© jianxiaoBai 2021 - 2022