浅色背景上的正则表达式符号,例如 \d、\d+、\d{4}、^ 和 $

时隔一段时间,正则表达式系列迎来了第四篇。

在上一篇《系列【正则表达式】——把搜索到的内容重新排列后再替换》中,我们介绍了如何用括号捕获日期中的年、月、日,再通过 $1、$2、$3 改变它们的顺序。

这一次,我们把同样的方法用到英文句式的调整中。

哪些内容需要替换,哪些需要保留?

假设一份英文技术文档中出现了以下表达:

替换前替换后
the portion where an electrode is providedthe portion on which an electrode is provided
the part where a terminal is providedthe part on which a terminal is provided
the section where the sensor is providedthe section on which the sensor is provided
the surface where a wiring layer is providedthe surface on which a wiring layer is provided
the substrate where a thin insulating wiring layer is providedthe substrate on which a thin insulating wiring layer is provided

这些表达有一个共同的句式:

the [表示位置或部位的词] where [冠词] [部件名称] is provided

但where 前面的词可能是 portion、part、section 或 surface,where 后面也可能是 an electrode、a terminal、the sensor 或 a wiring layer。冠词有 a、an、the 三种,部件名称也可能由多个单词组成。

我们的目标只是把 where 改为 on which,位置、部件名称以及冠词都保持不变。也就是说,即使 where 前后的词语各不相同,我们也要找出相同的句式,只替换需要修改的部分。

需要先说明一点:where 与 on which 并不是在任何语境下都可以互换。只有当上下文能够确认部件位于某一表面之上等符合介词 on 所表达的位置关系时,这样的替换才合适。下面假定这些例子的技术含义已经核实。

为什么不直接搜索 where?

如果直接把文档中所有的 where 都替换掉,就可能误改其他用法。我们真正需要查找的,是上面这种 the ... where ... is provided 结构。

因此,搜索条件需要包含前后的内容。但也不能把 part、terminal 这样的词固定下来,否则其他变体就匹配不到了。

这正是上一篇介绍的捕获组发挥作用的地方:在搜索时匹配可能变化的词语,在替换时再把原来的内容放回去。

用 \S 匹配非空白字符

上一篇用 \d 匹配单个数字。这一次,我们使用 \S 来匹配单词所在的位置。

\S 表示匹配一个非空白字符。加上表示“一次或多次”的 +,就得到:

\S+

这样就可以把 portion、part、section、electrode、terminal 等中间没有空白的字符串作为一个整体进行匹配。

补充:\S 也会匹配标点和符号

\S 并不限于英文字母。连字符和斜杠同样不是空白字符,因此 heat-resistant、input/output 都可以由 \S+ 整体匹配。但逗号、句号等标点也符合条件。因此,\S+ 查找的其实是“连续的非空白字符”,而不一定是语言意义上的一个单词。

用括号捕获要保留的词语

先来看第一个例子:the portion where an electrode is provided。

查找

the (\S+) where an (\S+) is provided

替换

the $1 on which an $2 is provided

括号中匹配到的内容,可以在替换时再次引用。

捕获结果
$1 → portion
$2 → electrode

虽然搜索表达式中也包含 the、where、an 和 is provided,但这些部分没有用括号捕获。替换时,我们将 where 改为 on which,再通过 $1 和 $2 放回原来的 portion 和 electrode。

只要是中间不含空白的一个字符串,即使把 portion 换成 part 或 section,也能用同样的方法捕获。不过,此时的冠词仍然固定为 an。

用 | 同时匹配 a、an 和 the

接下来处理冠词的变化。如果希望 an electrode、a terminal 和 the sensor 都能匹配,可以使用竖线 |。

(a|an|the)

它表示“a、an 或 the 中的任意一个”。由于外面有括号,实际匹配到的冠词也能在替换时保留下来。

查找

the (\S+) where (a|an|the) (\S+) is provided

替换

the $1 on which $2 $3 is provided

现在有三个捕获组,因此可以取回三个部分。

捕获组捕获的内容以 the section where the sensor is provided 为例
$1where 前面的词section
$2冠词(a、an、the)the
$3冠词后面的词sensor

捕获组 $1、$2、$3 与替换结果的对应关系示意图

按照捕获组编号,将括号中的内容放回替换后的句子,原来的冠词和部件名称就能保留。

开头列出的 an electrode、a terminal、the sensor 都能通过这个表达式找到。我们并没有在替换表达式中重新指定冠词,而是用 $2 放回原文中的冠词,因此 a、an、the 的区别得以保留。

