Разделить строки на слова с несколькими разделителями слов - PullRequest
596 голосов
/ 29 июня 2009

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

"Hey, you - what are you doing here!?"

должно быть

['hey', 'you', 'what', 'are', 'you', 'doing', 'here']

Но Python str.split() работает только с одним аргументом, поэтому у меня есть все слова с пунктуацией после разделения на пробел. Есть идеи?

Ответы [ 32 ]

4 голосов
/ 06 октября 2013

Мне нравится re , но вот мое решение без него:

from itertools import groupby
sep = ' ,-!?'
s = "Hey, you - what are you doing here!?"
print [''.join(g) for k, g in groupby(s, sep.__contains__) if not k]

sep .__ содержит __ - метод, используемый оператором 'in'. В основном это так же, как

lambda ch: ch in sep

но здесь удобнее.

groupby получает нашу строку и функцию. Он разбивает строку на группы, используя эту функцию: всякий раз, когда значение функции изменяется - генерируется новая группа. Итак, sep .__ содержит __ именно то, что нам нужно.

groupby возвращает последовательность пар, где пара [0] является результатом нашей функции, а пара [1] является группой. Используя 'если не k' , мы отфильтровываем группы с разделителями (потому что результат sep .__ содержит __ - True для разделителей) Ну, вот и все - теперь у нас есть последовательность групп, каждая из которых является словом (группа на самом деле итеративная, поэтому мы используем join для преобразования его в строку).

Это решение довольно общее, потому что оно использует функцию для разделения строк (вы можете разбить любое условие, которое вам нужно). Кроме того, он не создает промежуточные строки / списки (вы можете удалить join , и выражение станет ленивым, поскольку каждая группа является итератором)

4 голосов
/ 10 сентября 2018

Вместо использования функции re-split модуля remoll вы можете достичь того же результата, используя метод pandas series.str.split

Сначала создайте серию с указанной строкой, а затем примените метод к серии.

thestring = pd.Series("Hey, you - what are you doing here!?") thestring.str.split(pat = ',|-')

параметр pat принимает разделители и возвращает разделенную строку в виде массива. Здесь два разделителя передаются с помощью | (или оператор). Вывод выглядит следующим образом:

[Hey, you , what are you doing here!?]

4 голосов
/ 30 марта 2012

Используйте заменить два раза:

a = '11223FROM33344INTO33222FROM3344'
a.replace('FROM', ',,,').replace('INTO', ',,,').split(',,,')

Результат:

['11223', '33344', '33222', '3344']
3 голосов
/ 15 июля 2018

В Python 3 вы можете использовать метод из PY4E - Python для всех .

Мы можем решить обе эти проблемы, используя строковые методы lower, punctuation и translate. translate - самый тонкий метод. Вот документация для translate:

your_string.translate(your_string.maketrans(fromstr, tostr, deletestr))

Замените символы в fromstr на символы в той же позиции в tostr и удалите все символы в deletestr. fromstr и tostr могут быть пустыми строками, а параметр deletestr можно опустить.

Вы можете увидеть "пунктуацию":

In [10]: import string

In [11]: string.punctuation
Out[11]: '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'  

Для вашего примера:

In [12]: your_str = "Hey, you - what are you doing here!?"

In [13]: line = your_str.translate(your_str.maketrans('', '', string.punctuation))

In [14]: line = line.lower()

In [15]: words = line.split()

In [16]: print(words)
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']

Для получения дополнительной информации вы можете обратиться:

3 голосов
/ 20 апреля 2012

Я заново знакомлюсь с Python и мне нужно то же самое. Решение findall может быть лучше, но я придумал это:

tokens = [x.strip() for x in data.split(',')]
2 голосов
/ 04 марта 2018

с помощью maketrans и translate вы можете сделать это легко и аккуратно

import string
specials = ',.!?:;"()<>[]#$=-/'
trans = string.maketrans(specials, ' '*len(specials))
body = body.translate(trans)
words = body.strip().split()
1 голос
/ 04 ноября 2014

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

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

однострочная лямбда-функция с пониманием списка:

(требуется import string):

split_without_punc = lambda text : [word.strip(string.punctuation) for word in 
    text.split() if word.strip(string.punctuation) != '']

# Call function
split_without_punc("Hey, you -- what are you doing?!")
# returns ['Hey', 'you', 'what', 'are', 'you', 'doing']


Функция (традиционная)

Как традиционная функция, это всего лишь две строки с пониманием списка (в дополнение к import string):

def split_without_punctuation2(text):

    # Split by whitespace
    words = text.split()

    # Strip punctuation from each word
    return [word.strip(ignore) for word in words if word.strip(ignore) != '']

split_without_punctuation2("Hey, you -- what are you doing?!")
# returns ['Hey', 'you', 'what', 'are', 'you', 'doing']

Это также естественным образом оставит сокращения и дефисные слова без изменений. Вы всегда можете использовать text.replace("-", " "), чтобы превратить дефисы в пробелы перед разбиением.

Общая функция без лямбды или понимания списка

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

def split_without(text: str, ignore: str) -> list:

    # Split by whitespace
    split_string = text.split()

    # Strip any characters in the ignore string, and ignore empty strings
    words = []
    for word in split_string:
        word = word.strip(ignore)
        if word != '':
            words.append(word)

    return words

# Situation-specific call to general function
import string
final_text = split_without("Hey, you - what are you doing?!", string.punctuation)
# returns ['Hey', 'you', 'what', 'are', 'you', 'doing']

Конечно, вы всегда можете обобщить лямбда-функцию на любую указанную строку символов.

1 голос
/ 02 июня 2015

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

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

import re
DATA = "Hey, you - what are you doing here!?"
reg_tok = re.compile("[\w']+")
print reg_tok.findall(DATA)
1 голос
/ 29 июня 2009

Другим способом достижения этой цели является использование набора инструментов для естественного языка ( nltk ).

import nltk
data= "Hey, you - what are you doing here!?"
word_tokens = nltk.tokenize.regexp_tokenize(data, r'\w+')
print word_tokens

Это печатает: ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

Самый большой недостаток этого метода в том, что вам нужно установить пакет nltk .

Преимущество состоит в том, что вы можете сделать массу забавных вещей с остальной частью пакета nltk, как только получите токены.

1 голос
/ 10 мая 2017

Создайте функцию, которая принимает в качестве входных данных две строки (исходную строку для разделения и строку разделителя списка разделителей) и выводит список разделенных слов:

def split_string(source, splitlist):
    output = []  # output list of cleaned words
    atsplit = True
    for char in source:
        if char in splitlist:
            atsplit = True
        else:
            if atsplit:
                output.append(char)  # append new word after split
                atsplit = False
            else: 
                output[-1] = output[-1] + char  # continue copying characters until next split
    return output
...