2013-09-22 2 views
2

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

import re 

noun_list = ['bacon', 'cheese', 'eggs', 'milk', 'list', 'dog'] 
CC_list = ['and', 'or'] 

noun_list_pattern1 = r'\b\w+\b,\s\b\w+\b,\sand\s\b\w+\b|\b\w+\b,\s\b\w+\b,\sor\s\b\w+\b|\b\w+\b,\s\b\w+\b\sand\s\b\w+\b|\b\w+\b,\s\b\w+\b,\saor\s\b\w+\b' 

with open('test_sentence.txt', 'r') as input_f: 
    read_input = input_f.read() 
    word = re.findall(noun_list_pattern1, read_input) 
    for w in word: 
     print w 
else: 
    pass 

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

Ограничение с помощью регулярного выражения состоит в том, что код \b\w+\w\, который содержится несколько раз в `noun_list_pattern ', фактически находит слова - любые слова - но не конкретные существительные. Это может вызвать ложные срабатывания. Я хочу еще больше сузить вещи, используя элементы в списке выше, а не в регулярном выражении.

Так как у меня на самом деле есть 4 разных регулярных выражения в шаблоне регулярных выражений (он содержит 4 |), я просто отправлюсь с 1 из них здесь. Таким образом, я должен был бы найти модель, такие как:

'noun in noun_list' + ', ' + 'noun in noun_list' + ', ' + 'C in CC_list' + ' ' + 'noun in noun_list

Очевидно, что приведенный выше код цитировал строки не реальный код питона, но это experession моих мыслей о матче необходимо. Где я говорю noun in noun_list Я имею в виду итерацию через noun_list; C in CC_list - итерация через CC_list; , - это буквальное совпадение строк для запятой и пробелов.

Надеюсь, я убедился!

Вот содержимое файла test_sentence.txt, что я использую:

I need to buy are bacon, cheese and eggs. 
I also need to buy milk, cheese, and bacon. 
What's your favorite: milk, cheese or eggs. 
What's my favorite: milk, bacon, or eggs. 
+0

Не могли бы вы разместить пример данных, которые вы хотите найти, пожалуйста? – jrd1

+0

упс! да будет, забыл об этом. –

+2

Вы пытаетесь проанализировать структуру каждого предложения и сгруппировать аналоги? Если да, вы можете попробовать библиотеку nltk: http://nltk.org/ У них также есть хорошо написанный бесплатный документ (поставляется в виде книги) в качестве руководства для начинающих. – Mai

ответ

2

Разбейте вашу проблему немного вниз. Во-первых, вам нужен шаблон, который будет соответствовать словам из вашего списка, но никому другому. Вы можете выполнить это с помощью оператора чередования | и буквальных слов. red|green|blue, например, будет соответствовать "red", "green", или "blue", но не "purple". Регистрация списка существительного с этим персонажем, и добавить слово краевых метасимволов со скобками для группы чередований:

noun_patt = r'\b(' + '|'.join(nouns) + r')\b' 

сделать то же самое для вашего списка конъюнкций:

conj_patt = r'\b(' + '|'.join(conjunctions) + r')\b' 

В целом матч вы хотите сделать «один или несколько совпадений noun_patt, каждый из которых может сопровождаться запятой, после чего следует соответствие для conj_patt, а затем еще один noun_patt совпадение». Легко достаточно для регулярных выражений:

patt = r'({0},?)+{1} {0}'.format(noun_patt, conj_patt) 

Вы действительно не хотите использовать re.findall(), но re.search(), так как вы ожидаете только один матч в каждой строке:

for line in lines: 
...  print re.search(patt, line).group(0) 
... 
bacon, cheese and eggs 
milk, cheese, and bacon 
milk, cheese or eggs 
milk, bacon, or eggs 

Как примечание, вы» re близко к, если не потирать, пределы регулярных выражений, поскольку синтаксический анализ английского языка. Все более сложное, чем это, и вы захотите изучить фактический синтаксический анализ, возможно, с помощью NLTK.

+0

Спасибо Josh =) Это прекрасно. Как newb я не знал о методе '.format', очень полезен. Я также изучил некоторые аккуратные вещи из того, как вы форматировали регулярное выражение для списков noun_patt и conj_patt. Поскольку мне может потребоваться больше одного совпадения в каждой строке (или целого файла) в зависимости от того, как я читаю файл, то я могу немного поиграть с 're.findall()' и 're.search() ', чтобы получить то, что я необходимо для любой ситуации. Этот подход с регулярным выражением будет очень полезен для других подобных вещей, которые мне нужны. Еще раз спасибо =) –

+0

Джош, мне также интересно, не возражаете ли вы объяснить мне расположение скобок в 'noun_patt' и' conj_patt'? Я попытался взглянуть на документы, но не мог понять. Мое понимание заключалось в том, что скобки в регулярном выражении вернули эту часть совпадения, так же как и код, не возвращающий '\ b', который сидит вне скобки? Также мне интересно, как скобки располагаются между двумя одинарными кавычками, такими как сегменты 'r '\ b ('' и '') \ b'' в списке' noun_patt'. Это похоже на скобку «крючок» между одинарными кавычками –

+0

1 еще вещь =) Я пробовал этот скрипт, открывая текстовый файл с помощью метода '.read()', используя функцию 're.findall()' follow по циклу for для печати каждого «найти», если «re.findall()». В результате получилось немного, но близко. По какой-то причине мы получаем дублирующее существительное, первую печатную строку: '('cheese', 'cheese', 'and', 'eggs')'. Мы получаем 2 варианта «сыра» - с и без заднего пространства. Другие печатные строки следуют в одном костюме. Не знаете, почему использование метода '.read()' изменяет соответствие регулярного выражения? Я немного играл с регулярным выражением, чтобы не было желаемого результата. –

2

На самом деле вам не обязательно нужны регулярные выражения, так как существует несколько способов сделать это, используя только ваши исходные списки.

noun_list = ['bacon', 'cheese', 'eggs', 'milk', 'list', 'dog'] 
conjunctions = ['and', 'or'] 

#This assumes that file has been read into a list of newline delimited lines called `rawlines` 
for line in rawlines: 
    matches = [noun for noun in noun_list if noun in line] + [conj for conj in conjunctions if conj in line] 
    if len(matches) == 4: 
     for match in matches: 
      print match 

Причина, по которой номер матча равен 4, состоит в том, что 4 - правильное количество совпадений. (Обратите внимание, что это также может иметь место для повторных существительных или союзов).

EDIT:

Эта версия печатает строки, которые подбираются и слова совпавшие. Также исправлена ​​возможная множественная проблема соответствия слова:

words_matched = [] 
matching_lines = [] 

for l in lst: 
    matches = [noun for noun in noun_list if noun in l] + [conj for conj in conjunctions if conj in l] 
    invalid = True 
    valid_count = 0 
    for match in matches: 
     if matches.count(match) == 1: 
      valid_count += 1 
    if valid_count == len(matches): 
     invalid = False 

    if not invalid: 
     words_matched.append(matches) 
     matching_lines.append(l) 

for line, matches in zip(matching_lines, words_matched): 
    print line, matches 

Однако, если это вас не устраивает, вы всегда можете построить регулярное выражение следующим образом (с помощью itertools модуля):

#The number of permutations choices is 3 (as revealed from your examples) 
for nouns, conj in itertools.product(itertools.permutations(noun_list, 3), conjunctions): 
    matches = [noun for noun in nouns] 
    matches.append(conj) 
    #matches[:2] is the sublist containing the first 2 items, -1 is the last element, and matches[2:-1] is the element before the last element (if the number of nouns were more than 3, this would be the elements between the 2nd and last). 
    regex_string = '\s,\s'.join(matches[:2]) + '\s' + matches[-1] + '\s' + '\s,\s'.join(matches[2:-1]) 
    print regex_string 
    #... do regex related matching here 

Оговорки из этого метода заключается в том, что он является чистой грубой силой, поскольку он генерирует все возможные комбинации (считывание перестановок) обоих списков, которые затем могут быть протестированы, чтобы увидеть, соответствует ли каждая строка. Следовательно, он ужасно медленный, но в этом примере, который соответствует указанным (не запятая перед конъюнкцией), этот точно сгенерирует точные соответствия.

Адаптировать при необходимости.

+0

Спасибо за предоставление 2 подробных ответов, я ценю помощь. Я просто попытался ваш первый код, тот, который не использует регулярное выражение, и он печатает это: '' bacon' cheese' 'eggs' ' 'and' bacon' ' 'cheese' milk' '' and' cheese' 'eggs' ' 'milk' or' ' 'bacon' eggs' ' 'milk' or' Каждый из этих слов печатаются на новой строке. То, что я искал, это «бекон, сыр и яйца» на одной линии в качестве первого совпадения, затем «молоко, сыр и бекон» на следующей строке и т. Д. –

+0

(Также интересно, что вы используете функции перестановок itertools У меня есть привязка к моим долгосрочным целям для этого скрипта, в котором я создаю все перестановки и использую их для замены совпадений. Но это еще один день!) –

+0

@ Darren: Так я его реализовал, так как я интерпретировал его из вашего оригинал вопрос. Выводимый вами результат - это слова, которые встречаются в каждой строке как из 'nouns_list', так и в' conjunctions'. Это было главным образом для проверки результатов. Логика, которую я использовал, заключалась в том, что если бы эти слова были в строке (число 4), то это совпадение - что вы хотели, правильно? Или, к сожалению, я неверно истолковал ваш вопрос? – jrd1

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