最近在做web开发,前台js和后台python经常会使用正则表达式,来处理一些字符的问题,比如查询,替换,匹配等场景,本文将汇总在开发中正则表达式使用的方法,并对js和python在实现同样功能时,两者的方法区别等做一下整理。
javascript
先说明一下js中正则表达式的基本使用,首先是构造一个正则表达式,有两种方法,分别如下:
- 使用正则表达式字面量,包含在斜杠之间的模式组成,例如如下:
// 格式: /pattern/flags 其中flags包括: i / g / m
const regex_1 = /[a-z]+/;
const regex_2 = /[a-z]+/gi;
- 使用 RegExp 对象来构造,例如如下:
// 格式: new RegExp(pattern [, flags])
let regex_1 = new RegExp("[a-z]+\\d+");
let regex_2 = new RegExp(/[a-z]+\d+/, "gi");
let regex_3 = new RegExp("[a-z]+\\d+", "gi")
可以看出使用斜杆方法是不能传入变量的,但是通过RegExp中使用字符串的方式,可以传入变量,来丰富使用场景。例如如下用法
let regex = new RegExp("^\\" + site_url + "event_list\/[0-9]+\/alert_detail\/[0-9]+\/", 'i');
下面摘取一些特殊符号的使用说明如下,具体点击查阅.
符号 | 说明 |
---|---|
. |
小数点符号匹配除 换行符 之外的任何单个字符 |
\w |
匹配一个单字字符(字母、数字、下划线),等价于 [a-zA-Z0-9_]
|
\W |
匹配一个非单字字符,等价与 [^a-zA-Z0-9_]
|
\s |
匹配一个空白字符,包括:空格、制表符、换页符和换行符 |
\b |
匹配一个词的边界,匹配词的边界并不包含在匹配的内容中 |
(x) |
匹配 x 并且记住匹配项,括号称为捕获括号 |
x(?=y) |
正向肯定查找,匹配 x 仅仅当 x 后面跟着 y |
x(?!y) |
正向否定查找,匹配 x 仅仅当 x 后面不跟着 y |
(?:y)+ |
表示匹配y一次或多次,但是不记住匹配项 y,与 (x)+ 的区别就在于是否有记住匹配项 |
x|y |
匹配 x 或者 y |
注意: 使用 (x)
捕获括号时,在正则表达式中,还可以使用 \1
\2
等来表示子表达式的匹配项,例如如下例子:
let regex = new RegExp(/([\w]+)\s+([\w]+)\s+\1\s+\2/, 'g');
let str = "hello world hello world ...";
regex.exec(str);
// 结果为: ["hello world hello world", "hello", "world", index: 0, input: "hello world hello world ...", groups: undefined]
regex.exec(str);
// 结果为: null
javascript方法汇总比较
下面先汇总得出各个方法比较和使用场景。
方法 | 用法 | 返回值 | 使用场景 | 注意事项 |
---|---|---|---|---|
match |
str.match(regexp) |
Array / null | 获取第一次匹配的子串,比如想获取子表达式匹配的文本 | |
exec |
regexp.exec(str) |
Array / null | 循环获取匹配的子串,也能够获取子表达式匹配的文本 | |
search |
str.search(regexp) |
Number / -1 | 获取第一次匹配到的子串的下标位置 | 此处的regexp可以有多种定义方式 |
test |
regexp.test(str) |
true / false | 判断某个正则表达式在字符串中是否有匹配的子串 | |
replace |
str.replace(regexp/substr, replacement) |
newstr | 替换字符串中某些条件的子字符串 | 不会改变原字符串str内容 |
提供几个javascript的正则表达式使用网站,可视化正则表达式,在线解析正则匹配结果分析,在线解析正则匹配结果。
match
match
方法将检索字符串str,找到一个或多个与regexp匹配的文本(如果flags中有g
那么就会全局匹配)
如果没有g
,那么match方法就只能在str中执行一次匹配,如果没有找到则返回null
,否则返回一个Array,其中存放了与他找到的匹配文本有关的信息,例如如下结果,其中 res[0]
表示存放的是匹配文本,res[1]
表示存放的是与正则表达式regex
里子表达式([a-z]+)
匹配的文本;res['index']
表示存放的是匹配文本的其实字符在str
中的位置;res['input']
表示存放的是str
的引用。
let str = "I'm a chinese.";
let regex = new RegExp(/\s+([a-z]+)\s+/);
let res = str.match(regex);
// res结果为: [" a ", "a", index: 3, input: "I'm a chinese.", groups: undefined]
如果有g
,那么match将执行全局检索,找到str
中的所有匹配子字符串。如果没有找到则返回null;否则返回一个Array,存放的是所有匹配子串。例如如下例子:
let str = "I'm a chinese.";
let regex = new RegExp(/\s+([a-z]+)\s+/, 'g');
let res = str.match(regex);
// res结果为: [" a "]
所以在全局检索模式下,match既不提供与子表达式匹配的文本的信息,也不返回每个匹配子串的位置,如果需要这些信息,可以使用 exec
方法获取。
exec
exec
方法用于检索字符串中的正则表达式的匹配,返回一个数组,用于存放匹配的结果;如果没有找到匹配,返回null。
当使用非全局正则表达式时,exec
和 match
的返回结果是一样的,只是调用方式不同而已。
当使用全局正则表达式时,exec
会使 lastIndex 在正则表达式匹配到字符串的最后一个字符的下一个位置,这样可以通过反复调用 exec
方法来遍历字符串的所有匹配文本。
当 exec
再也找不到匹配的文本时,返回null,并把 lastIndex 属性重置0,所以如果反复循环调用 exec
的话,那么得到的结果也会是一个循环的数值,结果格式可能为:
['m', ...] ['a', ...] ['chinese', ...] null ['m', ...] ['a', ...] ['chinese', ...] null ...
另外,无论正则表达式是否是全局,调用 exec
方法,都会把完整的细节添加到它的返回数组中。例如如下例子:
let str = "I'm a chinese";
let regex = new RegExp(/[a-z]+/, 'g');
regex.exec(str)
// 结果为: ["m", index: 2, input: "I'm a chinese", groups: undefined]
regex.exec(str)
// 结果为: ["a", index: 4, input: "I'm a chinese", groups: undefined]
regex.exec(str)
// 结果为: ["chinese", index: 6, input: "I'm a chinese", groups: undefined]
regex.exec(str)
// 结果为: null
regex.exec(str)
// 结果为: ["m", index: 2, input: "I'm a chinese", groups: undefined]
search
查询字符串中满足条件(字符串或正则表达式)的子字符串,返回值为该子字符串的起始位置,如果没有查找到,则返回 -1
。
search
的传参可以是字符串,也可以是斜杆写法的正则表达式,search会将字符串转化为斜杆写法,例如如下三种写法是等价的:
// 写法一
let str = "I'm a chinese.";
let regex = new RegExp(/\s+([a-z]+)\s+/, 'i');
let res = str.search(regex);
// 写法二
let str = "I'm a chinese.";
let res = str.search(/\s+([a-z]+)\s+/i);
// 写法三
let str = "I'm a chinese.";
let res = str.search("\\s+([a-z]+)\\s+", "i");
// 以上结果都为: 3
test
test
方法用于检测一个字符串是否匹配某个模式,如果字符串中含有匹配的文本,则返回true,否则返回false。
例如如下例子:
let str = "I'm a chinese.";
let regex = new RegExp(/\s+([a-z]+)\s+/, 'i');
let res = regex.test(str);
// res结果为: true
replace
replace
用于替换字符的场景,用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。返回值为替换之后的字符串结果。
例如如下例子:
// 语法: str.replace(regexp/substr, replacement)
// 其中 regexp/substr 表示此处既可以是正则表达式也可以是字符串,如果是substr那么不会转化为RegExp对象,而是作为普通的字符串
// replacement 既可以是普通字符串,也可以是替换函数
let str = "I'm a chinese.";
let res = str.replace(/\b([\w']+)\b/g, "[$1]");
// res结果为: "[I'm] [a] [chinese]."
// replacment使用函数
let res_f = str.replace(/\b([\w']+)\s+\b/g, item =>
"[" + item.substring(0,1).toUpperCase() + item.substring(1) + "]");
// res_f结果为: "I'm A Chinese."
这里再举一个通过单词分隔位置来对数字进行英文逗号分隔的效果
let num = 1234567890;
num.toString().replace(/(?=(?!\b)(?:\d{3})+$)/g, ',');
// 当然也可以使用 num.toLocaleString()
当replacement为函数的时候,参数 item
表示的是与regexp匹配的子串,和字符串表示中的 $&
内容一样。
当replacement为字符串时,字符 $
具有特定的含义,具体如下表:
字符 | 替换文本 |
---|---|
$1 / $2 ... $99
|
表示与regexp中的第1到第99个子表达式匹配的文本 |
$& |
表示与regexp匹配的子串(注意不是子表达式) |
$` | 表示位于匹配子串左侧的文本 |
$' |
表示位于匹配子串右侧的文本 |
$$ |
表示字符 $ |