标题的正则表达式

Regular Expression for Titles

我是正则表达式的新手,对它们的强大功能很感兴趣。我想提出一个正则表达式来生成标题大小写约定。一般来说,书籍、电影等作品的英文名称中的每个单词都需要首字母大写,除了文章("a"、"an"、"the"),单词"to" 作为不定式的一部分,以及短于五个字母的介词和并列连词("in"、"on"、"from"、"and"、"with"),除非它们开始或结束标题或副标题。

话虽如此,我想做的基本上是将字符串(标题)中每个单词的第一个字母大写,除了以下单词:

a
an
the
to
in
on
from
and
with

这些单词是第一个或最后一个单词时首字母大写,否则全部小写。

Examples:
   A New Kind of Science     (uppercase A - first word)
   Once in a While           (lowercase a - not first/last word)
   The World We Live In      (uppercase The - first word)
   Ghost in the Shell        (lowercase the - not first/last word)
   To Be or Not to Be        (uppercase and lowercase To, to)

理想情况下,罗马数字 (1-5000) 应全部大写:

I, II, III, ... (ones)
IV, V, VI, ...  (fives)
IX, X, XI, ...  (tens)
XL, L, LX, ...  (fifties)
XC, C, CX, ...  (hundreds)
XD, D, DX, ...  (five hundreds)
CM, M, MC, ...  (thousands)

所有排列见:Roman Numerals

有什么关于从哪里开始的建议吗?

正则表达式很强大,没错。但在这种情况下,您最终会用一页正则表达式来定义所有这些规则。这不实用。

但如果你介意的话,我还有一个想法。

  1. 定义停用词数组(a、an、the、to 等)
  2. 为罗马数字定义一个数组。
  3. 拆分每个标题的所有单词
  4. 对于每个标题,迭代每个词并检查该词是停用词还是罗马数字。
  5. 如果是停用词,则全部小写,如果是数字,则全部大写,否则第一个字母大写,其余字母小写。
  6. 连接处理过的单词以获得最终标题。

不到 50 行 Java 代码就可以完成这项工作。

首先,没有 "regex",每种工具和语言都有自己的正则表达式实现。您将无法在大多数正则表达式风格中完成您的任务,因为它们不支持对匹配项的操作(将大写字母转换为小写字母,反之亦然)。

但是 Boost Regex Engine, which is used in Notepad++(我测试过的地方)和 C++ 可以做这种事情。

那么让我们先从匹配的部分开始吧

\b(?<!^)(a(?:nd?)?|the|to|[io]n|from|with)(?!$)\b|\b(?=[ivxlcdm]+\b)(m{0,4}(?:cm|cd|d?c{0,3})(?:xc|xl|l?x{0,3})(?:ix|iv|v?i{0,3}))(?<=\w)\b|\b(\w)(\w*)\b

如果它们支持 lookahead and lookbehind(java脚本不支持),您可以使用它来匹配大多数正则表达式风格。在某些情况下,您必须将反斜杠加倍(例如 java)。您还需要包括多行匹配修饰符(锚点 ^ 和 $ 匹配每一行的 beginning/end)和不区分大小写的匹配。 Notepad++ 自动包含多行,并有一个大小写不敏感的复选框。

我在这里经常使用 \b,因为它会检查单词的 start/end,所以我们只将完整的单词放入匹配中。

基本上我正在检查 3 种不同的情况:

  • 您的一个关键字应为小写字母,但不能位于字符串的开头(注意:检查 to 仅作为不定式的一部分是不可能的,因为我们无法解释该语言)
  • 罗马数字
  • 任何其他词

所以 \b(?<!^)(a(?:nd?)?|the|to|[io]n|from|with)(?!$)\b 匹配您的一个关键字,如果它不在开头 ((?<!^)) 和结尾 ((?!$)),同时使用否定前瞻和后视作为主播。

\b(?=[ivxlcdm]+\b)(m{0,4}(?:cm|cd|d?c{0,3})(?:xc|xl|l?x{0,3})(?:ix|iv|v?i{0,3}))(?<=\w)\b 匹配罗马数字。实际支票 ((m{0,4}(?:cm|cd|d?c{0,3})(?:xc|xl|l?x{0,3})(?:ix|iv|v?i{0,3}))) 取自 this answer,因此所有功劳都归作者所有。我在开头添加了前瞻 ((?=[ivxlcdm]+\b)),以确保后面只有字母,可以构建罗马数字(这纯粹是速度优化),最后添加了前瞻 (?<=\w),以确保我们不匹配空字符串。 (对于像 ill 这样的词,只包含有效字母,但实际上不是罗马数字)

\b(\w)(\w*)\b 匹配之前未匹配的每个单词,将第一个字母放在一个捕获组中,其他字母放在第二个捕获组中。需要拆分成这些组以将第一个转换为大写,将最后一个转换为小写

替换相当简单:\L\U\U\L 它利用 \L\U,在 boost 正则表达式中强制以下字母为小写或大写。 </code> 是对第一个捕获组的反向引用,依此类推。</p> <p>所以如果我们有这样的示例文本:</p> <pre><code>a NEw kinD of ScIENce ONCE IN A WHILE the world we live in GHOST in the Shell To Be Or Not To Be Louis xiv and Edward IV In Year mmXII we will all die ILL till we die

我们将把它转换成

A New Kind Of Science
Once in a While
The World We Live In
Ghost in the Shell
To Be Or Not to Be
Louis XIV and Edward IV
In Year MMXII We Will All Die
Ill Till We Die