17.2. plural.py, 第 1 阶段

你所针对的单词 (至少在英语中) 是字符串和字符。你还需要规则来找出不同的字符 (字母) 组合,并对它们进行不同的操作。这听起来像是正则表达式的工作。

例 17.1. plural1.py


import re

def plural(noun):                            
    if re.search('[sxz]$', noun):             
        return re.sub('$', 'es', noun)        
    elif re.search('[^aeioudgkprt]h$', noun):
        return re.sub('$', 'es', noun)       
    elif re.search('[^aeiou]y$', noun):      
        return re.sub('y$', 'ies', noun)     
    else:                                    
        return noun + 's'                    
好啦,这是一个正则表达式,但是它使用了你在 第 7 章 正则表达式 中未曾见过的语法。方括号的意思是 “完全匹配这些字符中的一个”。也就是说,[sxz] 意味着 “s,或者 x,再或者 z”,但只是其中的一个。$ 应该不陌生,它意味着匹配字符串的结尾。也就是说,检查 noun 是否以 sx,或者 z 结尾。
re.sub 函数进行以正则表达式为基础的替换工作。让我们更具体地看看它。

例 17.2. re.sub 介绍

>>> import re
>>> re.search('[abc]', 'Mark')   
<_sre.SRE_Match object at 0x001C1FA8>
>>> re.sub('[abc]', 'o', 'Mark') 
'Mork'
>>> re.sub('[abc]', 'o', 'rock') 
'rook'
>>> re.sub('[abc]', 'o', 'caps') 
'oops'
Mark 包含 ab,或者 c吗?是的,含有 a
好的,现在找出 ab,或者 c 并以 o 取代之。Mark 就变成 Mork 了。
同一方法可以将 rock 变成 rook
你可能认为它可以将 caps 变成 oaps,时时彩计划软件公式:但事实并非如此。re.sub 替换所有 的匹配项,并不只是第一个匹配项。因此正则表达式将会把 caps 变成 oops,因为 ca 都被转换为 o了。

例 17.3. 回到 plural1.py


import re

def plural(noun):                            
    if re.search('[sxz]$', noun):            
        return re.sub('$', 'es', noun)        
    elif re.search('[^aeioudgkprt]h$', noun): 
        return re.sub('$', 'es', noun)        
    elif re.search('[^aeiou]y$', noun):      
        return re.sub('y$', 'ies', noun)     
    else:                                    
        return noun + 's'                    
回到 plural 函数。你在做什么?你在以 es 取代字符串的结尾。换句话说,追加 es 到字符串。你可以通过字符串拼合做到相同的事,例如 noun + 'es',但是我使用正则表达式做这一切,既是为了保持一致,也是为了本章稍后你会明白的其它原因。
仔细看看,这是另一个新的内容。^ 是方括号里面的第一个字符,这有特别的含义:否定。[^abc] 意味着 “ab、 和 c 以外的 任意单字符”。所以,[^aeioudgkprt] 意味着除 aeioudgkprt 以外的任意字符。这个字符之后应该跟着一个 h,然后是字符串的结尾。你在寻找的是以发音的 H 结尾的单词。
这是一个相似的表达:匹配 Y 前面不是 aeiou,并以这个 Y 结尾的单词。你在查找的是以发 I 音的 Y 结尾的单词。

例 17.4. 正则表达式中否定的更多应用

>>> import re
>>> re.search('[^aeiou]y$', 'vacancy') 
<_sre.SRE_Match object at 0x001C1FA8>
>>> re.search('[^aeiou]y$', 'boy')     
>>> 
>>> re.search('[^aeiou]y$', 'day')
>>> 
>>> re.search('[^aeiou]y$', 'pita')    
>>> 
vacancy 匹配这个正则表达式,因为它以 cy 结尾,并且 c 不在 aeiou 之列。
boy 不能匹配,因为它以 oy 结尾,并且你特别指出 y 之前的字符不可以是 oday 不能匹配是因为以 ay 结尾。
pita 不匹配是因为不以 y 结尾。

例 17.5. 更多的 re.sub

>>> re.sub('y$', 'ies', 'vacancy')              
'vacancies'
>>> re.sub('y$', 'ies', 'agency')
'agencies'
>>> re.sub('([^aeiou])y$', r'\1ies', 'vacancy') 
'vacancies'
正则表达式把 vacancy 变为 vacancies,把 agency 变为 agencies,这正是你想要的。注意,将 boy 变成 boies 是可行的,但是永远不会发生,因为 re.search 首先确定是否应该应用 re.sub
顺便提一下,可以将两个正则表达式 (一个确定规则适用与否,一个应用规则) 合并在一起成为一个正则表达式。这便是合并后的样子。它的大部分已经很熟悉:你应用的是在 第 7.6 节 “个案研究:解析电话号码” 学过的记忆组 (remembered group) 记住 y 之前的字符。然后再替换字符串,你使用一个新的语法 \1,这意味着:“嘿!记得前面的第一个组吗?把它放这儿”。就此而言,记住了 y 之前的 c ,然后你做替换工作,你将 c 替换到 c 的位置,并将 ies 替换到 y 的位置。(如果你有不止一个组则可以使用 \2 或者 \3 等等。)

正则表达式替换非常强大,并且 \1 语法使之更加强大。但是将整个操作放在一个正则表达式中仍然晦涩难懂,也不能与前面描述的复数规则直接呼应。你原来列出的规则,比如 “如果单词以 S,X 或者 Z 结尾,结尾追加 ES”。如果你在函数中看到两行代码描述 “如果单词以 S,X 或者 Z 结尾,结尾追加 ES”,更加直观些。

时时彩专家软件 时时彩投注技巧大全 时时彩奖金1980元平台 重庆时时彩软件计划手机版 江西时时彩搜狐
江西时时彩计划后一公式 时时彩平台架设一条龙 时时彩举报网 双色球怎么杀号最准确 求重庆时时彩交流群
微信上怎么玩时时彩 时时彩代理招商 仿重庆时时彩平台源码 时时彩后二分解 时时彩平台追号刷钱
时时彩定位胆玩法技巧 时时彩开户 大华解码器软件 双色球专家杀号必赢网 江西时时彩不定位
11选5开奖结果走势图 福建快3开奖公告 秒速时时彩盛世开奖 白小姐资料 香港赛马会开奖直播
香港六合彩曾道人 云南时时彩开奖结果走势图 广西快乐双彩票开奖查询 北京赛车投注平台官网 香港赛马会公开网
卡西欧急速赛车系列 大乐透走势图浙江 平刷王北京赛车 甘肃十一选五的开奖结果 重庆时时彩助赢软件免费版
河南体彩有没有11选5 安徽省福利25选5开奖结果 吉林时时彩走势图开奖结果查询 北京11选5杀号技巧 湖北快三预测一定牛