使用字典替换字符串,使用标点符号进行复杂化

时间:2012-12-11 05:43:29

标签: python dictionary replace punctuation

我正在尝试编写一个函数进程(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在原始字符串中完全停止。如果是这样,我如何忽略标点符号并获得ASAP替换?

7 个答案:

答案 0 :(得分: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()的版本不同,它会观察单词边界,因此不会替换碰巧出现在其他单词中间的缩写(例如“fetch”中的“etc”)。

此外,与目前为止提供的大多数(全部?)其他解决方案不同,它只对输入字符串进行一次迭代,无论字典中有多少搜索字词。

答案 1 :(得分:2)

您可以这样做:

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

答案 2 :(得分:2)

以下是一个有效的解决方案:使用re.split(),并按字边界分割(保留插页式字符):

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

此代码与Vaughn或Sheena的答案有一个显着不同之处在于此代码利用了字典的O(1)查找时间,而他们的解决方案则查看字典中的每个键。这意味着当s很短并且d非常大时,他们的代码运行时间会更长。此外,部分单词仍将在其解决方案中被替换:如果d = { "lol": "laugh out loud" }s="lollipop"他们的解决方案将错误地生成"laugh out loudlipop"

答案 3 :(得分: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匹配单词的开头或结尾。感谢Paul的评论

答案 4 :(得分:0)

不使用空格分割,而是使用:

split("\W")

它将被任何不属于单词的角色的任何东西分开。

答案 5 :(得分: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来匹配它,但这会从最终字符串中删除标点符号(因此,如果替换不是正则,那么正则表达式可能是最佳选项工作)。

答案 6 :(得分:0)

    python 3.2

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