Python字典替换密钥中的空格

时间:2016-02-02 01:55:29

标签: python algorithm dictionary replace textmatching

我有一个字符串和一个字典,我必须替换该文本中每次出现的dict键。

text = 'I have a smartphone and a Smart TV'
dict = {
    'smartphone': 'toy',
    'smart tv': 'junk'
}

如果按键中没有空格,我会将文字分成单词并逐一用dict 进行比较。看起来像是 O(n)。但现在钥匙内部有空间,所以事情更加复杂。请建议我这样做的好方法,请注意密钥可能与案文不匹配。

更新

我已经考虑过这个解决方案,但效率不高。 O(m * n)或更多......

for k,v in dict.iteritems():
    text = text.replace(k,v) #or regex...

5 个答案:

答案 0 :(得分:1)

如果你的钥匙没有空格:

output = [dct[i] if i in dct else i for i in text.split()]

' '.join(output)

您应该使用dct而不是dict,这样它就不会与内置函数dict()碰撞

这会使用dictionary comprehensionternary operator 过滤数据。

如果你的钥匙有空格,那你就是对的:

for k,v in dct.iteritems():
    string.replace('d', dct[d])

是的,这个时间复杂度将是m * n,因为你必须每次为dct中的每个键迭代字符串。

答案 1 :(得分:1)

如果文本中的关键词彼此不相关(关键字其他关键字),我们可能会这样做。取O(n)给我>“<

def dict_replace(dictionary, text, strip_chars=None, replace_func=None):
    """
        Replace word or word phrase in text with keyword in dictionary.

        Arguments:
            dictionary: dict with key:value, key should be in lower case
            text: string to replace
            strip_chars: string contain character to be strip out of each word
            replace_func: function if exist will transform final replacement.
                          Must have 2 params as key and value

        Return:
            string

        Example:
            my_dict = {
                "hello": "hallo",
                "hallo": "hello",    # Only one pass, don't worry
                "smart tv": "http://google.com?q=smart+tv"
            }
            dict_replace(my_dict, "hello google smart tv",
                         replace_func=lambda k,v: '[%s](%s)'%(k,v))
    """

    # First break word phrase in dictionary into single word
    dictionary = dictionary.copy()
    for key in dictionary.keys():
        if ' ' in key:
            key_parts = key.split()
            for part in key_parts:
                # Mark single word with False
                if part not in dictionary:
                    dictionary[part] = False

    # Break text into words and compare one by one
    result = []
    words = text.split()
    words.append('')
    last_match = ''     # Last keyword (lower) match
    original = ''       # Last match in original
    for word in words:
        key_word = word.lower().strip(strip_chars) if \
                   strip_chars is not None else word.lower()
        if key_word in dictionary:
            last_match = last_match + ' ' + key_word if \
                         last_match != '' else key_word
            original = original + ' ' + word if \
                       original != '' else word
        else:
            if last_match != '':
                # If match whole word
                if last_match in dictionary and dictionary[last_match] != False:
                    if replace_func is not None:
                        result.append(replace_func(original, dictionary[last_match]))
                    else:
                        result.append(dictionary[last_match])
                else:
                    # Only match partial of keyword
                    match_parts = last_match.split(' ')
                    match_original = original.split(' ')
                    for i in xrange(0, len(match_parts)):
                        if match_parts[i] in dictionary and \
                           dictionary[match_parts[i]] != False:
                            if replace_func is not None:
                                result.append(replace_func(match_original[i], dictionary[match_parts[i]]))
                            else:
                                result.append(dictionary[match_parts[i]])
            result.append(word)
            last_match = ''
            original = ''

    return ' '.join(result)

答案 2 :(得分:0)

将所有字典键和输入文本删除为小写,因此比较很容易。现在......

for entry in my_dict:
    if entry in text:
        # process the match

这假定字典足够小以保证匹配。相反,如果字典很大且文字较小,则您需要记下每个单词,然后是每个双字短语,并查看它们是否在字典中。

这足以让你前进吗?

答案 3 :(得分:0)

您需要测试从1(每个单词)到len(文本)(整个字符串)的所有邻居排列。您可以通过以下方式生成邻居排列:

text = 'I have a smartphone and a Smart TV'

array = text.lower().split()

key_permutations = [" ".join(array[j:j + i]) for i in range(1, len(array) + 1) for j in range(0, len(array) - (i - 1))]

>>> key_permutations
['i', 'have', 'a', 'smartphone', 'and', 'a', 'smart', 'tv', 'i have', 'have a', 'a smartphone', 'smartphone and', 'and a', 'a smart', 'smart tv', 'i have a', 'have a smartphone', 'a smartphone and', 'smartphone and a', 'and a smart', 'a smart tv', 'i have a smartphone', 'have a smartphone and', 'a smartphone and a', 'smartphone and a smart', 'and a smart tv', 'i have a smartphone and', 'have a smartphone and a', 'a smartphone and a smart', 'smartphone and a smart tv', 'i have a smartphone and a', 'have a smartphone and a smart', 'a smartphone and a smart tv', 'i have a smartphone and a smart', 'have a smartphone and a smart tv', 'i have a smartphone and a smart tv']

现在我们通过字典替换:

import re

for permutation in key_permutations:
    if permutation in dict:
        text = re.sub(re.escape(permutation), dict[permutation], text, flags=re.IGNORECASE)

>>> text
'I have a toy and a junk'

虽然您可能希望以相反的顺序尝试排列,但最先使用最长的排列,因此更具体的短语优先于单个单词。

答案 4 :(得分:0)

您可以使用正则表达式轻松完成此操作。

import re

text = 'I have a smartphone and a Smart TV'
dict = {
    'smartphone': 'toy',
    'smart tv': 'junk'
}

for k, v in dict.iteritems():
    regex = re.compile(re.escape(k), flags=re.I)
    text = regex.sub(v, text)

如果一个项目的替换值是另一个项目的搜索词的一部分,它仍然存在依赖于dict键的处理顺序的问题。