处理多词名称:[^…] 与 +?

到目前为止,\S+ 遇到空白就会停止,因此无法一次捕获下面这些例子中的完整部件名称:

the surface where a wiring layer is provided

the substrate where a thin insulating wiring layer is provided

怎样才能允许部件名称包含空格,同时避免匹配范围延伸到下一句话呢?

不排除空格,而是排除标点和换行

如果在方括号开头写上 ^,表示匹配方括号中列出的字符以外的字符。例如:

[^\s.,;:!?]+

这里排除了表示空白字符的 \s,以及列出的标点。因此,这个写法仍然无法一次捕获包含空格的 wiring layer。

所以,在本例用于匹配部件名称的部分,我们选择允许空格,但排除标点和换行符:

[^.,;:!?\r\n]+

这里排除了句号、逗号、分号、冒号、感叹号、问号,以及换行字符 \r、\n。普通半角空格仍然允许出现,所以 wiring layer 和 thin insulating wiring layer 都可以匹配。

注意,这里的 ^ 位于方括号开头,表示排除指定字符;它与用于表示字符串开头的 ^ 不是同一种用法。

用 +? 在第一个 is provided 处停止

不过,允许空格以后又会出现一个问题:如果同一句中多次出现 is provided,具有贪婪特性的 + 可能匹配过长的内容。这时可以将它改成 +?:

[^.,;:!?\r\n]+?

+? 仍表示“一次或多次”,但会优先尝试尽可能短的匹配。当后面接着 is provided 时,正则表达式就可以在第一个满足整体条件的位置完成匹配。前面排除的标点和换行仍然是匹配边界。

整理后,搜索表达式如下:

查找

the ([^\s.,;:!?]+) where (a|an|the) ([^.,;:!?\r\n]+?) is provided

替换

the $1 on which $2 $3 is provided

对于 the surface where a wiring layer is provided,$3 是 wiring layer;对于 the substrate where a thin insulating wiring layer is provided,$3 是 thin insulating wiring layer。这样就不必把部件名称限制为一个或两个单词了。

即使采用非贪婪匹配,也要检查结果

下面这句话中,第一个 is provided 已经满足整体条件,因此 $3 只捕获 wiring layer:

the surface where a wiring layer is provided and a protective film is provided

在下面的例子中,匹配也不会越过句号延伸到下一句:

the surface where a wiring layer is formed. A protective film is provided

但下面这句话需要注意:

the surface where a wiring layer is formed and a protective film is provided

此时,$3 会捕获 wiring layer is formed and a protective film。因为中间没有被排除的标点,后面又出现了 is provided,整个字符串仍然符合匹配条件。

换句话说,这个表达式可以查找包含多个单词的部件名称的句式,却无法从语法上判断名词短语在哪里结束、其他句子成分从哪里开始。对于没有排除的符号或特殊格式,也需要留意。

另外,where 前面是多个单词,或者句式中不含冠词等情况,也不在本次表达式的匹配范围内。更重要的是,将 where 改为 on which 是否保留原有的技术含义,仍需要根据上下文以及必要时的附图来判断。

先用正则表达式找出候选位置,再逐一确认哪些地方适合替换。 对于专利说明书等技术文档,这一点尤其重要。

本篇要点回顾

表达式含义
\S匹配一个非空白字符
\s匹配一个空白字符,例如空格、制表符或换行
|表示“或”,可用来指定不同冠词等选项
[ ]匹配方括号中列出的任意一个字符
[^ ]匹配方括号中未列出的字符
+?匹配一次或多次,并优先尝试最短匹配

在这次的例子中,我们允许多词部件名称中存在空格,同时排除指定的标点和换行符,从而控制匹配范围。

查找

the ([^\s.,;:!?]+) where (a|an|the) ([^.,;:!?\r\n]+?) is provided

替换

the $1 on which $2 $3 is provided

上一篇,我们捕获日期中的数字并调整顺序;这一次,我们捕获句式中可能变化的词语和冠词,再将它们放回替换后的句子。同时也能看到,要让搜索更可靠,还需要明确哪些位置允许出现空格、哪些标点应当作为边界,以及匹配应该在哪里停止。

下一篇:在 memoQ 中实际操作

前四篇已经介绍了使用正则表达式进行搜索和替换的基础。下一篇开始,我们将进入 memoQ 翻译编辑器,结合查找与替换功能、文本筛选器,看看如何定位候选表达、检查匹配结果,再修改真正需要调整的内容。