Remova todos os caracteres especiais, pontuação e espaços da string

236

Preciso remover todos os caracteres especiais, pontuação e espaços de uma string, para ter apenas letras e números.

user664546
fonte

Respostas:

351

Isso pode ser feito sem regex:

>>> string = "Special $#! characters   spaces 888323"
>>> ''.join(e for e in string if e.isalnum())
'Specialcharactersspaces888323'

Você pode usar str.isalnum:

S.isalnum() -> bool

Return True if all characters in S are alphanumeric
and there is at least one character in S, False otherwise.

Se você insistir em usar o regex, outras soluções funcionarão bem. No entanto, observe que, se isso puder ser feito sem o uso de uma expressão regular, essa é a melhor maneira de fazer isso.

user225312
fonte
7
Por que não usar regex como regra geral?
22412 Chris Dutrow
@ChrisDutrow regex são mais lentos do que seqüência de python funções embutidas
Diego Navarro
Isso funciona apenas quando a string está no unicode . Caso contrário, ele reclama como o objeto 'str' não tem atributo 'isalnum' 'isnumeric' e assim por diante.
NeoJi
10
@DiegoNavarro exceto que não é verdade, eu aferido ambos os isalnum()e regex versões, eo regex é 50-75% mais rápido
Francisco Couzo
2
Além disso: "Para cadeias de caracteres de 8 bits, esse método depende da localidade."! Assim, a alternativa regex é estritamente melhor!
Antti Haapala
232

Aqui está uma regex para corresponder a uma sequência de caracteres que não são letras ou números:

[^A-Za-z0-9]+

Aqui está o comando Python para fazer uma substituição de regex:

re.sub('[^A-Za-z0-9]+', '', mystring)
Andy White
fonte
10
BEIJO: Mantenha-o simples estúpido! Isso é mais curto e muito mais fácil de ler do que as soluções que não são regex e também pode ser mais rápido. (No entanto, eu gostaria de acrescentar um +quantificador para melhorar a sua eficiência um pouco.)
Ridgerunner
1
isso também remove os espaços entre as palavras "ótimo lugar" -> "ótimo lugar". Como evitá-lo?
21717 Reihan_amn
5
@Reihan_amn Basta adicionar um espaço ao regex, por isso torna-se:[^A-Za-z0-9 ]+
ostroon
1
@ Andy White Você pode adicionar o espaço ao regex na resposta? O espaço não é um carácter especial ...
Ufos
3
Eu acho que isso não funciona com caracteres modificados em outros idiomas, como á , ö , ñ , etc. Estou certo? Em caso afirmativo, como seria o regex para isso?
HuLu ViCa 08/08/19
50

Maneira mais curta:

import re
cleanString = re.sub('\W+','', string )

Se você quiser espaços entre palavras e números, substitua '' por ''

tuxErrante
fonte
3
Exceto que _ está em \ w e é um caractere especial no contexto desta pergunta.
Kkurian #
Depende do contexto - o sublinhado é muito útil para nomes de arquivos e outros identificadores, a ponto de eu não o tratar como um caractere especial, mas como um espaço higienizado. Geralmente, eu mesmo uso esse método.
Echelon
1
r'\W+'- ligeiramente fora de tópico (e muito pedante), mas eu sugiro um hábito que todos os padrões de regex ser cordas matérias
Bob Stein
2
Este procedimento não trata o sublinhado (_) como um caractere especial.
Md. Sabbir Ahmed 5/04/19
30

Depois de ver isso, eu estava interessado em expandir as respostas fornecidas, descobrindo quais são executadas no menor período de tempo. Por isso, analisei algumas das respostas propostas com timeitduas das seqüências de exemplo:

  • string1 = 'Special $#! characters spaces 888323'
  • string2 = 'how much for the maple syrup? $20.99? That s ricidulous!!!'

Exemplo 1

'.join(e for e in string if e.isalnum())

  • string1 - Resultado: 10.7061979771
  • string2 - Resultado: 7.78372597694

