Разбиение строки на слова и знаки препинания

Я пытаюсь разбить строку на слова и знаки препинания, добавляя знаки препинания в список, созданный разделением.

Например:

>>> c = "help, me"
>>> print c.split()
['help,', 'me']

Я действительно хочу, чтобы список выглядел так:

['help', ',', 'me']

Итак, я хочу, чтобы строка была разделена пробелами с пунктуацией из слов.

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

>>> for character in c:
...     if character in ".,;!?":
...             outputCharacter = " %s" % character
...     else:
...             outputCharacter = character
...     separatedPunctuation += outputCharacter
>>> print separatedPunctuation
help , me
>>> print separatedPunctuation.split()
['help', ',', 'me']

Это дает желаемый результат, но мучительно медленно на больших файлах.

Есть ли способ сделать это более эффективно?

14.12.2008 23:30:33
Для этого примера (не общего случая)c.replace(' ','').partition(',')
Chris_Rands 21.11.2016 08:59:51
12 ОТВЕТОВ
РЕШЕНИЕ

Это более или менее способ сделать это:

>>> import re
>>> re.findall(r"[\w']+|[.,!?;]", "Hello, I'm a string!")
['Hello', ',', "I'm", 'a', 'string', '!']

Хитрость в том, чтобы не думать о том, где разбить строку, а о том, что включить в токены.

Предостережения:

  • Подчеркивание (_) считается символом внутреннего слова. Замените \ w, если вы этого не хотите.
  • Это не будет работать с (одинарными) кавычками в строке.
  • Поместите любые дополнительные знаки препинания, которые вы хотите использовать, в правую половину регулярного выражения.
  • Все, что явно не упомянуто в ре, молча отбрасывается.
85
19.08.2011 23:01:27
Если вы хотите разбить на ЛЮБУЮ пунктуацию, в том числе ', попробуйте re.findall(r"[\w]+|[^\s\w]", "Hello, I'm a string!"). В результате ['Hello', ',', 'I', "'", 'm', 'a', 'string', '!'] обратите внимание также, что цифры включены в слово соответствия.
Codie CodeMonkey 15.05.2012 08:21:00
Сожалею! Не могли бы вы объяснить, как именно это работает?
Curious 5.02.2016 02:36:09
@ Любопытно: если честно, нет, я не могу. Потому что, с чего мне начать? Что ты знаешь? Какая часть является проблемой для вас? Чего ты хочешь достичь?
user3850 5.02.2016 19:01:27
Ничего! Я сам это понял! Спасибо за ответ :)
Curious 5.02.2016 20:39:05

Вы пытались использовать регулярные выражения?

http://docs.python.org/library/re.html#re-syntax


Кстати. Зачем вам "," на втором? Вы будете знать, что после написания каждого текста

[0]

""

[1]

""

Поэтому, если вы хотите добавить «,», вы можете просто сделать это после каждой итерации, когда используете массив.

-1
14.12.2008 23:34:49

В синтаксисе регулярных выражений в стиле perl \bсоответствует границе слова. Это должно пригодиться для деления на основе регулярных выражений.

edit: мне сообщили, что "пустые совпадения" не работают в функции split модуля re Python. Я оставлю это здесь в качестве информации для тех, кто еще кого-то озадачил этой «функцией».

5
15.12.2008 09:41:13
Какого черта? Это ошибка в re.split? В Perl split /\b\s*/работает без проблем.
Svante 15.12.2008 01:29:34
это как-то задокументировано, что re.split () не будет разбиваться на пустые совпадения ... так что нет, не / действительно / ошибка.
user3850 15.12.2008 01:51:26
"вид документально"? Даже если это действительно задокументировано, это все равно бесполезно, так что я предполагаю, что это фактически функция redeclared от ошибок.
Svante 15.12.2008 02:08:28
может быть. я не знаю обоснование этого. Вы должны были проверить, работало ли это в любом случае! я больше не могу удалить понижающий голос, но, пожалуйста, подумайте над переписыванием пассивно-агрессивного редактирования - никому не поможет.
user3850 15.12.2008 09:16:08
Это не ответ на вопрос.
reducing activity 26.01.2019 16:55:34

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

0
15.12.2008 00:34:08

Вот небольшое обновление вашей реализации. Если вы пытаетесь сделать что-то более подробное, я предлагаю заглянуть в NLTK, который предложил le dorfier.

Это может быть только немного быстрее, так как вместо + = используется .join (), который, как известно, быстрее .

import string

d = "Hello, I'm a string!"

result = []
word = ''

for char in d:
    if char not in string.whitespace:
        if char not in string.ascii_letters + "'":
            if word:
                    result.append(word)
            result.append(char)
            word = ''
        else:
            word = ''.join([word,char])

    else:
        if word:
            result.append(word)
            word = ''
