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即“描述某种规则的表达式”之意。

正则表达式用来做什么:

  1. 判断一个句子中是否有Lizzy, Hello everyone, my name is Li Zhiyan, you can call me Lizy.
  2. 判断一个字符串中是否有数字, Twenty two is 22
  3. 判断一个字符串中有英文字母, 23n20230n;23+&*^&*
  4. 判断一个字符串中是否有John或者Jone, Look! John's AirPods is becoming AirPod.
  5. 判断一个字符串是否是手机号码, 15195812506
  6. 判断一个字符串是否一Leon开头, Leon is from China.
  7. 判断一个字符串是否是邮件地址, [email protected]
  8. 使用非字符串分割字符串,A, B, c, D, E;F|g

正则表达式表达了什么

  1. 断言(Assertions)
    表示一个匹配在某些条件下发生。断言包含先行断言、后行断言和条件表达式。
  2. 字符类(Character Classes)
    区分不同类型的字符,例如区分字母和数字。
  3. 组和范围(Groups and Ranges)
    表示表达式字符的分组和范围。
  4. 量词(Quantifiers)
    表示匹配的字符或表达式的数量。
  5. 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'>


特殊符号

  1. \d: 匹配一个数字。等价于[0-9]。
  2. \D: 匹配一个非数字字符。等价于1
  3. \w: 匹配一个单字字符(字母、数字或者下划线)。等价于 [A-Za-z0-9_]。
  4. \W: 匹配一个非单字字符。等价于 2
  5. \t: 匹配一个水平制表符 (U+0009)。
  6. \v: 匹配一个垂直制表符 (U+000B)。
  7. \f: 匹配一个换页符 (U+000C)。
  8. \n: 匹配一个换行符 (U+000A)。
  9. \r: 匹配一个回车符 (U+000D)。
  10. \s: 匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。
  11. \S: 匹配一个非空白字符。等价于 3
  12. .: 匹配除了换行符\n以外的任意一个字符
  13. \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'>


匹配次数

  1. {m,n} m次到n次(包含)
  2. {m,} 至少m次
  3. {m} m次
  4. ? 0到1次
  5. + 至少1次
  6. * 任意次(0到∞)

指定匹配位置

  1. ^: 匹配字符串的开头
  2. $: 匹配字符串的末尾
  3. \b: 匹配单词(word)的边界
  4. \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 / 参考

  1. Wiki:正则表达式
  2. JavaScript:正则表达式
  3. Python:Regular expression operations
  4. Java:Pattern
  5. .NET:Regular Expression Language - Quick Reference

  1. 0-9
  2. A-Za-z0-9_
  3. \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff

标签: none

评论已关闭