2016-09-07 3 views
4

У меня есть предложение, скажем:Как можно отменить части предложения в python?

Быстрая коричневая лиса перепрыгивает через ленивую собаку

Я хочу создать функцию, которая принимает 2 аргумента, предложение и список вещей, чтобы игнорировать. И он возвращает это предложение с обратными словами, однако он должен игнорировать материал, который я передаю ему во втором аргументе. Это то, что я имею на данный момент:

def main(sentence, ignores): 
    return ' '.join(word[::-1] if word not in ignores else word for word in sentence.split()) 

Но это будет работать только тогда, когда я прохожу второй список, как так:

print(main('The quick brown fox jumps over the lazy dog', ['quick', 'lazy'])) 

Однако, я хочу, чтобы передать список, как это:

print(main('The quick brown fox jumps over the lazy dog', ['quick brown', 'lazy dog'])) 

ожидаемый результат: ehT quick brown xof spmuj revo eht lazy dog

Поэтому в основном второй аргумент (список) будет содержать части предложения, которые следует игнорировать. Не только отдельные слова.

Должен ли я использовать regexp для этого? Я пытался избежать ...

+0

Вы не обращая внимания на слова или полную фразу? –

+0

Я пытаюсь игнорировать полные фразы. – Bravi

+0

Итак, если коричневый появился позже, то не сразу после него его нужно отменить? –

ответ

0

Вместо заполнителей, почему не только изначально реверса любой фразы, которую вы хотите быть вокруг правого пути, а затем реверсировать всю строку:

def main(sentence, ignores): 
    for phrase in ignores: 
     reversed_phrase = ' '.join([word[::-1] for word in phrase.split()]) 
     sentence = sentence.replace(phrase, reversed_phrase) 

    return ' '.join(word[::-1] for word in sentence.split()) 

print(main('The quick brown fox jumps over the lazy dog', ['quick', 'lazy'])) 
print(main('The quick brown fox jumps over the lazy dog', ['quick brown', 'lazy dog'])) 

возвращается:

ehT quick nworb xof spmuj revo eht lazy god 
ehT quick brown xof spmuj revo eht lazy dog 
+0

Что делать, если у вас есть '['lazy dog', 'quick brown']'? – furas

+0

Это не плохая идея, но для этого требуется, чтобы «список» фраз оставался неизменным, соответствовал структуре предложения в обоих числах повторений (не может игнорировать все экземпляры фразы, всего по одному) и order ('ignores' должен точно соответствовать порядку, указанному в предложении). – ShadowRanger

+0

Я думаю, что вы можете сначала найти индекс, что каждая фраза найдена в предложении, а затем сортировка игнорирует этот индекс, а затем выполняет замену. – SuperShoot

0

Я первый человек, рекомендуем избегать регулярных выражений, но в этом случае сложность делать не больше, чем сложность добавленной их с помощью:

import re 

def main(sentence, ignores): 
    # Dedup and allow fast lookup for determining whether to reverse a component 
    ignores = frozenset(ignores) 

    # Make a pattern that will prefer matching the ignore phrases, but 
    # otherwise matches each space and non-space run (so nothing is dropped) 
    # Alternations match the first pattern by preference, so you'll match 
    # the ignores phrases if possible, and general space/non-space patterns 
    # otherwise 
    pat = r'|'.join(map(re.escape, ignores)) + r'|\S+|\s+' 

    # Returns the chopped up pieces (space and non-space runs, but ignore phrases stay together 
    parts = re.findall(pat, sentence) 

    # Reverse everything not found in ignores and then put it all back together 
    return ''.join(p if p in ignores else p[::-1] for p in parts) 
+0

Почему 'frozenset' вместо просто' set'? –

+0

@StefanPochmann: Абсолютно никаких причин, кроме того, что мы не будем изменять его позже. На практике я не думаю, что это имеет значение (текущие версии Python не выполняют специальных оптимизаций для 'frozenset', внутренние структуры для' set' и 'frozenset' идентичны, поэтому, если вы никогда не мутируете это, единственная разница подходит для использования в качестве ключа 'dict' или' set'), но я использую 'frozenset', когда он не предназначен для мутирования; ничего не стоит, всегда можно изменить, если это необходимо. Если фразы могут быть подфазами друг друга, вам нужно, чтобы 'collections.OrderedDict' сохранял порядок. – ShadowRanger

+0

Это довольно чистый и читаемый, я просто пытался избежать использования регулярного выражения. – Bravi

0

Просто еще одна идеи, реверс каждое слова, а затем поменять местами игнорирования обратно:

>>> from functools import reduce 
>>> def main(sentence, ignores): 
     def r(s): 
      return ' '.join(w[::-1] for w in s.split()) 
     return reduce(lambda s, i: s.replace(r(i), i), ignores, r(sentence)) 

>>> main('The quick brown fox jumps over the lazy dog', ['quick brown', 'lazy dog']) 
'ehT quick brown xof spmuj revo eht lazy dog' 
+0

Не думаю, что вы могли бы сделать его менее читаемым;) –

+1

@PadraicCunningham Вы недооцениваете меня. Как насчет, например, переименования 'r' и всех его переменных в' _'? То есть 'def _ (_): return '. .join (_ [:: - 1] для _ in _.split())'? –

0

Я попытался решить проблему перекрывающихся игнорировать фразы, например, ['brown fox', 'quick brown'] поднят @PadraicCunningham.

Очевидно, что гораздо больше циклов, и код чувствует себя менее питоническим, поэтому мне будет интересно узнать, как улучшить это.

import re 

def _span_combiner(spans): 
    """replace overlapping spans with encompasing single span""" 
    for i, s in enumerate(spans): 
     start = s[0] 
     end = s[1] 
     for x in spans[i:]: 
      if x[0] < end: 
       end = x[1] 
     yield (start, end) 

def main(sentence, ignores): 
    # spans is a start and finish indices for each ignore phrase in order of occurence 
    spans = sorted(
      [[m.span() for m in re.finditer(p, sentence)][0] for p in ignores if p in sentence] 
    ) 
    # replace overlapping indices with single set of indices encompasing overlapped range 
    spans = [s for s in _span_combiner(spans)] 
    # recreate ignore list by slicing sentence with combined spans 
    ignores = [sentence[s[0]:s[1]] for s in spans] 
    for phrase in ignores: 
     reversed_phrase = ' '.join([word[::-1] for word in phrase.split()]) 
     sentence = sentence.replace(phrase, reversed_phrase) 

    return ' '.join(word[::-1] for word in sentence.split()) 

if __name__ == "__main__": 
    print(main('The quick brown fox jumps over the lazy dog', ['quick', 'lazy'])) 
    print(main('The quick brown fox jumps over the lazy dog', ['brown fox', 'lazy dog'])) 
    print(main('The quick brown fox jumps over the lazy dog', ['nonexistent' ,'brown fox', 'quick brown'])) 
    print(main('The quick brown fox jumps over the brown fox', ['brown fox', 'quick brown'])) 

результаты:

ehT quick nworb xof spmuj revo eht lazy god 
ehT kciuq brown fox spmuj revo eht lazy dog 
ehT quick brown fox spmuj revo eht yzal god 
ehT quick brown fox spmuj revo eht brown fox 
Смежные вопросы