Regular Expressions Regex

一、基本语法

1. 基础匹配

  • . 全部匹配
  • [abc] 字符集
  • [^abc] 否定字符集
  • [a-z] 字母范围:我们需要将起始字母和结束字母写进[] 中,中间用连字符 - 分隔
  • [0-9] 数字范围:我们需要将起始数字和结束数字写进 [] 中,中间用连字符 - 分隔

2. 标志 Flags

/ Regex /g  global 
/ Regex /m  multiline
/ Regex /i  case insensitive
  • global :默认只匹配第一个匹配项,全局标志使表达式选中所有匹配项
  • multiline:默认将所有文本看作一行,多行标志可以单独处理每一行
  • case insensitive:使我们编写的表达式不再大小写敏感,不区分大小写

3. 重复匹配 Repetitions

  • 星号 * Asterisk: 我们在字符后面加上 *,表示一个字符完全不匹配或可以匹配多次。
  • 加号 + The Plus: 为了表示一个字符可以出现一次或多次,我们将 + 放在它后面
  • 问号 ? The Question Mark:为了表示一个字符是可选的,我们在它后面加一个 ?

大括号 {} Curly Braces :在该字符的末尾

  • 为表示一个字符出现的确切次数,将它出现的次数写进大括号 {} 中,如 {n}
  • 为表示一个字符至少出现多少次,将它至少应出现的次数写进大括号  {}  中,并在数字后面加上逗号 ,,如  {n, }
  • 为表示一些字符出现的次数在某个数字范围内,将它至少和至多出现的次数写进大括号  {}  中,中间用逗号 , 分隔,如  {x,y}
[0-9]{2,}  //匹配文本中,位数至少为 2 的阿拉伯数字

4. 分组 Grouping

括号 () 分组,我们可以对一个表达式进行分组,并用这些分组来引用或执行一些规则。为了给表达式分组,我们需要将文本包裹在  ()  中。 -\n 表示第 n 个分组

括号  (?:group) 非捕获分组:对表达式进行分组,但是不被引用捕获

(ha)-\1,(haa)-\2      \\ ha-ha,haa-haa 
(?:ha)-ha,(haa)-\1     \\  ha-ha,haa-haa

5. 特殊

  • 竖线 | 竖线允许一个表达式包含多个不同的分支。所有分支用 | 分隔。 (相当于或)
  • 转义字符 \ Escape Character: {} [] / \ + * . $ ^ | ? 这些特殊字符。为了匹配这些特殊字符本身,我们需要通过 \ 将它们转义
  • 插入符 ^:匹配字符串的开始,在表达式前面加上 ^
  • 美元符号 $:匹配字符串的结束,在表达式末尾加上 $
^[0-9]    //  仅查找行首的数字
html$     // 在行末出现的 html

6. 预定义字符

简写含义等价于
\d数字[0-9]
\D非数字[^0-9]
\w单词字符(字母、数字、下划线)[A-Za-z0-9_]
\W非单词字符[^A-Za-z0-9_]
\s空白字符(空格、制表符、换行等)[\t\n\r\f\v]
\S非空白字符[^\t\n\r\f\v]

7. 零宽断言 Lookarounds

希望正在写的词语出现在另一个词语之前或之后

lookahead 先行断言
  • 正向先行断言 Positive lookahead:在表达式后面使用 (?=pattern) ,匹配出现在 pattern 前面的表达式
  • 负向先行断言 Negative lookahead:在表达式后面使用 (?!pattern),不匹配出现在 pattern 前面的表达式
Date: 4 Aug 3PM 
\d+(?=PM)     // 得到 3 
\d+(?!PM)     // 得到 4 
lookbehind 后行断言
  • 正向后行断言 Positive lookbehind :在表达式前面使用正向后行断言 (?<=pattern) ,匹配出现在 pattern 后面的表达式
  • 负向后行断言 Negative lookbehind assertion:在表达式前面使用 (?<!pattern) ,不匹配出现在 pattern 后面的表达式
Product Code: 1064 Price: $5 

(?<=\$)\d+  //5  正向后行断言 匹配前面带有 \$ 的数字 

(?<!\$)\d+  //1064  负向后行断言

(?<=$)\d+ //5 正向后行断言匹配前面带有 $ 的数字

(?<!$)\d+ //1064 负向后行断言

8. 匹配 Matching

  • Greedy Matching : 正则表达式默认执行贪婪匹配。这意味着匹配内容会尽可能长
  • Lazy Matching:在第一次匹配时停止,在 * 之后添加 ?

二、Python 使用

import re
API作用返回值
re.search(pattern, text)在任意位置找第一次匹配Match 对象或 None
re.match(pattern, text)只在开头匹配Match 对象或 None
re.fullmatch(pattern, text)整段必须完全匹配Match 对象或 None
re.findall(pattern, text)返回所有匹配片段的列表 Listlist[str]
re.finditer(pattern, text)返回迭代器(省内存)Iterator[Match]
re.sub(pattern, repl, text, count=0)替换替换后的字符串

re.sub(pattern, repl, string) 常用的“查找-替换”函数之一,它会在一个字符串中搜索与正则表达式匹配的所有子串,然后用你指定的新内容把它们全部替换掉,最后返回替换后的完整字符串。

return re.sub(r'([A-Z]{3,})|([a-z]{3,})',lambda m: m.group(1).lower() if m.group(1) else m.group(2).upper(),s)

实际使用

[\u4e00-\u9fa5]   匹配中文文本

(\]\()/(img/user/Functional%20files/Photo%20Resources/[^)]+\. (?:png|jpg|jpeg|gif|webp|svg))

$1../$2

^[ \t]*[\[\]][ \t]*$ 

实际例子:正则表达式实现 Obsidian 路径批量更新

\\*\*[^*]+\*\*\

\\*\*|\*\*\|\[\[|\]\]

  • \( 和 \):匹配左右括号(需要转义)。
  • terminology:::匹配字面量 terminology::。
  • \*\*:匹配两个星号 **(需要转义)。
  • [^*]+:匹配一个或多个非星号字符(即术语内容)。
  • \*\*:再次匹配两个星号 **(需要转义)。
  • \):匹配右括号。

参考资料

交互式学习网站:https://regexlearn.com/