<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            7.4. 使用 {n,m} 語法

            前面的章節,你處理了相同字符可以重復三次的情況。在正則表達式中,有另外一個方式來表達這種情況,并且能提高代碼的可讀性。首先看看我們在前面的例子中使用的方法。

            例 7.5. 老方法:每一個字符都是可選的

            >>> import re
            >>> pattern = '^M?M?M?$'
            >>> re.search(pattern, 'M')    1
            <_sre.SRE_Match object at 0x008EE090>
            >>> pattern = '^M?M?M?$'
            >>> re.search(pattern, 'MM')   2
            <_sre.SRE_Match object at 0x008EEB48>
            >>> pattern = '^M?M?M?$'
            >>> re.search(pattern, 'MMM')  3
            <_sre.SRE_Match object at 0x008EE090>
            >>> re.search(pattern, 'MMMM') 4
            >>> 
            
            1 這個模式匹配串的開始,接著是第一個可選的字符 M,第二第三個 M 字符則被忽略 (這是可行的,因為它們都是可選的),最后是字符串的結尾。
            2 這個模式匹配串的開始,接著是第一和第二個可選字符 M,而第三個 M 字符被忽略 (這是可行的,因為它們都是可選的),最后匹配字符串的結尾。
            3 這個模式匹配字符串的開始,接著匹配所有的三個可選字符 M,最后匹配字符串的結尾。
            4 這個模式匹配字符串的開始,接著匹配所有的三個可選字符 M,但是不能夠匹配字符串的結尾 (因為還有一個未匹配的字符 M),因此不能夠匹配而返回一個 None

            例 7.6. 一個新的方法:從 nm

            >>> pattern = '^M{0,3}$'       1
            >>> re.search(pattern, 'M')    2
            <_sre.SRE_Match object at 0x008EEB48>
            >>> re.search(pattern, 'MM')   3
            <_sre.SRE_Match object at 0x008EE090>
            >>> re.search(pattern, 'MMM')  4
            <_sre.SRE_Match object at 0x008EEDA8>
            >>> re.search(pattern, 'MMMM') 5
            >>> 
            
            1 這個模式意思是說:“匹配字符串的開始,接著匹配 0 到 3 個 M 字符,然后匹配字符串的結尾。”這里的 0 和 3 可以改成其它任何數字;如果你想要匹配至少 1 次,至多 3 次字符 M,則可以寫成 M{1,3}
            2 這個模式匹配字符串的開始,接著匹配三個可選 M 字符中的一個,最后是字符串的結尾。
            3 這個模式匹配字符串的開始,接著匹配三個可選 M 字符中的兩個,最后是字符串的結尾。
            4 這個模式匹配字符串的開始,接著匹配三個可選 M 字符中的三個,最后是字符串的結尾。
            5 這個模式匹配字符串的開始,接著匹配三個可選 M 字符中的三個,但是沒有匹配上 字符串的結尾。正則表達式在字符串結尾之前最多只允許匹配三次 M 字符,但是實際上有四個 M 字符,因此模式沒有匹配上這個字符串,返回一個 None
            注意
            沒有一個輕松的方法來確定兩個正則表達式是否等價。你能采用的最好的辦法就是列出很多的測試樣例,確定這兩個正則表達式對所有的相關輸入都有相同的輸出。在本書后面的章節,將更多地討論如何編寫測試樣例。

            7.4.1. 校驗十位數和個位數

            現在我們來擴展一下關于羅馬數字的正則表達式,以匹配十位數和個位數,下面的例子展示十位數的校驗方法。

            例 7.7. 校驗十位數

            >>> pattern = '^M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)$'
            >>> re.search(pattern, 'MCMXL')    1
            <_sre.SRE_Match object at 0x008EEB48>
            >>> re.search(pattern, 'MCML')     2
            <_sre.SRE_Match object at 0x008EEB48>
            >>> re.search(pattern, 'MCMLX')    3
            <_sre.SRE_Match object at 0x008EEB48>
            >>> re.search(pattern, 'MCMLXXX')  4
            <_sre.SRE_Match object at 0x008EEB48>
            >>> re.search(pattern, 'MCMLXXXX') 5
            >>> 
            
            1 這個模式匹配字符串的開始,接著是第一個可選字符 M,接著是 CM,接著 XL,接著是字符串的結尾。請記住,(A|B|C) 這個語法的含義是“精確匹配 A、B 或者 C 其中的一個”。此處匹配了 XL,因此不再匹配 XCL?X?X?X?,接著就匹配到字符串的結尾。MCML 表示羅馬數字 1940
            2 這個模式匹配字符串的開始,接著是第一個可選字符 M,接著是 CM,接著 L?X?X?X?。在模式 L?X?X?X? 中,它匹配 L 字符并且跳過所有可選的 X 字符,接著匹配字符串的結尾。MCML 表示羅馬數字 1950
            3 這個模式匹配字符串的開始,接著是第一個可選字符 M,接著是 CM,接著是可選的 L 字符和可選的第一個 X 字符,并且跳過第二第三個可選的 X 字符,接著是字符串的結尾。MCMLX 表示羅馬數字 1960
            4 這個模式匹配字符串的開始,接著是第一個可選字符 M,接著是 CM,接著是可選的 L 字符和所有的三個可選的 X 字符,接著匹配字符串的結尾。MCMLXXX 表示羅馬數字 1980
            5 這個模式匹配字符串的開始,接著是第一個可選字符M,接著是CM,接著是可選的 L字符和所有的三個可選的X字符,接著就未能匹配 字符串的結尾ie,因為還有一個未匹配的X 字符。所以整個模式匹配失敗并返回一個 None. MCMLXXXX 不是一個有效的羅馬數字。

            對于個位數的正則表達式有類似的表達方式,我將省略細節,直接展示結果。

            >>> pattern = '^M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'
            

            用另一種 {n,m} 語法表達這個正則表達式會如何呢?這個例子展示新的語法。

            例 7.8. 用 {n,m} 語法確認羅馬數字

            >>> pattern = '^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'
            >>> re.search(pattern, 'MDLV')             1
            <_sre.SRE_Match object at 0x008EEB48>
            >>> re.search(pattern, 'MMDCLXVI')         2
            <_sre.SRE_Match object at 0x008EEB48>
            >>> re.search(pattern, 'MMMDCCCLXXXVIII')  3
            <_sre.SRE_Match object at 0x008EEB48>
            >>> re.search(pattern, 'I')                4
            <_sre.SRE_Match object at 0x008EEB48>
            
            1 這個模式匹配字符串的開始,接著匹配三個可選的 M 字符的一個,接著匹配 D?C{0,3},此處,僅僅匹配可選的字符 D 和 0 個可選字符 C。繼續向前匹配,匹配 L?X{0,3},此處,匹配可選的 L 字符和 0 個可選字符 X,接著匹配 V?I{0,3},此處,匹配可選的 V 和 0 個可選字符 I,最后匹配字符串的結尾。MDLV 表示羅馬數字 1555
            2 這個模式匹配字符串的開始,接著是三個可選的 M 字符的兩個,接著匹配 D?C{0,3},此處為一個字符 D 和三個可選 C 字符中的一個,接著匹配 L?X{0,3},此處為一個 L 字符和三個可選 X 字符中的一個,接著匹配 V?I{0,3},此處為一個字符 V 和三個可選 I 字符中的一個,接著匹配字符串的結尾。MMDCLXVI 表示羅馬數字 2666
            3 這個模式匹配字符串的開始,接著是三個可選的 M 字符的所有字符,接著匹配 D?C{0,3},此處為一個字符 D 和三個可選 C 字符中所有字符,接著匹配 L?X{0,3},此處為一個 L 字符和三個可選 X 字符中所有字符,接著匹配 V?I{0,3},此處為一個字符 V 和三個可選 I 字符中所有字符,接著匹配字符串的結尾。MMMDCCCLXXXVIII 表示羅馬數字3888,這個數字是不用擴展語法可以寫出的最大的羅馬數字。
            4 仔細看哪!(我像一個魔術師一樣,“看仔細嘍,孩子們,我將要從我的帽子中拽出一只兔子來啦!”) 這個模式匹配字符串的開始,接著匹配 3 個可選 M 字符的 0 個,接著匹配 D?C{0,3},此處,跳過可選字符 D 并匹配三個可選 C 字符的 0 個,接著匹配 L?X{0,3},此處,跳過可選字符 L 并匹配三個可選 X 字符的 0 個,接著匹配 V?I{0,3},此處跳過可選字符 V 并匹配三個可選 I 字符的一個,最后匹配字符串的結尾。哇賽!

            如果你在第一遍就跟上并理解了所講的這些,那么你做的比我還要好。現在,你可以嘗試著理解別人大規模程序里關鍵函數中的正則表達式了。或者想象著幾個月后回頭理解你自己的正則表達式。我曾經做過這樣的事情,但是它并不是那么有趣。

            在下一節里,你將會研究另外一種正則表達式語法,它可以使你的表達式具有更好的可維持性。

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线