2016-02-02 5 views
5

У меня есть строка и словарь, я должен заменить каждое вхождение ключа dict в этом тексте.Замена словаря на языке Python с пробелом в ключе

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

Если нет места в ключах, я разбить текст на слова и сравнить один за другим с Dict. Похоже, это заняло O (n). Но теперь у ключа есть пространство внутри, поэтому вещь более сложна. Пожалуйста, предложите мне хороший способ сделать это, и обратите внимание, что ключ может не совпадать с текстом.

Update

меня думать об этом решении, но не эффективно. O (м * п) или более ...

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

ответ

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) 
1

Если ключи не имеют пространства:

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

' '.join(output) 

Вы должны использовать DCT вместо Словаре поэтому не конфликтует со встроенной функцией dict()

Использует dictionary comprehension и ternary operator для фильтрации данных.

Если ключи действительно есть пробелы, вы правы:

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

И да, на этот раз сложность будет т * п, как вы должны перебирать строку каждый раз для каждого ключа в ДКП.

+0

Ключ имеет пространство, поэтому вы не можете разбить –

+0

строка replace не сработает, если у dict есть что-то вроде этого my_dict = {"google": "yahoo", "yahoo": "google"} и текст "google больше yahoo" –

0

Отбросьте все словарные клавиши и текст ввода на нижний регистр, поэтому сравнения просты. Теперь ...

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

Предполагается, что словарь достаточно мал, чтобы гарантировать соответствие. Если вместо этого словарь будет большим, а текст будет небольшим, вам нужно будет взять каждое слово, затем каждую двусловную фразу и посмотреть, находятся ли они в словаре.

Достаточно ли этого для вас?

+0

У дикта может быть 3 слова, 4 слова ... кто знает. И ваш алгоритм неэффективен. –

+0

Я считаю, что это ** O (n) ** для ограниченного числа слов. Если это ограничено только входной длиной, то это ** O (n^2) ** - но при назначении пунктуации, чтобы разбить фразы на входе, ** n ** также весьма ограничен. Является ли это приемлемым для вашей заявки? – Prune

+0

, если запись в тексте взяла больше, чем O (n), чтобы сравнить и для входа в мой dict взял еще один O (m), так что было бы O (n * m) –

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' 

Хотя вы, вероятно, хотите попробовать перестановки в обратном порядке, самый длинный первый, так еще определенные фразы имеют приоритет над отдельными словами.

+0

: o Вы могли бы объяснить сложность? Это очень похоже на меня. O (m^n) может быть @. @ –

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, если значение для замены одного элемента является частью термина поиска для другого элемента.

+0

string replace не будет работать, если у dict есть что-то вроде этого my_dict = {"google": "yahoo", "yahoo": "google"} и текст "google больше yahoo" –

+1

Как я отметил в ответе –

 Смежные вопросы

  • Нет связанных вопросов^_^