专栏文章

再谈正则表达式

科技·工程参与者 15已保存评论 15

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
15 条
当前快照
1 份
快照标识符
@mhz5szms
此快照首次捕获于
2025/11/15 01:56
4 个月前
此快照最后确认于
2025/11/29 05:24
3 个月前
查看原文

-1 为什么要再谈

虽然之前有一篇日报讲正则表达式,但是内容比较深奥且排版不美观,于是决定“再谈”一次。

0 引言:为什么要学习正则表达式

Regex Match Tracer 安装 链接: https://pan.baidu.com/s/13_JR3vzBJw97aP7tQx_6ng 提取码: lgrb
Regex Match Tracer 可以检验正则表达式的正确性。
在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
使用正则表达式可以用来按一定的方式处理某些字符串
正则表达式是一种查找以及字符串替换操作。正则表达式在文本编辑器中广泛使用,比如正则表达式被用于:
  • 检查文本中是否含有指定的特征词
  • 找出文中匹配特征词的位置
  • 从文本中提取信息,比如:字符串的子串
  • 修改文本
与文本编辑器相似,几乎所有的高级编程语言都支持正则表达式。在这样的语境下,“文本”也就是一个字符串,可以执行的操作都是类似的。一些编程语言(比如 Perl,JavaScript)会检查正则表达式的语法。

1 入门

如果你想在一段文本中查找 hi\tt hi,你可以使用正则表达式 hi。但是,这样的话,history,high,\tt history,high,\cdots 中的 hi 都会被查到,如果你想精确地查询 hi\tt hi 这个单词,你可以用正则表达式 \bhi\b,这里的 \b 就是正则表达式的一个特殊字符(元字符),代表「单词的分界处」。

1.1 元字符

1.2 限定符

  • * :重复 00 次或更多次。
  • + :重复 11 次或更多次。
  • ? :重复 00 次或 11 次。
  • {n} :重复 nn 次。
  • {n,} :重复 nn 次或更多次。
  • {n,m} :重复 nnmm 次。

1.3 字符集合

[123] 代表匹配 1,2,3\tt 1,2,3 中的任意一个,也可以使用如 [0-9],这个意义是同 \d 一样的。

1.4 反义

  • \W :匹配任意不是字母,数字,下划线,汉字的字符。
  • \S :匹配任意不是空白符的字符。
  • \D :匹配任意非数字的字符。
  • \B :匹配不是单词开头或结束的位置。
  • [^123] :匹配除了 1,2,3\tt 1,2,3 以外的任何字符。

2 进阶

2.1 后向引用

使用 () 框住一个子表达式后,该表达式会有一个编号(从 11 开始),之后,可以使用 \组号 的形式重复编号为 组号 的子表达式。
  • (exp) :匹配 exp,并自动分组。
  • (?<Name>exp) :匹配 exp,并命名为 Name,重复可用 \k<Name>
  • (?:exp) :匹配 exp,但不捕获匹配的文本,也不给此分组分配组号。
  • (?=exp) :匹配 exp 前面的位置。
  • (?<=exp) :匹配 exp 后面的位置。
  • (?!exp) :匹配 exp 后面的不是 exp 的位置。
  • (?<!exp) :匹配 exp 前面的不是 exp 的位置。
  • (?#note) :这种类型的分组对正则表达式的处理产生任何影响,用于提供注释让人阅读。
  • \n :重复组号为 nn 的子表达式。
好的,我们来解释一下:比如 \b\w+(?=ing) 会匹配一个单词中 ing\tt ing 前面的部分,在 He is playing computer and coding. 中会匹配到 play,cod\tt play,cod
此外,对于 \n 的应用,我也举个例子:匹配四个相同的英语单词,可以使用以下代码:\b([a-z]+) \1 \1 \1\b。其中 \1 指的是子表达式 [a-z]+

2.2 实践

请匹配一个合法邮箱,合法邮箱满足:
  • 第一部分,由若干个字符组成(包括 a-z,A-Z,0-9)。
  • 第二部分,由一个 @ 组成。
  • 第三部分,由网站名组成,网站名由若干个字符组成(包括 a-z,A-Z,0-9),后缀可用 .com
示例如:\b([a-zA-Z0-9]+)@\1\.com\b
(还少了字符串匹配中的哪两个元字符?)
当然,这只是为了简便写的,它只能匹配类似于 iakioi2021@iakioi2021.com 这样的网站名与邮箱名相同的邮箱。

2.3 贪婪

正则表达式会匹配尽可能多的字符,如 a.*b 就会匹配一个以 a\tt a 开头、b\tt b 结尾的最长的字符串。当然,如果你想匹配尽可能少的字符,在后面加上一个 ? 即可。

2.4 栈

匹配一个字符串,问 <> 是否匹配完整(是否是一个完整的括号序列)
需要语法:
  • (?'Name') :把捕获的内容命名为 Name,并压入栈(Stack\bf{Stack})。
  • (?'-Name') :从栈中压出最后一个压入的名为 Name 的内容,若不存在,捕获失败。
  • (?(Name)Yes|No) :若栈中有一个名为 Name 的内容,则执行 Yes,否则执行 No
  • (?!)直接断言无法匹配(可以类比为 C++ 中的 break)。
于是正则表达式:
PLAIN
<                   # 匹配最左边的括号
  [^<>]*            # 匹配非括号部分
  (
    (
      (?'Stack'<)   # 如果匹配到左括号, 压入 "Stack"
      [^<>]*        # 匹配非括号部分
    )+
    (
      (?'-Stack'>)  # 如果匹配到右括号, 弹出 "Stack"
      [^<>]*        # 匹配非括号部分
    )+
  )*
  (?(Stack)(?!))
>

3 参考资料

评论

15 条评论,欢迎与作者交流。

正在加载评论...