2012-12-11 39 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