- JS引擎 v.s. 正则表达式引擎
它们的转义符都是\
经过JS引擎会进行一次转义
经过正则表达式会进行一次转义 - 在一次转义中
\\\\\
的转义过程:
第一个 \ (转义符) 会“吃掉”第二个 \,结果是得到一个字面量的 \。
第三个 \ (转义符) 会“吃掉”第四个 \,结果是得到另一个字面量的 \。
第五个剩下
最终结果: 字符串中会包含3个字面量的反斜杠。 \d{4}*
这种表达是错误的,因为*
表示d{4}
重复0~N次,前面必须放一个表示新字符的表达式。如.
- 练习
这个dataPattern能匹配什么内容?
const str=`
<script>
(function(){
const Patternstr ="\/\\\\\d{4}\/\\\\\d{2}\/\\\\\d{2}\/\.*";
const dataPattern = new RegExp(Patternstr);
})()
</script>`
html = html.replace(/<\/body>/, str + '</body>');
解析:
- 模板字串 (backtick ``)中
\
也是转义符,Patternstr变为/\\\d{4}/\\\d{2}/\\\d{2}/.*";
- 经过 JavaScript 字串解析器处理,Patternstr变为
/\\d{4}/\\d{2}/\\d{2}/.*
- 经过正则表达式引擎解析,Patternstr变为
/\d{4}/\d{2}/\d{2}/.*
- 根据正则表达式,可知形如
/2025/05/28/.....
这类字符串可以被成功匹配
- 补充
在 JavaScript 中,.test() 和 .match() 都是 RegExp (正则表达式) 对象或字符串对象的方法,用于执行正则表达式匹配操作。它们的主要区别在于返回值的类型和目的。
当你只需要判断字符串中是否存在某个模式时,使用 .test()。 它的性能通常比 .match() 更好,因为它一旦找到匹配就会立即返回 true,不需要构建并返回完整的匹配数组。
当你需要获取匹配到的具体内容、匹配位置或所有匹配项时,使用 .match()。
正则表达式
语法 | 含义 | 示例 | | |
---|
* | 通配符 | find ./ -name *.txt/ 查找./目录下的任何Txt文件 | | |
. | 匹配任意一个字符(除换行回车) | a.c 可匹配 abc | .* 任意个任意字符 可以是0个 | .+ 至少一个任意字符 |
^ | 匹配开头 | ^abc 匹配以 abc 开头 | 在[^]里表示非 | |
$ | 匹配结尾 | abc$ 匹配以 abc 结尾 | | |
[] | 匹配字符集中的任一字符 | [abc] 匹配 a b c | [a-zA-Z0-9] | |
[^] | 非字符集 | [^abc] 不匹配 a b c | | |
\d | 匹配数字 [0-9] | \d\d 匹配两位数字 | \D 非0-9 | |
\w | 匹配单词字符 \[a-zA-Z0-9\_] (字母、数字、下划线) | \w+ 匹配单词 | | |
\s | 匹配空白符(空格、tab) | \s+ 匹配空格 | \S 非空白符 | |
+ | 前面的重复一次或多次 | a+ 匹配 a aa aaa | | |
* | 前面的重复0次或多次 | a* 匹配空串、a 等 | | |
? | 前面重复0或1次 | a? 匹配有或没有 a | | |
{n,m} | 重复n到m次 | \d{2,4} 两到四位数字 | {n} n次,{n,} 至少出现n次 | |
| | 或者 | a | b 匹配a 或b | | |
\ | 转义字符 | \\ 得到\ | | |
() | 分组 | (ab)+ 匹配重复的 ab | | |
模式 | 匹配结果 |
---|
<title>.*</title> | <title>你好</title><title>世界</title> (吃到不能吃为止) |
<title>.*?</title> | <title>你好</title> (吃一口就停) |
场景 | 正则表达式 |
---|
手机号 | 1[3-9]\d{9} |
邮箱 | [a-zA-Z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,} |
URL | https?:\/\/[^\s]+ |
IP地址 | \b\d{1,3}(\.\d{1,3}){3}\b |
身份证 | \d{17}[\dXx] |
密码强度 | (?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,} |
正向前瞻:(?=...)
/\d+(?=元)/.exec("价格为30元")
\d? 0个或1个数字
\d+ 1~n个数字
\d{3} 3个数字
\d{3,5} 3~5个数字
\d* 0~n个数字
\b 单词边界
\B 非单词边界
例如
\bis\b 表示句子中的this is a pen;里的单词is会被识别 而不会识别this里的is
(abc) abc里是一个分组group 便于提取出来
abc{2} 只是c循环两次
(abc){2}
分组在引用时分别为$1 $2 $3
忽略某分组 直接在分组内加上?:
(?:by).(ok) =>by被忽略
/ /gi 全局匹配并且忽略大小写
例1 匹配http://头的jpg文件地址
http:\/\/.+\.jpg
注意:斜杠和点需要转义
要求把末尾是.jpg的http://的头去掉:/http:(\/\/.\.jpg)/
例2 日期替换
^(/d{4})[/-](\d{2})[/-](\d{2})$ 使格式类似2006/02/03和2006-02-03提取出来,
其中每一个组分别为$1 $2 $3
replace with $2-$3-$1 可得 02-03-2006
js里的正则表达式:
方法1
str.replace(/reg/,'a')
方法2
var reg =new RegExp('\\bis\\b') 注意这个\要转移
var reg =new RegExp('\\bis\\b','g') 全局匹配
正则表达式可视化
https://regexper.com/
JS & Python
JS 方法 | 作用 | 常用于 | 返回值 |
---|
test() | 测试字符串是否匹配 | 布尔判断 | true 或 false |
exec() | 执行匹配,返回匹配结果对象 | 捕获分组 | RegExpExecArray 或 null |
String.prototype.match() | 匹配正则,返回匹配内容 | 一次或全部匹配 | 匹配数组或 null |
String.prototype.matchAll() | 匹配所有结果(支持分组) | 多次匹配+分组 | 迭代器 |
String.prototype.search() | 查找第一次匹配的位置 | 搜索位置 | 匹配索引或 -1 |
String.prototype.replace() | 替换匹配的内容 | 替换 | 替换后的字符串 |
String.prototype.replaceAll() | 替换所有匹配(ES2021) | 替换所有 | 替换后的字符串 |
String.prototype.split() | 拆分字符串 | 分隔 | 拆分后的数组 |
const regex1 = /abc/;
const regex2 = new RegExp('abc');
regex.test(str)
"abc123".replace(/\d+/, "***")
"apple,banana".split(/,/)
"Abc".match(/abc/i)
"1 2 3".match(/\d+/g)
Python 方法 | 功能说明 | 返回值类型 |
---|
re.match() | 从字符串开头匹配 | Match 或 None |
re.search() | 扫描字符串,返回第一个匹配项 | Match 或 None |
re.findall() | 找出所有匹配项(无分组则字符串) | list[str] 或 list[tuple] |
re.finditer() | 找出所有匹配项,返回迭代器 | 可遍历的 Match 对象 |
re.sub() | 替换匹配内容 | 替换后的新字符串 |
re.subn() | 替换并返回替换次数 | (新字符串, 替换数) |
re.split() | 按正则拆分字符串 | 列表 |
re.compile() | 编译正则表达式成 Pattern 对象 | Pattern 实例 |
pattern.fullmatch() | 整个字符串是否完整匹配 | Match 或 None |
import re
regex = re.compile(r'abc')
regex.search(str)
re.sub(r"\d+", "***", "abc123")
re.split(r"[,\s]+", "a, b, c")
re.search(r"abc", "ABC", re.I)
re.findall(r"\d+", "1 2 3")