2012-12-11 88 views
2

我正在嘗試編寫一個函數過程(s,d),用字典替換字符串中的縮寫和完整含義。其中s是字符串輸入,d是字典。例如:字符串替換字典,與標點符號併發

>>>d = {'ASAP':'as soon as possible'} 
>>>s = "I will do this ASAP. Regards, X" 
>>>process(s,d) 
>>>"I will do this as soon as possible. Regards, X" 

我已經嘗試使用split函數來分隔字符串並將每個部分與字典進行比較。

def process(s): 
    return ''.join(d[ch] if ch in d else ch for ch in s) 

但是,它返回同樣的確切字符串。我懷疑代碼不起作用,因爲原始字符串中的ASAP完全停止。如果是這樣,我該如何忽略標點並儘快更換?

回答

0

而是用空格分割的,可以使用:

split("\W") 

它將由任何非這將是一個單詞的一部分字符分割。

1

使用正則表達式:

re.sub(pattern,replacement,s) 

在您的應用程序:

ret = s 
for key in d: 
    ret = re.sub(r'\b'+key+r'\b',d[key],ret) 
return ret 

\ b詞的開頭或結尾匹配。感謝保羅的評論

+1

查看我對Vaughn Cato的評論,感謝剛剛迭代d的弱點。或者,由於您使用的是正則表達式,因此您可以跳過該類並將代碼更改爲'ret = re.sub(r'\ b'+ key + r'\ b',d [key],ret)',這樣你不會無意中更換較大的縮寫詞。 – PaulMcG

2

你可以做這樣的事情:

def process(s,d): 
    for key in d: 
     s = s.replace(key,d[key]) 
    return s 
+0

一個問題 - 如果'AS'和'ASAP'都是d中的鍵,那麼可能會首先評估'AS',但是錯誤地替換源文本中'ASAP'的前導'AS'。我認爲你需要稍微修改這段代碼,以便按照密鑰長度的相反順序來遍歷d,通過改變'for key in d' to'for key in sorted(d,key = lambda x:len(x ),reverse = True):'。 – PaulMcG

0

這是字符串替換,以及(+1至@VaughnCato)。這使用reduce函數遍歷字典,用值替換字符串中任何鍵的實例。在這種情況下,s是累加器,其在每次迭代中被減少(即饋送到替換函數),保持所有過去的替換(同樣,根據上述@ PaulMcGuire的觀點,這將替換從最長開始並以最短結束的密鑰)。

In [1]: d = {'ASAP':'as soon as possible', 'AFAIK': 'as far as I know'} 

In [2]: s = 'I will do this ASAP, AFAIK. Regards, X' 

In [3]: reduce(lambda x, y: x.replace(y, d[y]), sorted(d, key=lambda i: len(i), reverse=True), s) 
Out[3]: 'I will do this as soon as possible, as far as I know. Regards, X' 

至於爲什麼你的函數沒有返回你所期望的 - 不是的話 - 當你通過迭代s,你實際上是通過字符的字符串迭代。你的版本可以通過迭代s.split()(這將是一個單詞列表)來調整,但是你會遇到標點符號導致單詞不符合你的字典的問題。您可以通過導入string並從每個單詞中除去string.punctuation來匹配它,但這會從最終字符串中刪除標點符號(因此,如果替換不起作用,正則表達式可能是最佳選擇)。

+0

您可以使用'word.strip(string.punctuation)'進行比較,但可以使用'word'進行操作。 –

+0

@BrendenBrown這就是我剛開始玩的時候,但我找不到一個'知道'被剝離出來的好方法(因爲你必須從字典中取出被剝離的字符串,但需要以某種方式用你剝離的標點符號重新加入)。然而,我不是專家,所以我絕對可以忽略一些東西:) – RocketDonkey

2

這裏是一個有效的解決方案:使用re.split()和拆分的單詞邊界(保留間質性字符):

''.join(d.get(word, word) for word in re.split('(\W+)', s)) 

一個顯著的差異,該代碼從沃恩的擁有或希娜的回答是,這個代碼利用O(1)查找時間的字典,而他們的解決方案將查看字典中的每個關鍵字。這意味着當s較短且d非常大時,它們的代碼將花費較長的時間運行。此外,部分文字仍將在其解決方案中被替換:如果d = { "lol": "laugh out loud" }s="lollipop"其解決方案將錯誤地生成"laugh out loudlipop"

0
python 3.2 

    [s.replace(i,v) for i,v in d.items()] 
5

這是一種用單個正則表達式來做到這一點:

In [24]: d = {'ASAP':'as soon as possible', 'AFAIK': 'as far as I know'} 

In [25]: s = 'I will do this ASAP, AFAIK. Regards, X' 

In [26]: re.sub(r'\b' + '|'.join(d.keys()) + r'\b', lambda m: d[m.group(0)], s) 
Out[26]: 'I will do this as soon as possible, as far as I know. Regards, X' 

與基於str.replace()版本,這個觀察單詞邊界,因此不會取代碰巧出現在中間的縮寫(例如「取」中的「etc」)。

此外,與目前爲止所介紹的大多數(所有?)其他解決方案不同,它只是對輸入字符串進行一次迭代,而不管字典中有多少個搜索項。

+0

+1 - 有關縮寫換句話的絕佳之處(沒有想到:)) – RocketDonkey

+0

這個解決方案的一個問題是,它仍然有O (dictLength * stringLength)的複雜性,因爲它使用正則表達式中的所有字典的鍵。通過遍歷字符串中的單詞,並檢查它們是否存在於字典中,您只需對字符串進行一次迭代,在輸入邊界中尊重單詞,並且具有O(stringLength)複雜性(請參閱下面的答案) –

+0

@RyanMadsen:這就是不正確。使用任何half-decent正則表達式引擎,匹配此表單的正則表達式的代價與「OR」條款的數量無關。我推薦http://en.wikipedia.org/wiki/Formal_grammar#Regular_grammars及其鏈接。 – NPE