我正在尝试使用以下正则表达式从文本中识别罗马数字:
>>>Title="LXXXIV XC, XCII XXX LXII"
>>>RomanNum = re.findall(r'[\s,]+M{0,4}[CM|CD|D?C{0,3}]?[XC|XL|L?X{0,3}]?[IX|IV|V?I{0,3}]?[\s,]+', Title, re.M|re.I)`
>>>RomanNum
[' \t']
我想要类似的东西:
['LXXXIV', 'XC, 'XCII', 'XXX', 'LXII']
就我对正则表达的理解而言,我认为至少XC
应该匹配。 XC
应该与上面的空格前面的正则表达式的[XC|XL|L?X{0,3}]
部分匹配,并且上面的正则表达式捕获后面的逗号。我错过了什么?
除此之外,我可以达到以下所需的结果(但我希望避免更大的复杂性):
>>>RomanNum = [re.search(r'^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$', TitleElem, re.M|re.I) for TitleElem in re.split(',| ', Title)]`
任何帮助表示感谢。
答案 0 :(得分:1)
此时您的正则表达式语法已关闭:
匹配
XC
应与[XC|XL|L?X{0,3}]
因为您使用 square 括号,您可以在其中描述 round 括号的行为。将方括号更改为圆形以进行更正。
在完整正则表达式的其他部分重复此错误。
答案 1 :(得分:1)
如果您想使用findall
或finditer
方法在字符串中查找多个罗马数字,可能的模式是:
(?=[MDCXLVI])(?<![MDCXLVI])M{0,4}(?:C[MD]|D?C{0,3})(?:X[CL]|L?X{0,3})(?:I[XV]|V?I{0,3})(?![MDCXLVI])
它有点长,我将解释为什么我认为它有效:
(?=[MDCXLVI])
是一个前瞻,检查位置是否跟随其中一个字符。这个前瞻有两个功能:
首先是模仿一种第一个字符的歧视,以便快速避免所有不包含其中一个字符的位置(这样,正则表达式引擎就是& #39;需要使用M{0,4}(?:C[MD]|D?C{0,3})(?:X[CL]|L?X{0,3})(?:I[XV]|V?I{0,3})
)测试所有可能的开头。
第二个检查是否至少有一个字符,因为M{0,4}(?:C[MD]|D?C{0,3})(?:X[CL]|L?X{0,3})(?:I[XV]|V?I{0,3})
可以匹配一个空字符串。
(?<![MDCXVLI])
和(?![MDCXVLI])
用作边界,以确保没有其他&#34;罗马字符&#34;周围(否则像ILVIII
这样的子字符串将返回LVIII
,而不是以错误的格式跳过整个字符组)。 请注意,其他类型的边界也是可能的,例如\b
或(?<![^\s,])
(?![^\s,])
...取决于字符串格式。另请注意,左边界是仅在(?=[MDCXVLI])
之后放置才能打破第一个字符歧视。
CM|CD
等变体缩小为C[MD]
。
该模式仅使用非捕获组(?:...)
来保留内存并避免不必要的存储任务。
答案 2 :(得分:0)
Dive Into Python为检测罗马数字提供了一个很好的正则表达式。它们还提供了sample script,您可以利用它来开始。此脚本来自我的第一个链接的7.5部分。
#Define pattern to detect valid Roman numerals
romanNumeralPattern = re.compile("""
^ # beginning of string
M{0,4} # thousands - 0 to 4 M's
(CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
# or 500-800 (D, followed by 0 to 3 C's)
(XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
# or 50-80 (L, followed by 0 to 3 X's)
(IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
# or 5-8 (V, followed by 0 to 3 I's)
$ # end of string
""" ,re.VERBOSE)