Exemplo 2

import re re.sub('[^A-Za-z0-9]+', '', string)

  • string1 - Resultado: 7.10785102844
  • string2 - Resultado: 4.12814903259

Exemplo 3

import re re.sub('\W+','', string)

  • string1 - Resultado: 3.11899876595
  • string2 - Resultado: 2.78014397621

Os resultados acima são um produto do menor resultado retornado de uma média de: repeat(3, 2000000)

O exemplo 3 pode ser 3x mais rápido que o exemplo 1 .

mbeacom
fonte
@kkurian Se você leu o começo da minha resposta, isso é apenas uma comparação das soluções propostas anteriormente acima. Você pode comentar sobre a resposta de origem ... stackoverflow.com/a/25183802/2560922
mbeacom
Oh, eu vejo aonde você está indo com isso. Feito!
Kkurian #
1
Deve-se considerar o Exemplo 3, ao lidar com corpus grande.
HARSH NILESH PATHAK
Válido! Obrigado por notar.
mbeacom
você pode comparar minha resposta''.join([*filter(str.isalnum, string)])
Grijesh Chauhan
22

Python 2. *

Eu acho que filter(str.isalnum, string)funciona

In [20]: filter(str.isalnum, 'string with special chars like !,#$% etcs.')
Out[20]: 'stringwithspecialcharslikeetcs'

Python 3. *

No Python3, a filter( )função retornaria um objeto iterável (em vez de uma string diferente da acima). É preciso se juntar novamente para obter uma string do itertable:

''.join(filter(str.isalnum, string)) 

ou para passar listno uso da junção ( não tenho certeza, mas pode ser um pouco rápido )

''.join([*filter(str.isalnum, string)])

note: descompactar em [*args]válido a partir do Python> = 3.5

Grijesh Chauhan
fonte
4
@Alexey corrigir, Em python3 map, filtere reduce retorna objeto itertable vez. Ainda em Python3 +, preferirei ''.join(filter(str.isalnum, string)) (ou passar a lista no uso de junção ''.join([*filter(str.isalnum, string)])) à resposta aceita.
Grijesh Chauhan 15/03/19
Não tenho certeza se ''.join(filter(str.isalnum, string))é uma melhoria filter(str.isalnum, string), pelo menos para ler. Essa é realmente a maneira Pythreenic (sim, você pode usar isso) para fazer isso?
The proletariado
1
@TheProletariat O ponto é simplesmentefilter(str.isalnum, string) não retornam string no Python3 como filter( )em Python3 retorna iterador ao invés de tipo de argumento ao contrário de Python-2 +.
Grijesh Chauhan
@GrijeshChauhan, acho que você deve atualizar sua resposta para incluir suas recomendações em Python2 e Python3.
Mwfearnley #
18
#!/usr/bin/python
import re

strs = "how much for the maple syrup? $20.99? That's ricidulous!!!"
print strs
nstr = re.sub(r'[?|$|.|!]',r'',strs)
print nstr
nestr = re.sub(r'[^a-zA-Z0-9 ]',r'',nstr)
print nestr

você pode adicionar mais caracteres especiais e que serão substituídos por "" não significa nada, ou seja, eles serão removidos.

pkm
fonte
16

Diferentemente do que todo mundo usava regex, eu tentava excluir todos os caracteres que não são o que eu quero, em vez de enumerar explicitamente o que não quero.

Por exemplo, se eu quiser apenas caracteres de 'a a z' (maiúsculas e minúsculas) e números, excluiria todo o resto:

import re
s = re.sub(r"[^a-zA-Z0-9]","",s)

Isso significa "substituir todo caractere que não seja um número ou um caractere no intervalo 'a a z' ou 'A a Z' por uma string vazia".

De fato, se você inserir o caractere especial ^no primeiro lugar do seu regex, receberá a negação.

Dica adicional: se você também precisar diminuir o resultado em minúsculas , poderá tornar o regex ainda mais rápido e fácil, desde que não encontre maiúsculas agora.

