Измените re.findall (регулярное выражение, текст) на nltk.Text.findall (регулярное выражение)

Используя Python и NLTK, я написал регулярное выражение для поиска слов, начинающихся с заглавной буквы в тексте, но не в начале предложения.

Первоначально я использовал его следующим образом:

[w for w in text if re.findall(r'(?<!\.\s)\b[A-Z][a-z]\b',w)]

переменный текст создается с использованием корпуса treebank следующим образом:

 >>> def concat(lists):
    biglist = [ ]
    while len(lists)>0:
        biglist = biglist+lists[0]
        lists=lists[1:]
    return biglist
>>> tbsents = concat(treebank.sents()[200:250])
>>> text = nltk.Text(tbsents)

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

>>> text.findall("<[A-Z][a-z]{3,}>")

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

Спасибо.


person egd    schedule 05.01.2012    source источник


Ответы (1)


Я не уверен, что вы делаете с первым пониманием списка: вы используете findall для каждого отдельного слова, не для самого текста.

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

import itertools
non_starting_words = list(itertools.chain(*[s[1:] for s in treebank.sents()]))
uppercase_words = [w for w in non_starting_words if w[0].isupper()]

Возможно, это то, что вы хотели сделать с помощью функции concat, но она просто получила список всех слов, а не удалила первое из каждого предложения. Если вы хотите объединить список списков, гораздо лучший способ — это list(itertools.chain(*lists)) то, что я сделал выше.

ETA: учитывая, что вам нужно работать со списком токенов, лучшим решением будет не использовать регулярные выражения, а:

punctuation_marks = ".!?"
first_word = True
uppercase_words = []

for w in text:
    if not first_word and re.match("[A-Z][a-z]*$", w):
        uppercase_words.append(w)
    first_word = w in punctuation_marks

print uppercase_words
person David Robinson    schedule 05.01.2012
comment
Да, я понял, что я сделал с первой строкой, но я включил ее, так как регулярное выражение работает так, как я хочу. К сожалению, функция concat и раздел text = nltk.text(tbsents) были предоставлены, и мне нужно найти имена собственные в переменной text. - person egd; 06.01.2012
comment
Я не понял, что это задание. Вы уверены, что ваша первая строка работает? Когда я точно воспроизвожу ваш код, я получаю ['Он', 'мистер', 'он', 'ко', 'мистер', 'он', 'он', 'так', «Мистер», «Мистер», «В»] в виде списка. - person David Robinson; 06.01.2012
comment
Вот как я это тестировал: ››› re.findall(r'(?‹!\.\s)\b[A-Z][a-z]*\b', Обезьяна была. Они любят Чика и Чопа. WOws и WOnt и WOOZ) ['Monkey', 'Chik', 'Chop'] - person egd; 06.01.2012
comment
В этом тесте вы применяете его ко всему предложению. В коде в вашем вопросе вы применяете его к каждому отдельному слову - есть огромная разница. - person David Robinson; 06.01.2012
comment
Это то, что я понял, поэтому я подумал, что сделаю это, используя второй метод с text.findall(), но делает ли это то же самое? - person egd; 06.01.2012
comment
Это не так по нескольким причинам. NLTK.findall() — очень плохая функция, поскольку она даже ничего не возвращает, а просто выводит слова. Это также заставляет вас использовать ‹ для ваших токенов. Я добавил гораздо лучшее решение выше. - person David Robinson; 06.01.2012
comment
list(itertools.chain(*[s[1:] for s in treebank.sents()])) можно выразить проще как [w for s in treebank.sents() for w in s[1:]]. - person Kirill Bulygin; 08.01.2017