Я думаю, что я хочу сделать, это довольно распространенная задача, но я не нашел ссылки в Интернете. У меня есть текст с пунктуацией, и я хочу список слов.
"Hey, you - what are you doing here!?"
должно быть
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']
Но Python работает str.split()
только с одним аргументом, поэтому у меня есть все слова с пунктуацией после разделения на пробел. Любые идеи?
str.split()
также работает без каких-либо аргументовОтветы:
Случай, когда регулярные выражения оправданы:
источник
re
, просто неfindall
. Ответ ниже даетre.split()
превосходство.don't
обрабатывается как одно слово, а не разделяется наdon
иt
.re.split ()
источник
\w
,\W
,\s
и\S
. Кто бы ни думал, что заглавная буква флага должна инвертировать его значение, нужно выстрелить в голову.shift
ключ, чтобы сделать что-то противоположное.ctrl+z
отменить противctrl+shift+z
повторного. Такshift w
или иначеW
будет противоположностьw
.Другой быстрый способ сделать это без регулярного выражения - сначала заменить символы, как показано ниже:
источник
Так много ответов, но я не могу найти никакого решения, которое бы эффективно выполняло то, что буквально запрашивает заголовок вопросов (разделение на несколько возможных разделителей - вместо этого, многие ответы разделяются на все, что не является словом, которое отличается). Итак, вот ответ на вопрос в заголовке, основанный на стандартном и эффективном
re
модуле Python :где:
[…]
матчи один из сепараторов , перечисленные внутри,\-
в регулярном выражении здесь , чтобы предотвратить специальную интерпретацию в-
качестве индикатора диапазона символов (как вA-Z
),+
пропускает один или несколько разделителей (она может быть опущена благодаряfilter()
, но это было бы излишне производить пустые строки между согласованными сепараторами), иfilter(None, …)
удаляет пустые строки, возможно, созданные начальным и конечным разделителями (поскольку пустые строки имеют ложное логическое значение).Это
re.split()
точно "разделяется с несколькими разделителями", как это было указано в заголовке вопроса.Кроме того, это решение неуязвимо для проблем с не-ASCII-символами в словах, обнаруженных в некоторых других решениях (см. Первый комментарий к ответу ghostdog74 ).
re
Модуль является гораздо более эффективным (по скорости и краткости) , чем делать петлю и тесты Python «от руки»!источник
Другой способ, без регулярных выражений
источник
"Hey, you - what are you doing here María!?"
. Принятое решение не будет работать с предыдущим примером.''.join([o if not o in string.punctuation else ' ' for o in s]).split()
o for o in s if (o in not string.punctuation or o == "'")
, но тогда это становится слишком сложным для однострочника, если мы добавим также патч cedbeu."First Name,Last Name,Street Address,City,State,Zip Code"
и мы хотим разделить ее только запятой,
. Желаемый результат будет таким:['First Name', 'Last Name', 'Street Address', 'City', 'State', 'Zip Code']
Что мы получим вместо этого:['First', 'Name', 'Last', 'Name', 'Street', 'Address', 'City', 'State', 'Zip', 'Code']
re
модуль является стандартным и дает удобочитаемость и скорость, я не понимаю, почему его следует избегать.Pro-Tip: Используйте
string.translate
для самых быстрых строковых операций, которые есть в Python.Некоторое доказательство ...
Во-первых, медленный путь (извините, pprzemek):
Далее используем
re.findall()
(как указано в предложенном ответе). Намного быстрее:Наконец, мы используем
translate
:Объяснение:
string.translate
реализован на C и, в отличие от многих функций манипуляции со строками в Python,string.translate
не создает новую строку. Так что это почти так же быстро, как вы можете получить для замены строк.Это немного неловко, так как для этой магии нужна таблица перевода. Вы можете сделать таблицу перевода с
maketrans()
удобной функцией. Цель здесь - перевести все нежелательные символы в пробелы. Замена один на один. Опять же, никаких новых данных не производится. Так что это быстро !Далее мы используем старое доброе
split()
.split()
по умолчанию будут работать со всеми пробельными символами, группируя их вместе для разделения. Результатом будет список слов, которые вы хотите. И этот подход почти в 4 раза быстрееre.findall()
!источник
patt = re.compile(ur'\w+', re.UNICODE); patt.findall(S)
быстрее, чем перевод, потому что вы должны закодировать строку перед применением преобразования и декодировать каждый элемент в списке после разделения, чтобы вернуться к юникоду.s.translate(''.join([(chr(i) if chr(i) not in seps else seps[0]) for i in range(256)])).split(seps[0])
У меня была похожая дилемма, и я не хотел использовать модуль 're'.
источник
re
модуль, который намного быстрее и понятнее (не то, что регулярные выражения особенно понятны, а потому что он короче и прямее)?Во-первых, я хочу согласиться с другими, что регулярные выражения или
str.translate(...)
основанные на них решения наиболее эффективны. Для моего варианта использования производительность этой функции была незначительной, поэтому я хотел добавить идеи, которые я рассмотрел, с помощью этих критериев.Моя главная цель состояла в том, чтобы обобщить идеи из некоторых других ответов в одно решение, которое могло бы работать для строк, содержащих больше, чем просто слова регулярных выражений (то есть внесение в черный список явного поднабора символов пунктуации против символов слов из белого списка).
Обратите внимание, что при любом подходе можно также рассмотреть возможность использования
string.punctuation
вместо определенного вручную списка.Вариант 1 - re.sub
Я был удивлен, что пока не получил ответа, использует re.sub (...) . Я считаю это простым и естественным подходом к этой проблеме.
В этом решении я вложил вызов
re.sub(...)
внутрьre.split(...)
- но если критична производительность, компиляция регулярного выражения извне может быть полезной - для моего случая использования разница не была значительной, поэтому я предпочитаю простоту и удобочитаемость.Вариант 2 - str.replace
Это еще несколько строк, но оно имеет преимущество, заключающееся в возможности расширения без необходимости проверять необходимость экранирования определенного символа в регулярном выражении.
Было бы неплохо иметь возможность вместо этого сопоставить str.replace со строкой, но я не думаю, что это можно сделать с неизменяемыми строками, и хотя сопоставление со списком символов будет работать, выполнение каждой замены для каждого символа звучит чрезмерно. (Изменить: см. Следующий вариант для функционального примера.)
Вариант 3 - functools.reduce
(В Python 2
reduce
доступен в глобальном пространстве имен без импорта из functools.)источник
str.translate
- он не поддерживает юникод, но, скорее всего, он быстрее, чем другие методы, и в некоторых случаяхreplacements=',-!?'; import string; my_str = my_str.translate(string.maketrans(replacements, ' ' * len(replacements)))
он может быть полезен: здесь также обязательно иметь замены в виде строки символов, а не кортежа или список.Тогда это становится тремя линиями:
объяснение
Это то, что в Хаскеле известно как монада List. Идея, лежащая в основе монады, заключается в том, что, оказавшись «в монаде», вы «остаетесь в монаде», пока что-то не вытеснит вас. Например, в Haskell, скажем, вы отображаете
range(n) -> [1,2,...,n]
функцию python на List. Если результатом будет список, он будет добавлен в список на месте, так что вы получите что-то вродеmap(range, [3,4,1]) -> [0,1,2,0,1,2,3,0]
. Это называется map-append (или mappend, или, может быть, что-то в этом роде). Идея заключается в том, что у вас есть эта операция, которую вы применяете (разделение на токене), и всякий раз, когда вы делаете это, вы присоединяете результат к списку.Вы можете абстрагировать это в функцию и использовать
tokens=string.punctuation
по умолчанию.Преимущества такого подхода:
источник
map_then_append
можно использовать, чтобы сделать задачу 2-строчной , а также многие другие задачи, которые гораздо проще написать. Большинство других решений используютre
модуль регулярных выражений , который не является Python. Но я был недоволен тем, как мой ответ кажется не элегантным и раздутым, когда он действительно лаконичен ... Я собираюсь его отредактировать ...fragments
результат - просто список символов в строке (включая токены).fragments = ['the,string']
,fragments = 'the,string'
илиfragments = list('the,string')
ни один из них не производят правильный выход.попробуй это:
это напечатает
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
источник
Используйте заменить два раза:
результаты в:
источник
Мне нравится re , но вот мое решение без него:
sep .__ содержит ___ метод, используемый оператором 'in'. В основном это так же, как
но здесь удобнее.
groupby получает нашу строку и функцию. Он разбивает строку на группы, используя эту функцию: всякий раз, когда значение функции изменяется - генерируется новая группа. Итак, Sep .__ содержит ___ именно то, что нам нужно.
groupby возвращает последовательность пар, где пара [0] является результатом нашей функции, а пара [1] является группой. Используя 'если не k', мы отфильтровываем группы с разделителями (потому что результат sep .__ содержит__ равен True для разделителей). Ну, вот и все - теперь у нас есть последовательность групп, каждая из которых является словом (группа на самом деле является итеративной, поэтому мы используем join для преобразования ее в строку).
Это решение довольно общее, потому что оно использует функцию для разделения строк (вы можете разбить любое условие). Кроме того, он не создает промежуточные строки / списки (вы можете удалить объединение, и выражение станет ленивым, поскольку каждая группа является итератором)
источник
Вместо использования функции re-split модуля reim вы можете добиться того же результата, используя метод 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!?]
источник
Я заново знакомлюсь с Python и мне нужно то же самое. Решение findall может быть лучше, но я придумал это:
источник
используя макетранс и перевод, вы можете сделать это легко и аккуратно
источник
В Python 3 вы можете использовать метод из PY4E - Python for Everybody .
your_string.translate(your_string.maketrans(fromstr, tostr, deletestr))
Вы можете увидеть «пунктуацию»:
Для вашего примера:
Для получения дополнительной информации вы можете обратиться:
источник
Другой способ добиться этого - использовать набор инструментов Natural Language Tool Kit ( nltk ).
Это печатает:
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
Самый большой недостаток этого метода заключается в том, что вам нужно установить пакет nltk .
Преимущества в том, что вы можете делать много интересного с остальной частью пакета nltk, как только получите токены.
источник
Прежде всего, я не думаю, что вы намерены использовать пунктуацию в качестве разделителей в функциях разделения. Ваше описание предполагает, что вы просто хотите исключить пунктуацию из результирующих строк.
Я сталкиваюсь с этим довольно часто, и мое обычное решение не требует повторного.
Однострочная лямбда-функция с пониманием списка:
(требуется
import string
):Функция (традиционная)
Как традиционная функция, это все еще только две строки с пониманием списка (в дополнение к
import string
):Это также естественно оставит сокращения и дефисные слова нетронутыми. Вы всегда можете использовать,
text.replace("-", " ")
чтобы превратить дефисы в пробелы до разделения.Общая функция без лямбды или понимания списка
Для более общего решения (где вы можете указать символы для исключения) и без понимания списка, вы получите:
Конечно, вы всегда можете обобщить лямбда-функцию на любую указанную строку символов.
источник
Прежде всего, всегда используйте re.compile () перед выполнением любой операции RegEx в цикле, потому что она работает быстрее, чем обычная операция.
поэтому для вашей проблемы сначала скомпилируйте шаблон, а затем выполните действие с ним.
источник
Вот ответ с некоторыми объяснениями.
или в одну строку мы можем сделать так:
обновленный ответ
источник
Создайте функцию, которая принимает в качестве входных данных две строки (исходную строку, которую нужно разделить, и строку разделителя списка разделителей) и выводит список разделенных слов:
источник
Мне нравится решение pprzemek, потому что оно не предполагает, что разделители являются одиночными символами, и не пытается использовать регулярное выражение (что не будет работать хорошо, если количество разделителей будет слишком большим).
Вот более читаемая версия вышеупомянутого решения для ясности:
источник
У меня та же проблема, что и у @ooboo, и найти эту тему @ ghostdog74 вдохновил меня, может быть, кто-то найдет мое решение полезным
введите что-то в пробел и разделите, используя тот же символ, если вы не хотите разбивать пробел.
источник
Вот мой пример с несколькими разделителями:
источник
Я думаю, что следующее - лучший ответ для удовлетворения ваших потребностей:
\W+
может подходить для этого случая, но может не подходить для других случаев.источник
\w
и\W
решения не являются ответом на (название) вопроса. Обратите внимание, что в вашем ответе|
должен быть удален (вы думаете,expr0|expr1
а не[char0 char1…]
). Кроме того, нет необходимостиcompile()
в регулярном выражении.Вот мой взгляд на это ....
источник
Мне нравится,
replace()
как лучше всего. Следующая процедура заменяет все разделители, определенные в строке,splitlist
на первый разделитель,splitlist
а затем разбивает текст на этом одном разделителе. Он также учитываетsplitlist
, является ли пустая строка. Возвращает список слов без пустых строк.источник
Вот использование:
источник
Если вам нужна обратимая операция (сохраните разделители), вы можете использовать эту функцию:
источник
Недавно мне нужно было сделать это, но я хотел функцию, которая в некоторой степени соответствовала стандартной библиотечной
str.split
функции, эта функция ведет себя так же, как стандартная библиотека, когда вызывается с 0 или 1 аргументом.ПРИМЕЧАНИЕ . Эта функция полезна только в том случае, если разделители состоят из одного символа (как в моем случае использования).
источник