import re
s = re.sub(r"[^a-z0-9]","",s.lower())
Andrea
fonte
9

Supondo que você queira usar uma regex e que deseje / precise do código 2.x com reconhecimento de Unicode que esteja pronto para 2to3:

>>> import re
>>> rx = re.compile(u'[\W_]+', re.UNICODE)
>>> data = u''.join(unichr(i) for i in range(256))
>>> rx.sub(u'', data)
u'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\xaa\xb2 [snip] \xfe\xff'
>>>
John Machin
fonte
7
s = re.sub(r"[-()\"#/@;:<>{}`+=~|.!?,]", "", s)
sneha
fonte
6

A abordagem mais genérica é usar as 'categorias' da tabela unicodedata que classifica cada caractere único. Por exemplo, o código a seguir filtra apenas caracteres imprimíveis com base em sua categoria:

import unicodedata
# strip of crap characters (based on the Unicode database
# categorization:
# http://www.sql-und-xml.de/unicode-database/#kategorien

PRINTABLE = set(('Lu', 'Ll', 'Nd', 'Zs'))

def filter_non_printable(s):
    result = []
    ws_last = False
    for c in s:
        c = unicodedata.category(c) in PRINTABLE and c or u'#'
        result.append(c)
    return u''.join(result).replace(u'#', u' ')

Veja o URL fornecido acima para todas as categorias relacionadas. Naturalmente, você também pode filtrar pelas categorias de pontuação.

Andreas Jung
fonte
O que há com $o final de cada linha?
precisa
Se for um problema de copiar e colar, você deve corrigi-lo?
Olli
5

string.punctuation contém os seguintes caracteres:

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

Você pode usar as funções de conversão e maketrans para mapear pontuações para valores vazios (substituir)

import string

'This, is. A test!'.translate(str.maketrans('', '', string.punctuation))

Resultado:

'This is A test'
Vlad Bezden
fonte
4

Use traduzir:

import string

def clean(instr):
    return instr.translate(None, string.punctuation + ' ')

Advertência: Funciona apenas em seqüências ascii.

jjmurre
fonte
Diferença de versão? Eu recebo TypeError: translate() takes exactly one argument (2 given)com py3.4
matt wilkie
1
import re
my_string = """Strings are amongst the most popular data types in Python. We can create the strings by enclosing characters in quotes. Python treats single quotes the 

o mesmo que aspas duplas. "" "

# if we need to count the word python that ends with or without ',' or '.' at end

count = 0
for i in text:
    if i.endswith("."):
        text[count] = re.sub("^([a-z]+)(.)?$", r"\1", i)
    count += 1
print("The count of Python : ", text.count("python"))
Vinay Kumar Kuresi
fonte
0
import re
abc = "askhnl#$%askdjalsdk"
ddd = abc.replace("#$%","")
print (ddd)

e você verá seu resultado como

'askhnlaskdjalsdk

Dsw Wds
fonte
4
aguarde .... você importou, remas nunca o usou. Seus replacecritérios funcionam apenas para essa sequência específica. E se a sua string for abc = "askhnl#$%!askdjalsdk"? Acho que não funcionará em nada além do #$%padrão. Pode querer ajustá-lo
JChao
0

Remoção de pontuações, números e caracteres especiais

Exemplo: -

insira a descrição da imagem aqui

Código

combi['tidy_tweet'] = combi['tidy_tweet'].str.replace("[^a-zA-Z#]", " ") 

Resultado:- insira a descrição da imagem aqui

Obrigado :)

Harish Kumawat
fonte
0

Para outros idiomas, como alemão, espanhol, dinamarquês, francês etc que contêm caracteres especiais (como o alemão "trema", como ü, ä, ö) simplesmente adicioná-los para a cadeia de pesquisa regex:

Exemplo para alemão:

re.sub('[^A-ZÜÖÄa-z0-9]+', '', mystring)
petezurich
fonte