print result
['Hello', ',', "I'm", 'a', 'string', '!']
1
15.12.2008 01:05:11
Я не описал это, но я думаю, что основная проблема заключается в конкатенации слова «символ за символом». Я бы вместо этого использовал индекс и ломтики.
user3850 15.12.2008 10:24:20
С помощью трюков я могу сэкономить 50% времени выполнения вашего решения. мое решение с re.findall () все еще в два раза быстрее.
user3850 15.12.2008 12:17:54
Вы должны вызывать if word: result.append(word)после окончания цикла, иначе последнее слово не в результате.
Roland Pihlakas 25.05.2017 12:15:24

Вот моя запись.

У меня есть сомнения относительно того, насколько хорошо это будет сохраняться в смысле эффективности, или если оно охватывает все случаи (обратите внимание на «!!!», сгруппированные вместе; это может или не может быть хорошей вещью).

>>> import re
>>> import string
>>> s = "Helo, my name is Joe! and i live!!! in a button; factory:"
>>> l = [item for item in map(string.strip, re.split("(\W+)", s)) if len(item) > 0]
>>> l
['Helo', ',', 'my', 'name', 'is', 'Joe', '!', 'and', 'i', 'live', '!!!', 'in', 'a', 'button', ';', 'factory', ':']
>>>

Одна очевидная оптимизация - это скомпилировать регулярное выражение заранее (используя re.compile), если вы собираетесь делать это построчно.

5
15.12.2008 01:30:32
плюс 1 за группировку знаков препинания.
UnsignedByte 4.04.2018 03:27:21

Вот версия с поддержкой Юникода:

re.findall(r"\w+|[^\w\s]", text, re.UNICODE)

Первая альтернатива перехватывает последовательности символов слова (как определено юникодом, поэтому «резюме» не превращается в ['r', 'sum']); вторая ловит отдельные несловарные символы, игнорируя пробелы.

Обратите внимание, что, в отличие от верхнего ответа, это рассматривает одиночную кавычку как отдельную пунктуацию (например, «я» -> ['I', "'", 'm']). Это кажется стандартным в НЛП, поэтому я считаю, что это особенность.

37
19.01.2012 17:58:09
Принято решение, потому что \w+|[^\w\s]конструкция более универсальная, чем принятый ответ, но в python 3 повторение .UNICODE не нужно
rloth 5.01.2015 16:21:39

Я придумал способ токенизации всех слов и \W+шаблонов, используя \bкоторый не требует жесткого кодирования :

>>> import re
>>> sentence = 'Hello, world!'
>>> tokens = [t.strip() for t in re.findall(r'\b.*?\S.*?(?:\b|$)', sentence)]
['Hello', ',', 'world', '!']

Вот .*?\S.*?шаблон, соответствующий всему, что не является пробелом и $добавляется для соответствия последнему токену в строке, если это символ пунктуации.

Однако обратите внимание на следующее - это сгруппирует пунктуацию, состоящую из более чем одного символа:

>>> print [t.strip() for t in re.findall(r'\b.*?\S.*?(?:\b|$)', '"Oh no", she said')]
['Oh', 'no', '",', 'she', 'said']

Конечно, вы можете найти и разделить такие группы с помощью:

>>> for token in [t.strip() for t in re.findall(r'\b.*?\S.*?(?:\b|$)', '"You can", she said')]:
...     print re.findall(r'(?:\w+|\W)', token)

['You']
['can']
['"', ',']
['she']
['said']
0
15.04.2014 19:16:25

Попробуй это:

string_big = "One of Python's coolest features is the string format operator  This operator is unique to strings"
my_list =[]
x = len(string_big)
poistion_ofspace = 0
while poistion_ofspace < x:
    for i in range(poistion_ofspace,x):
        if string_big[i] == ' ':
            break
        else:
            continue
    print string_big[poistion_ofspace:(i+1)]
    my_list.append(string_big[poistion_ofspace:(i+1)])
    poistion_ofspace = i+1

print my_list
0
18.04.2017 09:28:02

Если вы собираетесь работать на английском (или некоторых других распространенных языках), вы можете использовать NLTK (для этого есть много других инструментов, таких как FreeLing ).

import nltk
sentence = "help, me"
nltk.word_tokenize(sentence)
2
9.11.2018 10:30:56

Если вам не разрешено импортировать что-либо, используйте это!

word = "Hello,there"
word = word.replace("," , " ," )
word = word.replace("." , " .")
return word.split()
-1
27.11.2019 09:54:00

Это сработало для меня

import re

i = 'Sandra went to the hallway.!!'
l = re.split('(\W+?)', i)
print(l)

empty = ['', ' ']
l = [el for el in l if el not in empty]
print(l)

Output:
['Sandra', ' ', 'went', ' ', 'to', ' ', 'the', ' ', 'hallway', '.', '', '!', '', '!', '']
['Sandra', 'went', 'to', 'the', 'hallway', '.', '!', '!']
0
21.04.2020 08:41:57