利用「正则表达式」进行批量文本替换
利用「正则表达式」可以显著的提高文档处理的效率。本文围绕下列例子,简要的介绍了如何通过正则表达式进行文档的快速查找与替换。
查找字符串 ^[►](\D*)(\d+).* |
请注意,「正则表达式」Regular Expression 简称 Regx,是一门博大而深邃的艺术,本文只能算作入门教程的导论[1] [2]。
最简单的例子 - 删除多余空行
最直接的想法即是查找「换行符」直接删除,如下:
|
然而,这样是行不通的:
第一行文本
第二行文本
第三行文本
经过处理后就成为了:
第一行文本第二行文本第三行文本
正常段落间换行也被删除了。不过,稍加变化即可解决问题:
|
在 Regx 中,^ 标记行首;$ 标记行尾。
上述代码的意思即是查找出现在行首的「换行符」,从而解决了上述问题。
略微复杂的例子 - 删除行首行标
|
我们已经清楚通过 ^ 可以定位行首,现在新的问题是如何追踪到行标。凡事先问「是什么」,「行标」用自然语言来说,就是「出现在行首的一个或多个数字」。那么在 Regx 中可以用,\d+ 来表示。借此,引入「元字符」和「限定符」的概念,如下表:
元字符 | 匹配内容 |
---|---|
. | 匹配除换行符以外的任意字符 |
\ w | 匹配字母或数字或下划线或汉字 |
\ b | 匹配单词的开始或结束 |
\ s | 匹配任意的空白符 |
\ d | 匹配数字 |
限定符 | 重复次数 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
真实的应用:一堆文本与一个问题
最近在处理一个超过十万字的 [3] 文本,需要把它处理为某种计算机可用的格式。里面含有大量的类似于这样的文本:
► 指向 1984 。
需要替换为这个
-> 1984 [label = “ 指向 “];
其中,文本和数字都是任意的。这是个有些复杂的问题,最终解决的办法就是开头的那串复杂的 Regx,如下:
|
除了上述章节已经提及的元素,首先映入眼帘的[4],是一堆括号,那么就先来解释括号的意义。
方括号 [ ] 指没有预定义的「元字符」集,比方说[►]就是指当匹配到任何一个「 ► 」的时候。同理, [aeiou]指匹配到任何一个元音字母的时候。
小括号 ( ) 指分组,每个组会被按照次序依次加上序号。替换字符串这里是最简单的应用,
|
显然,Regx 是大小写敏感的。再浏览一遍上面的 Regx,只有一个地方不清除了,\D 的意义。现在引入「反义字符」的概念
反义字符 | 匹配内容 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\B | 匹配不是单词开头或结束的位置 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
^x | 匹配除了x以外的任意字符 |
同理 [^aeiou] 匹配除了 a e i o u 这几个字母以外的任意字符。那么,用自然语言解释这一串 Regx 的意义即是:
查找到行首;匹配 ► ;接着匹配任意数量非数字字符,编为第一组;接着匹配一个或多个数字,编为第二组;匹配任意数量的在本行的任意字符;完
一只 BUG 与「贪婪模式」
|
之前处理此问题的时候,用的是上面这个 Regx ,但最后替换的结果令人哭笑不得
-> b4 [label=” 指向198”];
原因如下:
通常当 Regx 中包含能接受重复的限定符时,在使整个 Regx 能得到匹配的前提下,匹配尽可能多的字符。这被称为「贪婪模式」Greedy Mode 。与此对应的称之为「懒惰模式」Lazy Mode 。
这样的话,在「► 指向 1984 。」中,前面的 * 一直取到 8 也就不足为奇了。
###
思考题:Unix Command
|
是什么意思?[5]
综上所述
Regx 也应该可以算作「计算机科学」中的上古神器之一 — 简洁,优雅,烧脑。