Regex 正则表达式
A regular expression (shortened as regex or regexp; also referred to as rational expression) is a sequence of characters that specifies a search pattern in text. Usually such patterns are used by string-searching algorithms for "find" or "find and replace" operations on strings, or for input validation. It is a technique developed in theoretical computer science and formal language theory.
正则表达式(英语:Regular Expression,常简写为regex、regexp或RE),又称正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。
Regular Expression的Regular一般被译为正则、正规或常规。此处的Regular即是规则、规律的意思,Regular Expression即“描述某种规则的表达式”之意。
正则表达式用来做什么:
- 判断一个句子中是否有Lizzy,
Hello everyone, my name is Li Zhiyan, you can call me Lizy.
- 判断一个字符串中是否有数字,
Twenty two is 22
- 判断一个字符串中有英文字母,
23n20230n;23+&*^&*
- 判断一个字符串中是否有John或者Jone,
Look! John's AirPods is becoming AirPod.
- 判断一个字符串是否是手机号码,
15195812506
- 判断一个字符串是否一Leon开头,
Leon is from China.
- 判断一个字符串是否是邮件地址,
[email protected]
- 使用非字符串分割字符串,
A, B, c, D, E;F|g
正则表达式表达了什么
- 断言(Assertions)
表示一个匹配在某些条件下发生。断言包含先行断言、后行断言和条件表达式。 - 字符类(Character Classes)
区分不同类型的字符,例如区分字母和数字。 - 组和范围(Groups and Ranges)
表示表达式字符的分组和范围。 - 量词(Quantifiers)
表示匹配的字符或表达式的数量。 - Unicode 属性转义(Unicode Property Escapes)
基于 unicode 字符属性区分字符。例如大写和小写字母、数学符号和标点。
在Python中,可以使用re模块和Pattern
来做正则:
import re
p = re.compile(pattern, flags=0)
re.search(pattern, string, flags=re.IGNORECASE)
re.match(pattern, string, flags=0)
re.split(pattern, string, maxsplit=0, flags=0)
re.findall(pattern, string, flags=0)
Pattern.search(string[, pos[, endpos]])
Pattern.match(string[, pos[, endpos]])
Pattern.split(string, maxsplit=0)
Pattern.findall(string[, pos[, endpos]])
在JavaScript中,可以使用var re = /pattern/flags;
import re
p1 = re.compile('Lizzy')
s = 'Hello everyone, my name is Li Zhiyan, you can call me Lizzy.'
p1.search(s)
# [\d] = [^\D]
p2 = re.compile('[0-9]') # \d = [0123456789]n
p2.search('Twenty two is 22')
p3 = re.compile('[a-zA-Z]') # \w (word) = [a-zA-Z0-9_]
p3.search('23n20230n;23+&*^&*')
<re.Match object; span=(2, 3), match='n'>
特殊符号
\d
: 匹配一个数字。等价于[0-9]。\D
: 匹配一个非数字字符。等价于。\w
: 匹配一个单字字符(字母、数字或者下划线)。等价于 [A-Za-z0-9_]。\W
: 匹配一个非单字字符。等价于 。\t
: 匹配一个水平制表符 (U+0009)。\v
: 匹配一个垂直制表符 (U+000B)。\f
: 匹配一个换页符 (U+000C)。\n
: 匹配一个换行符 (U+000A)。\r
: 匹配一个回车符 (U+000D)。\s
: 匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。\S
: 匹配一个非空白字符。等价于 。.
: 匹配除了换行符\n
以外的任意一个字符\u{hhhh}
or \u{hhhhh}
: 仅当设置了u标志时)匹配一个十六进制数表示的 Unicode 字符。
# 使用|作为选择
p4 = re.compile('John|Jone')
p4.search('Look! John\'s AirPods is becoming AirPod.')
# 匹配次数 {m,n}
p5 = re.compile('^1[0-9]{10}') # '1\d{10}'
# p5.search('15195812506')
p5.match('15195812506')
<re.Match object; span=(0, 11), match='15195812506'>
匹配次数
{m,n}
m次到n次(包含){m,}
至少m次{m}
m次?
0到1次+
至少1次*
任意次(0到∞)
指定匹配位置
^
: 匹配字符串的开头$
: 匹配字符串的末尾\b
: 匹配单词(word)的边界\B
: 匹配非单词边界
p6 = re.compile('^Leon')
s6 = 'Leon is from China.'
p6.search(s6)
# [email protected], \[email protected] @b.com [\w-] a@b._
p7 = re.compile('[\w\.\-\+]+@[\w-]+[\w\-\.]+([a-zA-Z0-9]+)$')
p7.match('[email protected]')
p8 = re.compile('[,;\|]')
p8.split('A, B, c, D, E;F|g')
['A', ' B', ' c', ' D', ' E', 'F', 'g']
总结
转义
如果你需要使用任何特殊字符的字面值(例如,搜索字符''),你必须通过在它前面放一个反斜杠来转义它。 例如,要搜索'a'后跟''后跟'b',你应该使用/a*b/- 反斜杠“转义”字符'*',使其成为文字而非特殊符号。
高级话题
使用插入语
任何正则表达式的插入语都会使这部分匹配的副字符串被记忆。一旦被记忆,这个副字符串就可以被调用于其它用途,如同使用括号的子字符串匹配之中所述。
通过标志进行高级搜索
一般而言,各种语言中实现的正则表达式有可选参数 (flags
) 允许全局和不分大小写搜索等。这些参数既可以单独使用也能以任意顺序一起使用, 并且被包含在正则表达式实例(模式)中。
Python中可以使用re.IGNORECASE
不分大小写搜索:
import re
p = re.compile(pattern, flags=0)
re.search(pattern, string, flags=re.IGNORECASE)
JavaScript则是:
标志 | 描述 |
---|
g | 全局搜索。 |
i | 不区分大小写搜索。 |
m | 多行搜索。 |
s | 允许 . 匹配换行符。 |
u | 使用unicode码的模式进行匹配。 |
y | 执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始。 |
let re = /^\w+\.\S+/gi;
用特殊字符检验输入
字符 | 含义 |
---|
(x) |
像下面的例子展示的那样,它会匹配 'x' 并且记住匹配项。其中括号被称为捕获括号。 模式`/(foo) (bar) \1 \2/`中的 '(foo)' 和 '(bar)' 匹配并记住字符串 "foo bar foo bar" 中前两个单词。模式中的`\1`和`\2`表示第一个和第二个被捕获括号匹配的子字符串,即 foo 和 bar,匹配了原字符串中的后两个单词。注意`\1`、`\2`、...、`\n` 是用在正则表达式的匹配环节,详情可以参阅后文的 `\n` 条目。而在正则表达式的替换环节,则要使用像 `$1`、`$2`、...、`$n` 这样的语法,例如,`'bar foo'.replace(/(...) (...)/, '$2 $1')`。$& 表示整个用于匹配的原字符串。 |
(?:x) |
匹配 'x' 但是不记住匹配项。这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。 看看这个例子 `/(?:foo){1,2}/`。如果表达式是 `/foo{1,2}/,{1,2}` 将只应用于 'foo' 的最后一个字符 'o'。如果使用非捕获括号,则 `{1,2}` 会应用于整个 'foo' 单词。 |
x(?=y) |
匹配'x'仅仅当'x'后面跟着'y'.这种叫做先行断言。 例如,`/Jack(?=Sprat)/`会匹配到'Jack'仅当它后面跟着'Sprat'。`/Jack(?=Sprat|Frost)/`匹配‘Jack’仅当它后面跟着'Sprat'或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配结果的一部分。 |
(?<=y)x |
匹配'x'仅当'x'前面是'y'.这种叫做后行断言。 例如,`/(?<=Jack)Sprat/`会匹配到' Sprat '仅仅当它前面是' Jack '。`/(?<=Jack|Tom)Sprat/`匹配‘ Sprat ’仅仅当它前面是'Jack'或者是‘Tom’。但是‘Jack’和‘Tom’都不是匹配结果的一部分。 |
x(?!y) |
仅仅当'x'后面不跟着'y'时匹配'x',这被称为正向否定查找。 例如,仅仅当这个数字后面没有跟小数点的时候,`/\d+(?!\.)/` 匹配一个数字。正则表达式`/\d+(?!\.)/.exec("3.141")`匹配‘141’而不是‘3.141’ |
Reference / 参考
- Wiki:正则表达式
- JavaScript:正则表达式
- Python:Regular expression operations
- Java:Pattern
- .NET:Regular Expression Language - Quick Reference