导航: 起始页 > Dive Into Python > 正则表达式 > 个案研究:罗马字母 | << >> | ||||
Python 研究(Dive Into Python)Python 从新手到高手 [DIP_5_4_CPUG_RELEASE] |
你可能经常看到罗马数字,即使你没有意识到他们。你可能曾经在老电影或者电视中看到他们(“版权所有 MCMXLVI” 而不是 “版权所有1946”),或者在某图书馆或某大学的贡献墙上看到他们(“成立于 MDCCCLXXXVIII”而不是“成立于1888”)。你也可能在某些文献的大纲或者目录上看到他们。这是一个表示数字的系统,他能够真正回溯到远古的罗马帝国(因此而得名)。
在罗马数字中,利用7个不同字母进行重复或者组合来表达各式各样的数字。
- I = 1
- V = 5
- X = 10
- L = 50
- C = 100
- D = 500
- M = 1000
下面是关于构造罗马数字的一些通用的规则的介绍:
- 字符是叠加的。 I表示1, II表示2, 而III表示3. VI 表示 6 (字面上为逐字符相加, “5 加 1”), VII 表示 7, VIII 表示 8.
- 能够被10整除的字符(I, X, C, 和 M)至多可以重复三次. 对于4, 你则需要利用下一个最大的能够被5整除的字符进行减操作得到,你不能把4 表示成 IIII; 而应表示为 IV (比“5小 1”)。数字40写成XL (比50小10), 41 写成 XLI, 42 写成 XLII, 43 写成 XLIII, 而 44 写成 XLIV (比50 小10, 然后比5小1).
- 类似的,对于数字 9,你必须利用下一个能够被10整除的字符进行减操作得到: 8 表示为 VIII, 而 9 则表示为 IX (比10 小1), 而不是 VIIII (因为字符I 不能连续重复四次)。数字90 表示为 XC, 900 表示为 CM.
- 被5整除的字符不能重复。数字10 常表示为X, 而从来不用VV来表示。数字100常表示为C, 也从来不表示为 LL.
- 罗马数字经常从高位到低位书写,从左到右阅读,因此不同顺序的字符意义大不相同。DC 表示 600; 而CD 是一个完全不同的数字(为400, 也就是比500 小100). CI 表示 101; 而IC 甚至不是一个合法的罗马字母(因为你不能直接从数字100减去1; 比需要写成XCIX, 意思是 比100 小10, 然后加上数字9,也就是比 10小1的数字).
本章译者注:“被5整除的数”这个译法并不严谨,因为所有被10整除的数也能够被5整除,此处表达的含义是:那些包含有5的含义的罗马数字字符。 |
怎样校验任意一个字符串是否为一个有效的罗马数字呢?我们每次只看一个数字,由于罗马数字经常是从高位到低位书写,我们从高位开始:千位。对于大于、等于1000的数字,千位有一系列的字符 M 表示。
例 7.3. 校验千位数
>>> import re >>> pattern = '^M?M?M?$' >>> re.search(pattern, 'M') <SRE_Match object at 0106FB58> >>> re.search(pattern, 'MM') <SRE_Match object at 0106C290> >>> re.search(pattern, 'MMM') <SRE_Match object at 0106AA38> >>> re.search(pattern, 'MMMM') >>> re.search(pattern, '') <SRE_Match object at 0106F4A8>
百位数的位置与千位数相比,识别起来要困难得多,这是因为有多种相互独立的表达方式都可以表达百位数,具体用那种方式表达和具体的数值相关。
- 100 = C
- 200 = CC
- 300 = CCC
- 400 = CD
- 500 = D
- 600 = DC
- 700 = DCC
- 800 = DCCC
- 900 = CM
因此有四种可能的模式:
- CM
- CD
- 零到三次出现C 字符 (如果是零,表示百位数为0)
- D, 后面跟零个到三个C字符
后面两个模式可以结合到一起:
- 一个可选的字符D, 加上零到3个C 字符。
这个例子显示如何有效的识别罗马数字的百位数位置。
例 7.4. 检验百位数
>>> import re >>> pattern = '^M?M?M?(CM|CD|D?C?C?C?)$' >>> re.search(pattern, 'MCM') <SRE_Match object at 01070390> >>> re.search(pattern, 'MD') <SRE_Match object at 01073A50> >>> re.search(pattern, 'MMMCCC') <SRE_Match object at 010748A8> >>> re.search(pattern, 'MCMC') >>> re.search(pattern, '') <SRE_Match object at 01071D98>
吆!来看正则表达式能够多快变得难以理解?你仅仅表示了罗马数字的千位和百位上的数字。如果你根据类似的方法,十位数和各位数就非常简单了,因为是完全相同的模式。让我们来看表达这个模式的另一种方式吧。
<< 个案研究:街道地址 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
使用{n,m} 语法 >> |