正则表达式 Checklist
本文最后更新于 2023年7月28日 上午
正则表达式一直都是开发人员的必备技能,有人甚至提出在学习开发前先要熟练掌握正则表达式,可见其重要性。
这次利用实现 GA 数据分析的机会,整理了一个 Checklist 方便查阅(APP 上传的事件数据由于没有统一规定,内容千奇百怪,利用正则抽取其中关注的部分)。
根据 Free Code Camp 的教程来写的,原示例基于 JS 语言.
JS 中的正则
常用方法
- 基本 => 正则表达式的创建:JS 中正则模式使用
//
来定义, 因此不需要使用双引号。 - 方法 => test: 使用 Test 方法
.test()
用于检查字符串是否匹配模式,如果是返回true
,regEx.test(someString)
。 - 方法 =>
match
: match 方法用于检测并返回匹配的字符串,比如"Hello, World!".match(/Hello/);
返回["Hello"]
。 - 注意 => match 和 test 的对象: test 是正则对象的方法, match 是字符串对象的方法.
常量匹配
常量匹配 => 大小写敏感:直接搜索常量,且默认匹配大小写,即 const testRegex = /Kevin/
.
正则标志
- 标志 =>
i
: 忽略大小写匹配, 使用i
标志, 如:/someString/i
- 标志 =>
g
: 整串搜索匹配, 使用g
标志(没有使用该标志则仅返回第一个匹配的子串)1
2
3let testStr = "Repeat, Repeat, Repeat";
let ourRegex = /Repeat/g;
testStr.match(ourRegex); // 返回 ["Repeat", "Repeat", "Repeat"]
单字符匹配
- 单字符匹配 =>
.
: 使用点通配符匹配一个任意字符
/hu./
能匹配hug
,huh
,huu
等 - 单字符匹配 => 字符集(character class)
[]
: 匹配集合中的某个字符, 比如/b[aiu]g/
能够匹配bag
,big
,bug
- 单字符匹配 => 字符集范围: 使用
-
指定字符集范围, 匹配范围内的任意一个字符(包含上下界的字符), 比如/[a-e]at/
能够匹配aat
,bat
,cat
,dat
,eat
- 单字符匹配 => 匹配范围内的字母或数字: 可以像这样定义
[a-z0-9]
, 比如/[a-z0-9]/ig;
用在Jenny8675309
上可以匹配所有的单个字符, 如果使用 match 方法则返回的是该字符串的所有字符. - 单字符匹配 => 排除: 使用
^
可定义排除字符集, 比如/aeiou/ig
匹配单个非元音字符(但这样写的话所有.
,!
这些非字母字符也会被匹配到, 甚至是空格, 因只排除了元音字母)1
2
3let quoteSample = "3 blind mice.";
let myRegex = /[^aeiou0-9]/ig; // 匹配排除元音和数字的其他所有字符, 且整串搜索忽略大小写
let result = quoteSample.match(myRegex); // 返回所有 9 个匹配的字符: 空格 b l n d 空格 m c . - 单字符匹配 =>
\w
: 匹配任意字母数字或下划线, 相当于[A-Za-z0-9_]
的简化写法/\w/g
用在are you
上返回["a", "r", "e", "y", "o", "u"]
- 单字符匹配 =>
\W
: 匹配任意非字母数字和下划线, 相当于[^A-Za-z0-9_]
/\W/
用在42%
上返回["%"]
- 单字符匹配 =>
\d
: 匹配数字, 相当于[0-9]
- 单字符匹配 =>
\D
: 匹配非数字, 相当于[^0-9]
- 单字符匹配 =>
\s
: 匹配空白符, 包括空格, 换行, tab, form feed 等, 相当于[\r\n\t\f\v]
- 单字符匹配 =>
\S
: 匹配非空白符, 相当于[^\r\t\f\n\v]
多字符匹配
- 多字符匹配 =>
+
: 匹配出现一次或多次, 比如/a+/g
, 用在abc
上返回["a"]
, 用在aaabc
上返回["aaa"]
, 用在abab
上返回["a", "a"]
- 多字符匹配 =>
*
: 匹配出现 0 次或多次, 比如/go*/
, 用在"gooooooooal!"
上返回["goooooooo"]
, 用在gut feeling
上返回["g"]
(u匹配 0 次或多次), 用在over the moon
上返回 null - 多字符匹配 => 贪心匹配和懒匹配:
- 利用
*
可以进行贪心匹配(最长匹配),/t[a-z]*i/
用在"titanic"
返回["titani"]
- 利用
?
可以进行懒匹配(最短匹配),/t[a-z]*?i/
用在"titanic"
返回["ti"]
- 利用
?
还可以表达”可以匹配, 也可以不匹配”, 比如/favou?rite/
可以匹配favorite
和favourite
- 利用
- 多字符匹配 =>
^
: 匹配字符串开头, 比如/^Ricky/
- 用在
"Ricky is first and can be found."
返回["Ricky"]
- 用在
"You can't find Ricky now."
返回null
- 用在
- 多字符匹配 =>
$
: 匹配字符串结尾, 比如/story$/
- 用在
"This is a never ending story"
返回["story"]
- 用在
"Sometimes a story will have to end"
返回null
- 用在
- 多字符匹配 =>
\w+
: 匹配任意一个或多个字母数字或下划线, 比如/\w+/
- 用在
"42"
返回["42"]
- 用在
"important_var"
返回["important_var"]
- 用在
"are you"
返回["are", "you"]
- 用在
- 多字符匹配 =>
\W+
: 匹配连续多个非字母数字下划线字符 - 多字符匹配 =>
\d+
: 匹配连续多个数字 - 多字符匹配 =>
\D+
: 匹配连续多个非数字字符
特殊操作
或操作符
|
: 比如/^[a-z][a-z]+\d*$|^[a-z]\d\d+$/i
中就是或操作符, 操作符两侧优先按左侧匹配, 未匹配则再看右侧出现频次限定: 比如
/a{3,5}h/
可以匹配aaaah
, 但不能匹配aah
{2,}
(仅下限){3,5}
(上下限){3}
(固定次数)
正则表达式中允许出现括号
()
以包括多个模式, 比如/^[a-z]([0-9]{2,}|[a-z]+\d*)$/i;
中限定末尾匹配的相关表达.Lookahead: 前瞻, 即仅判断是否满足指定正则, 但不进行后续匹配, 当想在一个字符串中使用多种正则查找时非常有用.
- positive:
(?=...)
其中...
是具体正则, positive 会根据指定的正则确认匹配是否存在, 但不匹配该正则. - negative:
(?!...)
其中...
是具体正则, negative 会根据指定的正则确认匹配是否不存在, 但不匹配该正则.
例如给一个字符串
"qu"
:- 如果使用
/q(?=u)/
进行匹配则返回q
(匹配到存在的位置, 但不进行后面的匹配) - 如果使用
/q(?!t)/
, 也仍会返回q
(匹配到不存在的位置, 但不进行后面的匹配)
- positive:
使用
|
配合()
可以匹配一组正则: 比如/P(engu|umpk)in/
可以匹配Penguin
和Pumpkin
Reuse Patterns Using Capture Groups: 使用括号包含的
(\w+) \1
, 即利用 capture group, 通过编号在后面进行引用.Use Capture Groups to Search and Replace: 使用 replace 方法, 利用 capture group 捕捉到的字符串进行替换, 或者是将匹配到的内容替换为新的字符串.
Remove Whitespace from Start and End: 这个练习中识别开头和结尾的连续空白, 并用 replace 替换为空, 即可去掉所有空白.
Python
compile
方法创建正则表达式对象匹配 import 语句:
1
2
3
4
5
6
7
8[
('#import ', '<', 'Foundation/', 'Foundation.h', '>'),
('#import ', '<', 'sqlitemanager/', 'FMDatabase.h', '>'),
('#import ', '<', 'sqlitemanager/', 'FMResultSet.h', '>'),
('#import ', '<', 'sqlitemanager/', 'FMDatabaseAdditions.h', '>'),
('#import ', '<', 'sqlitemanager/', 'FMDatabaseQueue.h', '>'),
('#import ', '<', 'sqlitemanager/', 'FMDatabasePool.h', '>')
]可以使用这个:
1
2
3import_regex = r'^(#import\s)(<)(\w+\/)*(\w+\.h)(>)(\s*)$'
match_import_regex = re.compile(import_regex, re.IGNORECASE | re.MULTILINE)
result = match_import_regex.sub(r'\1"\4"\6', content)抽取关注的内容, 如:
1
'["ver": "1.2.34.56", "id": " xxxxx-xxxxx-xxxxx-xxxxx-xxxx-- --2021-10-08 02:16:05 +0000,\\n sysV:11.6.0 Arm64"]'
1
2
3
4ver_regex = r'("ver":\s*)"((\d+\.)*\d+)"'
id_regex = r'([A-Z0-9]{5}-){4}([A-Z0-9]{4})'
event_date_regex = r'(\d{4}(-\d{2}){2}) ((\d{2}:*)*) \+\d{4}'
sys_info_regex = r'sysV:(\d+.*?)\s(\w+),'