Python, удалите все не алфавитные символы из строки

90

Я пишу программу подсчета слов MapReduce на Python. Проблема в том, что в данных разбросано много не алфавитных символов, я нашел этот пост Удаление всего, кроме буквенно-цифровых символов из строки в Python, которая показывает хорошее решение с использованием регулярного выражения, но я не уверен, как его реализовать

def mapfn(k, v):
    print v
    import re, string 
    pattern = re.compile('[\W_]+')
    v = pattern.match(v)
    print v
    for w in v.split():
        yield w, 1

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

Предложения?

KDecker
источник
v- это целая строка книги (в частности, moby dick), я перехожу слово в слово, а не символ за символом. Поэтому некоторые слова могут иметь в конце «унижение», поэтому «унижение» не сочетается с «унижением».
KDecker
Лолкс - вы делали то же домашнее упражнение перед собеседованием, что и я? Найдите 50 наиболее часто используемых слов в Моби Дике и сообщите об их частоте. Я сделал это на C ++, IIRC
Mawg говорит восстановить Монику
1
@Mawg Это было упражнение на моем старшем курсе "Облачные вычисления".
KDecker

Ответы:

128

Использовать re.sub

import re

regex = re.compile('[^a-zA-Z]')
#First parameter is the replacement, second parameter is your input string
regex.sub('', 'ab3d*E')
#Out: 'abdE'

В качестве альтернативы, если вы хотите удалить только определенный набор символов (поскольку апостроф может быть в вашем вводе ...)

regex = re.compile('[,\.!?]') #etc.
Limasxgoesto0
источник
Хм, я вполне могу его отследить, но как насчет шаблона для удаления всех не буквенно-цифровых символов, за исключением пробелов?
KDecker
1
Просто добавьте пробел в свой класс коллекции. т.е. ^a-zA-Z вместо просто^a-zA-Z
limasxgoesto0
Если вы также не беспокоитесь о новых строках, в этом случае a-zA-Z \n. Я пытаюсь найти регулярное выражение, которое объединит оба в одно, но использует \wили \Wне дает мне желаемого поведения. Возможно, вам просто нужно добавить, \nесли это так.
limasxgoesto0
Ах, символ новой строки. В этом и заключаются мои проблемы, я сравнивал свои результаты с полученными результатами, и я все еще не работал. Думаю, это моя проблема! Спасибо // Хм, я пробовал это с символом новой строки, те же результаты, я думаю, что есть еще один, который мне не хватает .. // Ммм ... Верхний и нижний регистр ... // Спасибо за помощь, теперь работает отлично!
KDecker
48

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

''.join([i for i in s if i.isalpha()])
Тэд
источник
как мне присоединиться к этому? с '' .join? печать s получает только объект фильтра
PirateApp
Вау, вот что я искал. При этом учитываются кандзи, хирагана, катакана и т. Д. kudos
root163
34

Вы можете использовать функцию re.sub () для удаления этих символов:

>>> import re
>>> re.sub("[^a-zA-Z]+", "", "ABC12abc345def")
'ABCabcdef'

re.sub (СООТВЕТСТВИЕ ШАБЛОНУ, ЗАМЕНИТЬ СТРОКУ, СТРОКУ ДЛЯ ПОИСКА)

  • "[^a-zA-Z]+" - ищите любую группу символов НЕ a-zA-z.
  • "" - Замените совпадающие символы на ""
Кевин
источник
Обратите внимание, что при этом также будут удалены буквы с диакритическими знаками: ãâàáéèçõ и т. Д.
Брэд Аренс,
19

Пытаться:

s = ''.join(filter(str.isalnum, s))

Это возьмет все символы из строки, оставит только буквенно-цифровые и построит из них строку.

Дон
источник
1
В этом ответе можно было бы использовать гораздо больше объяснений и ссылок на соответствующую документацию.
pdoherty926
4

Самый быстрый метод - регулярное выражение

#Try with regex first
t0 = timeit.timeit("""
s = r2.sub('', st)

""", setup = """
import re
r2 = re.compile(r'[^a-zA-Z0-9]', re.MULTILINE)
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""", number = 1000000)
print(t0)

#Try with join method on filter
t0 = timeit.timeit("""
s = ''.join(filter(str.isalnum, st))

""", setup = """
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""",
number = 1000000)
print(t0)

#Try with only join
t0 = timeit.timeit("""
s = ''.join(c for c in st if c.isalnum())

""", setup = """
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""", number = 1000000)
print(t0)


2.6002226710006653 Method 1 Regex
5.739747313000407 Method 2 Filter + Join
6.540099570000166 Method 3 Join
PirateApp
источник
0

Рекомендуется использовать модуль PyPi,regex если вы планируете сопоставить определенные классы свойств Unicode. Эта библиотека также оказалась более стабильной, особенно при работе с большими текстами, и дает стабильные результаты для различных версий Python. Все, что вам нужно сделать, это поддерживать его в актуальном состоянии.

Если вы установите его (используя pip intall regexили pip3 install regex), вы можете использовать

import regex
print ( regex.sub(r'\P{L}+', '', 'ABCŁąć1-2!Абв3§4“5def”') )
// => ABCŁąćАбвdef

, чтобы удалить все фрагменты из 1 или более символов, кроме букв Unicode text. См. Онлайн-демонстрацию Python . Вы также можете использовать "".join(regex.findall(r'\p{L}+', 'ABCŁąć1-2!Абв3§4“5def”'))для получения того же результата.

В Python re, чтобы соответствовать любой букве Unicode, можно использовать [^\W\d_]конструкцию ( Match any unicode letter? ).

Итак, чтобы удалить все небуквенные символы, вы можете сопоставить все буквы и объединить результаты:

result = "".join(re.findall(r'[^\W\d_]', text))

Или удалите все символы, кроме совпадающих с [^\W\d_]:

result = re.sub(r'([^\W\d_])|.', r'\1', text, re.DOTALL)

См. Демонстрацию регулярных выражений в Интернете . Однако вы можете получить противоречивые результаты в разных версиях Python, потому что стандарт Unicode развивается, и набор совпадающих символов \wбудет зависеть от версии Python. regexДля получения стабильных результатов настоятельно рекомендуется использовать библиотеку PyPi .

Виктор Стрибьев
источник