Python, remova todos os caracteres não alfabéticos da string

93

Estou escrevendo um programa de contagem de palavras MapReduce em python. O problema é que existem muitos caracteres não alfabéticos espalhados nos dados, encontrei este post Removendo tudo, exceto caracteres alfanuméricos de uma string em Python, que mostra uma boa solução usando regex, mas não tenho certeza de como implementá-lo

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

Infelizmente, não tenho certeza de como usar a biblioteca reou mesmo regex para esse assunto. Não tenho certeza de como aplicar o padrão regex à string de entrada (linha de um livro) vpara recuperar a nova linha sem caracteres não alfanuméricos.

Sugestões?

KDecker
fonte
vé uma linha inteira de um livro (especificamente moby dick), estou falando palavra por palavra, não char por char. Portanto, algumas palavras podem ter um "," no final, então "indignidade", não mapeia com "indignidade".
KDecker
Lolx - você fez o mesmo exercício em casa antes da entrevista que eu? Encontre as 50 palavras mais usadas em Moby Dick e relate sua frequência. Fiz isso em C ++,
IIRC
1
@Mawg Foi um exercício na minha aula de graduação "Cloud Computing".
KDecker

Respostas:

130

Usar 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'

Alternativamente, se você deseja remover apenas um determinado conjunto de caracteres (como um apóstrofo pode ser adequado em sua entrada ...)

regex = re.compile('[,\.!?]') #etc.
limasxgoesto0
fonte
Hmm, eu posso rastreá-lo perfeitamente, mas e o padrão para remover todos os não alfanuméricos, exceto espaços?
KDecker
1
Basta adicionar um espaço em sua classe de coleção. ou seja, em ^a-zA-Z vez de apenas^a-zA-Z
limasxgoesto0
A menos que você também esteja preocupado com novas linhas, nesse caso a-zA-Z \n. Estou tentando encontrar uma regex que agrupe ambos em um, mas usando \wou \Wnão me dando o comportamento desejado. Você só precisa adicionar \nse for esse o caso.
limasxgoesto0
Ahh, o char de nova linha. É aí que estão meus problemas, eu estava comparando meus resultados com os resultados dados e ainda estava ausente. Acho que esse é o meu problema! Obrigado // Hmm, tentei com o char de nova linha dos mesmos resultados, acho que está faltando outro .. // Duhhh ... Maiúsculas e minúsculas ... // Obrigado por toda a ajuda, funciona perfeitamente agora!
KDecker
50

Se você preferir não usar regex, você pode tentar

''.join([i for i in s if i.isalpha()])
Tad
fonte
como faço para entrar nisso? com '' .join? impressão s obtém apenas um objeto de filtro
PirateApp
1
Uau, isso é o que eu estava procurando. Isso leva em consideração kanji, hiragana, katakana, etc. elogios
root163 de
34

Você pode usar a função re.sub () para remover estes caracteres:

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

re.sub (CORRESPONDER PADRÃO, SUBSTITUIR CADEIA, CADEIA PARA PESQUISAR)

  • "[^a-zA-Z]+" - procure qualquer grupo de caracteres que NÃO seja a-zA-z.
  • "" - Substitua os caracteres correspondentes por ""
Kevin
fonte
Observe que isso também removerá as letras acentuadas: ãâàáéèçõ, etc.
Brad Ahrens
19

Experimentar:

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

Isso pegará todos os caracteres da string, manterá apenas os alfanuméricos e construirá uma string a partir deles.

Don
fonte
2
Esta resposta pode ter muito mais explicação e links para documentação relevante.
pdoherty926
4

O método mais rápido é regex

#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
fonte
0

É aconselhável usar o módulo PyPiregex se você planeja combinar classes de propriedade Unicode específicas. Esta biblioteca também provou ser mais estável, especialmente lidando com textos grandes e produz resultados consistentes em várias versões do Python. Tudo o que você precisa fazer é mantê-lo atualizado.

Se você instalá-lo (usando pip intall regexou pip3 install regex), você pode usar

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

para remover todos os blocos de 1 ou mais caracteres diferentes de letras Unicode de text. Veja uma demonstração online do Python . Você também pode usar "".join(regex.findall(r'\p{L}+', 'ABCŁąć1-2!Абв3§4“5def”'))para obter o mesmo resultado.

Em Python re, para corresponder a qualquer letra Unicode, pode-se usar a [^\W\d_]construção ( Corresponder a qualquer letra Unicode? ).

Portanto, para remover todos os caracteres que não são letras, você pode combinar todas as letras e juntar os resultados:

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

Ou remova todos os caracteres diferentes daqueles correspondidos com [^\W\d_]:

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

Veja a demonstração de regex online . No entanto , você pode obter resultados inconsistentes em várias versões do Python porque o padrão Unicode está evoluindo e o conjunto de caracteres correspondentes \wdependerá da versão do Python. Usar a regexbiblioteca PyPi é altamente recomendável para obter resultados consistentes.

Wiktor Stribiżew
fonte