2008-12-14 6 views
38

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

Например:

>>> 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'] 

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

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

+0

Для этого примера (а не общий случай) `c.replace (' ' '') раздел (',')` – 2016-11-21 08:59:51

ответ

57

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

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

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

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

  • подчеркивание (_) считается внутренним слово характер. Замените \ w, если вы этого не хотите.
  • Это не будет работать с (одиночными) кавычками в строке.
  • Поместите любые дополнительные знаки препинания, которые вы хотите использовать в правой половине регулярного выражения.
  • Все, что явно не указано в re, тихо отбрасывается.
-1

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

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


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

[0]

""

[1]

""

Так что, если вы хотите, чтобы добавить " , «вы можете просто сделать это после каждой итерации при использовании массива.

4

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

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

+0

только это не потому, что re.split не будет работать с r '\ b' ... – hop 2008-12-15 01:09:10

+0

Какого черта? Это ошибка в re.split? В Perl `split/\ b \ s * /` работает без проблем. – Svante 2008-12-15 01:29:34

+0

Это задокументировано, что re.split() не будет разбиваться на пустые совпадения ... так, нет, нет/действительно/ошибка. – hop 2008-12-15 01:51:26

0

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

1

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

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

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', '!'] 
2

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

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

>>> 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), если вы собираетесь делать это на основе линии построчно.

22

Вот Юникод версия:

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

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

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

0

я придумал способ разметить все слова и \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

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

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