2

Строка содержит различные символы, нужно удалить все, оставив лишь буквы и пробелы. Как я понимаю, нужно действовать через регулярные выражения, но как конкретно — мне непонятно.

titov_andrei
  • 1,342
SimonZen
  • 157

5 Answers5

8

При помощи regexp можно так:

import re
s = 'Hello!@#!%!#&&!*!#$#%@*+_{ world!'
reg = re.compile('[^a-zA-Z ]')
print(reg.sub('', s))
Avernial
  • 3,587
  • Все получилось, но команду вводил reg, а не regex, видимоб различие версий сказывается. Спасибо! – SimonZen Aug 31 '15 at 13:25
  • Прошу прощения, это у меня опечатка. – Avernial Sep 01 '15 at 00:49
3

Имеется метод str.translate(), который удаляет все символы из строки, содержащиеся в некотором наборе. regexp тут не нужны скорее всего.

3

Если хочется оставить только ascii буквы и соответствующие стандартные символы пробела, то bytes.translate() является наиболее эффективным методом:

#!/usr/bin/env python3
from string import ascii_letters, whitespace

good_chars = (ascii_letters + whitespace).encode()
junk_chars = bytearray(set(range(0x100)) - set(good_chars))

def clean(text):
    return text.encode('ascii', 'ignore').translate(None, junk_chars).decode()

print(clean('Hello1@#!%!#&&!*!#$#%@*+_{ world!'))
# -> Hello world

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

>>> import regex as re # $ pip install regex
>>> print(re.sub(r'[^\w\s]', '', 'Hello1@#!%!#&&!*!#$#%@*+_{\u00A0ёж!'))
Hello1_ ёж
>>> print(re.sub(r'[^\pL\p{Space}]', '', 'Hello1@#!%!#&&!*!#$#%@*+_{\u00A0ёж!'))
Hello еж

Стандартный re модуль не поддерживает \p{} Юникодные свойства, поэтому необходимо использовать regex модуль. Различные классы символов такие как \w, \pL могут порождать слегка отличные результаты (см. ёж vs. еж в примере). Можно также использовать Юникодные свойства напрямую: unicodedata + unicode.translate().

jfs
  • 52,361
2

Можно replace использовать. Более человеко-понимаемо чем всякие regexp

>>> i = 'abcdefg'
>>> i.replace('cde','')
'abfg'

Конечно это может быть утомительно и выглядеть слишком громоздко, но куда понятнее, чем regexp - который являет собой ни что иное, как рудимент трудно-читаемого программирования прошлого. Вы ещё перфокарты возьмите и попротыкайте...

>>> i = 'a$%b@.c&d*!@e$f%g'
>>> i.replace('%','').replace('$','').replace('@','').replace('*','').replace('.','').replace('!','').replace('&','')
'abcdefg'
  • 3
    А ваша строка похожа на дико корявую лапшу. Тогда уж в цикле делать. – Avernial Sep 01 '15 at 09:26
  • лучше иметь код из лапши, которую человеческий глаз может прочитать, чем кодировать код regexp-ами которые нужно сидеть и разбирать по пол часа каждый символ. Единственное, почему regexp-ы ещё в моде - это скорость. Как только напишут нормальные методы для таких тривиальных вещей как replace и delete, так ваши regexp-ы уйдут в музеи, акурательно рядом с перфокартами и польской инверсной записью будут стоять. – hateregexp Sep 07 '15 at 06:39
  • 3
    я думаю @Avernial имел ввиду: for junk_char in "%$@*.!&": s = s.replace(junk_char, '') (for-цикл, а не regex). Что может быть оправдано для пары-тройки .replace() вызовов. Для большего кол-ва, можно bytes.translate использовать: s = s.translate(None, b"%$@*.!&") – jfs Mar 03 '16 at 11:32
0

хотел бы добавить чуток полезного на примере датафрейма!

# приводим к нижнему регистру, учитываем наличие в тексте цифр, 
# c которыми не работает метод lower()
data.iloc[:,0] = data.iloc[:,0].apply(lambda x: ''.join([char.lower() if 
    not char.isdigit() and char is not None else char for char in x]))
    data['Text'] = data['Text'].apply(lambda x: x.translate(str.maketrans('', '', string.punctuation)))
    data.iloc[:,0]=data.iloc[:,0].apply(lambda x: re.sub('  ', ' ', x)) # удаление лишних пробелов
import nltk
nltk.download('stopwords')
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
stopwords.words('russian')
nltk.download('punkt')
from pymorphy3 import MorphAnalyzer
from nltk.corpus import stopwords

stop_words = set(stopwords.words('russian'))
data['Text'] = data['Text'].apply(lambda x: ' '.join([word for word in word_tokenize(x) if word not in stop_words]))
#Токенизируем
# Загрузка списка стоп-слов для русского языка
stopwords_ru = stopwords.words('russian')
morph = MorphAnalyzer()

def lemmatize_and_tokenize(doc):
    doc = re.sub(r'[^а-яА-Я]', ' ', doc)  # Заменяем не буквенные символы
    tokens = []
    for token in doc.split():
        if token and token not in stopwords_ru:
            token = token.strip()
            token = morph.parse(token)[0].normal_form  # Используем метод parse и normal_form
            tokens.append(token)
    if len(tokens) > 2:
        return tokens
    return tokens
morph1 = MorphAnalyzer()

def lemmatize(text):

    text = re.sub(r'[^а-яА-Я]', ' ', text)  # Заменяем не буквенные символы на пробелы
    clear_text = text.split()
    clear_text = [word for word in clear_text if word not in stop_words and len(word) > 2]
    clear_text = ' '.join(clear_text)
    clear_text = ' '.join([morph1.parse(word)[0].normal_form for word in clear_text.split()])
    return clear_text

data['Text_lemmatized'] = data['Text'].apply(lambda x: lemmatize(x))
data['Text_tokenized_lemmatized'] = data['Text'].apply(lambda x: lemmatize_and_tokenize(x))

#data_c.to_pickle('df_clear.pkl') #data = pd.read_pickle('df_clear.pkl')

0xdb
  • 51,614