如何使用字典进行多次搜索和替换操作?

96

我需要在地址字段中替换类似于“north”、“south”等的文本为“N”、“S”等。我想过用字典来保存要替换的内容。假设我们有:

replacements = {'NORTH':'N','SOUTH':'S','EAST':'E','WEST':'W'}
address = "123 north anywhere street"

我可以使用replacements字典来进行所有替换,例如通过迭代它吗?这样做的代码是什么样子?


3
如果匹配可以重叠,这就相当棘手。参见这个问题 - georg
问题的一个很大的部分是,字符串replace()方法会返回一个替换了出现次数的字符串的副本 - 它不会原地进行替换。 - martineau
4
你可以简单地使用str.translate - Neel Patel
3
请查看以下链接以获取最佳解决方案:https://dev59.com/5HE95IYBdhLWcg3wOLU1 - Ethan Bradford
经过审核:在删除代码尝试后(由于存在多个问题,几乎可以视为伪代码;而且并没有帮助理解问题,因为这显然是一个如何问题,而不是一个调试问题),很明显这是@EthanBradford找到的问题的重复。即使在我的编辑之后,我认为另一个问题(及其答案)总体上更高质量,所以我将其关闭为重复。 - Karl Knechtel
13个回答

1

所有这些答案都很好,但是你错过了Python字符串替换 - 它简单而快速,但需要正确格式化你的字符串。

address = "123 %(direction)s anywhere street"
print(address % {"direction": "N"})

不能使用'score: 99.5% name:%(name)s' %{'name':'foo'} - ahuigo
假设我们控制了要进行替换的字符串;也就是说,我们正在创建一些模板以填充值。但是,OP的问题似乎特别涉及清理格式错误的数据。如果我们可以手动编辑输入以使其具有%样式占位符,则我们也可以直接编辑替换内容。 - Karl Knechtel
可能想要在现代 Python(3.7+)中使用 f-strings。 - hobs

1
处理这个问题更快的方法是尊重单词边界,并且仅查找每个标记一次。
token_mapping = {
    'north': 'N', 'south': 'S', 
    'east': 'E', 'west': 'W'
    'street': 'St',
    }

def tokenize(text):
    return text.lower().split()

def detokenize(tokens):
    return ' '.join(tokens)

def replace_tokens(text, token_mapping=token_mapping):
    input_tokens = tokenize(text)
    output_tokens = []
    for tok in input_tokens:
        output_tokens.append(token_mapping.get(tok, tok))
    return detokenize(output_tokens)

>>> replace_tokens("123 north anywhere street")
'123 N anywhere St'

这种方法的另一个优点是,您可以根据需要折叠单个标记的情况:
def detokenize(tokens):
    return ' '.join([t.title() for t in tokens])

>>> replace_tokens("123 north anywhere street")
'123 N Anywhere St'

这是网络规模自然语言处理的方法,包括拼写纠正器缩写扩展器/收缩器

0
Duncan的方法的优点在于它小心地不会覆盖以前的答案。例如,如果您有{"Shirt": "Tank Top", "Top": "Sweater"},其他方法将用"Tank Sweater"替换"Shirt"。
以下代码扩展了该方法,但对键进行排序,以便始终先找到最长的键,并使用命名组进行不区分大小写的搜索。
import re
root_synonyms = {'NORTH':'N','SOUTH':'S','EAST':'E','WEST':'W'}
# put the longest search term first. This menas the system does not replace "top" before "tank top"
synonym_keys = sorted(root_synonyms.keys(),key=len,reverse=True)
# the groups will be named w1, w2, ... . Determine what each of them should become
number_mapping = {f'w{i}':root_synonyms[key] for i,key in enumerate(synonym_keys) }
# make a regex for each word where "tank top" or "tank  top" are the same
search_terms = [re.sub(r'\s+',r'\s+',re.escape(k)) for k in synonym_keys]
# give each search term a name w1 etc where
search_terms = [f'(?P<w{i}>\\b{key}\\b)' for i,key in enumerate(search_terms)]
# make one huge regex
search_terms = '|'.join(search_terms)
# compile it for speed
search_re = re.compile(search_terms,re.IGNORECASE)

query = "123 north anywhere street"
result = re.sub(search_re,lambda x: number_mapping[x.lastgroup],query)
print(result)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接