首字母大小寫無(wú)關(guān)模式
有一段時(shí)間,我在寫正則表達(dá)式來(lái)匹配Drug關(guān)鍵字時(shí),經(jīng)常寫出 /viagra|cialis|anti-ed/ 這樣的表達(dá)式。為了讓它更美觀,我會(huì)給關(guān)鍵詞排序;為了提升速度,我會(huì)使用 /[Vv]iagra/ 而非/viagra/i ,只讓必要的部分進(jìn)行大小寫通配模式。確切地說(shuō),我是需要對(duì)每個(gè)單詞的首字母進(jìn)行大小寫無(wú)關(guān)的匹配。
我寫了這樣的一個(gè)函數(shù),專門用來(lái)批量轉(zhuǎn)換。
復(fù)制代碼 代碼如下:
#convert regex to sorted list, then provide both lower/upper case for the first letter of each word
#luf means lower upper first
sub luf{
# split the regex with the delimiter |
my @arr=sort(split(/\|/,shift));
# provide both the upper and lower case for the
# first leffer of each word
foreach (@arr){s/\b([a-zA-Z])/[\l$1\u$1]/g;}
# join the keyword to a regex again
join('|',@arr);
}
print luf "sex pill|viagra|cialis|anti-ed";
# the output is:[aA]nti-[eE]d|[cC]ialis|[sS]ex [pP]ill|[vV]iagra
控制全局匹配下次開(kāi)始的位置
記得jyf曾經(jīng)問(wèn)過(guò)我,如何控制匹配開(kāi)始的位置。嗯,現(xiàn)在我可以回答這個(gè)問(wèn)題了。Perl 提供了 pos 函數(shù),可以在 /g 全局匹配中調(diào)整下次匹配開(kāi)始的位置。舉例如下:
復(fù)制代碼 代碼如下:
$_="abcdefg";
while(/../g)
{
print $;
}
其輸出結(jié)果是每?jī)蓚€(gè)字母,即ab, cd, ef
可以使用 pos($_)來(lái)重新定位下一次匹配開(kāi)始的位置,如:
復(fù)制代碼 代碼如下:
$_="abcdefg";
while(/../g)
{
pos($_)--; #pos($_)++;
print $;
}
輸出結(jié)果:
復(fù)制代碼 代碼如下:
pos($_)--: ab, bc, cd, de, ef, fg.
pos($_)++: ab, de.
可以閱讀 Perl 文檔中關(guān)于 pos的章節(jié)獲取詳細(xì)信息。
散列與正則表達(dá)式替換
《effective-perl-2e》第三章有這樣一個(gè)例子(見(jiàn)下面的代碼),將特殊符號(hào)轉(zhuǎn)義。
復(fù)制代碼 代碼如下:
my %ent = { '' => 'amp', '' => 'lt', '>' => 'gt' };
$html =~ s/([>])/$ent{$1};/g;
這個(gè)例子非常非常巧妙。它靈活地運(yùn)用了散列這種數(shù)據(jù)結(jié)構(gòu),將待替換的部分作為 key ,將與其對(duì)應(yīng)的替換內(nèi)容作為 value 。這樣只要有匹配就會(huì)捕獲,然后將捕獲的部分作為 key ,反查到 value 并運(yùn)用到替換中,體現(xiàn)了高級(jí)語(yǔ)言的效率。
不過(guò),這樣的 Perl 代碼,能否移植到 Python 中呢? Python 同樣支持正則,支持散列(Python 中叫做 Dictionary),但是似乎不支持在替換過(guò)程中插入太多花哨的東西(替換行內(nèi)變量?jī)?nèi)插)。
查閱 Python 的文檔,(在 shell 下 執(zhí)行 python ,然后 import re,然后 help(re)),:
復(fù)制代碼 代碼如下:
sub(pattern, repl, string, count=0)
Return the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in string by the
replacement repl. repl can be either a string or a callable;
if a string, backslash escapes in it are processed. If it is
a callable, it's passed the match object and must return
a replacement string to be used.
原來(lái) python 和 php 一樣,是支持在替換的過(guò)程中使用 callable 回調(diào)函數(shù)的。該函數(shù)的默認(rèn)參數(shù)是一個(gè)匹配對(duì)象變量。這樣一來(lái),問(wèn)題就簡(jiǎn)單了:
復(fù)制代碼 代碼如下:
ent={'':"lt",
'>':"gt",
'':"amp",
}
def rep(mo):
return ent[mo.group(1)]
html=re.sub(r"([>])",rep, html)
python 替換函數(shù) callback 的關(guān)鍵點(diǎn)在于其參數(shù)是一個(gè)匹配對(duì)象變量。只要明白了這一點(diǎn),查一下手冊(cè),看看該種對(duì)象都有哪些屬性,一一拿來(lái)使用,就能寫出靈活高效的 python 正則替換代碼。