Usuń wszystkie znaki specjalne, znaki interpunkcyjne i spacje z łańcucha

236

Muszę usunąć wszystkie znaki specjalne, znaki interpunkcyjne i spacje z ciągu, aby mieć tylko litery i cyfry.

użytkownik664546
źródło

Odpowiedzi:

351

Można to zrobić bez wyrażenia regularnego:

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

Możesz użyć 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.

Jeśli nalegasz na użycie wyrażenia regularnego, inne rozwiązania sprawdzą się. Należy jednak pamiętać, że jeśli można tego dokonać bez użycia wyrażenia regularnego, jest to najlepszy sposób, aby to zrobić.

użytkownik225312
źródło
7
Jaki jest powód, dla którego reguła nie jest wyrażeniem regularnym?
Chris Dutrow
Wyrażenie regularne @ChrisDutrow jest wolniejsze niż wbudowane funkcje łańcucha python
Diego Navarro,
Działa to tylko wtedy, gdy ciąg znaków jest w Unicode . W przeciwnym razie narzeka, że ​​obiekt „str” nie ma atrybutu „isalnum” „isnumeric” i tak dalej.
NeoJi
10
@DiegoNavarro oprócz tego, że to nieprawda, porównałem obie isalnum()wersje i wyrażenia regularne, a jeden z
wyrażeń
2
Dodatkowo: „W przypadku ciągów 8-bitowych ta metoda zależy od ustawień regionalnych.”! Zatem alternatywa wyrażeń regularnych jest zdecydowanie lepsza!
Antti Haapala
232

Oto wyrażenie pasujące do ciągu znaków, które nie są literami ani cyframi:

[^A-Za-z0-9]+

Oto polecenie Pythona, aby wykonać podstawienie wyrażenia regularnego:

re.sub('[^A-Za-z0-9]+', '', mystring)
Andy White
źródło
10
KISS: Keep Simple Simple Głupi! Jest to krótsze i znacznie łatwiejsze do odczytania niż rozwiązania inne niż wyrażenia regularne, a także może być szybsze. (Dodałbym jednak +kwantyfikator, aby nieco poprawić jego wydajność.)
ridgerunner
1
usuwa to również spacje między słowami „świetne miejsce” -> „świetne miejsce”. Jak tego uniknąć?
Reihan_amn
5
@Reihan_amn Wystarczy dodać spację do wyrażenia regularnego, aby stała się:[^A-Za-z0-9 ]+
ostroon
1
@ andy-white, czy możesz dodać spację do wyrażenia regularnego w odpowiedzi? Spacja nie jest postacią specjalną ...
Ufos
3
Myślę, że to nie działa ze zmodyfikowanymi znakami w innych językach, takich jak á , ö , ñ itp. Czy mam rację? Jeśli tak, to jak by to wyglądało?
HuLu ViCa
50

Krótsza droga:

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

Jeśli chcesz, aby spacje między słowami i cyframi zastąpiły słowa „”

tuxErrante
źródło
3
Tyle że _ jest w \ w i jest znakiem specjalnym w kontekście tego pytania.
kkurian
Zależy od kontekstu - podkreślenie jest bardzo przydatne w nazwach plików i innych identyfikatorach, do tego stopnia, że ​​nie traktuję go jako znaku specjalnego, ale raczej zdezynfekowanej przestrzeni. Z reguły tej metody używam sam.
Echelon
1
r'\W+'- nieco nie na temat (i bardzo pedantyczny), ale sugeruję nawyk, aby wszystkie wzorce wyrażeń regularnych były surowymi łańcuchami
Bob Stein
2
Ta procedura nie traktuje podkreślenia (_) jako znaku specjalnego.
Md. Sabbir Ahmed
30

Po tym, zainteresowałem się rozszerzeniem podanych odpowiedzi, dowiedzieć się, które polecenie wykonuje się w jak najkrótszym czasie, więc przejrzałem i sprawdziłem niektóre z proponowanych odpowiedzi pod kątem timeitdwóch przykładowych ciągów:

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

Przykład 1

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

  • string1 - Wynik: 10,7061979771
  • string2 - Wynik: 7,78372597694

Przykład 2

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

  • string1 - Wynik: 7,17785102844
  • string2 - Wynik: 4,12814903259

Przykład 3

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

  • string1 - Wynik: 3,11899876595
  • string2 - Wynik: 2,78014397621

Powyższe wyniki są wynikiem najniższego zwracanego wyniku ze średniej: repeat(3, 2000000)

Przykład 3 może być 3 razy szybszy niż w przykładzie 1 .

mbeacom
źródło
@kkurian Jeśli czytasz początek mojej odpowiedzi, jest to jedynie porównanie wcześniej zaproponowanych rozwiązań powyżej. Być może zechcesz skomentować pierwotną odpowiedź ... stackoverflow.com/a/25183802/2560922
mbeacom
Och, rozumiem, gdzie idziesz z tym. Gotowe!
kkurian
1
W przypadku dużego korpusu należy wziąć pod uwagę przykład 3.
HARSH NILESH PATHAK
Ważny! Dziękuję za uwagę.
mbeacom
czy możesz porównać moją odpowiedź''.join([*filter(str.isalnum, string)])
Grijesh Chauhan
22

Python 2. *

Myślę, że po prostu filter(str.isalnum, string)działa

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

Python 3. *

W Python3 filter( )funkcja zwróci obiekt itertowalny (zamiast ciągu w przeciwieństwie do powyższego). Trzeba połączyć się z powrotem, aby uzyskać ciąg z itertable:

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

lub przekazać listdołączenie do użycia ( nie jestem pewien, ale może być trochę szybki )

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

Uwaga: rozpakowywanie jest [*args]ważne z Pythona> = 3.5

Grijesh Chauhan
źródło
4
@Alexey poprawić, W python3 map, filteri reduce powraca itertable Object zamiast. Nadal w Python3 + wolę ''.join(filter(str.isalnum, string)) (lub przekazać listę przy łączeniu ''.join([*filter(str.isalnum, string)])) niż zaakceptowaną odpowiedź.
Grijesh Chauhan
Nie jestem pewien, ''.join(filter(str.isalnum, string))czy poprawa filter(str.isalnum, string), przynajmniej do czytania. Czy to naprawdę jest Pythreenic (tak, możesz tego użyć), aby to zrobić?
TheProletariat
1
@TheProletariat Chodzi o to, po prostufilter(str.isalnum, string) nie zwracają ciąg w Python3 jak filter( )w Python3 zwraca iterator zamiast typu argumentu przeciwieństwie python-2 +.
Grijesh Chauhan
@GrijeshChauhan, myślę, że powinieneś zaktualizować swoją odpowiedź, aby zawierała zarówno rekomendacje Python2, jak i 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

możesz dodać więcej znaków specjalnych, które zostaną zastąpione przez „” oznacza nic, tzn. zostaną usunięte.

pkm
źródło
16

W odróżnieniu od innych osób używających wyrażenia regularnego, starałbym się wykluczyć każdą postać, która nie jest tym, czego chcę, zamiast wyraźnego wyliczenia tego, czego nie chcę.

Na przykład, jeśli chcę tylko znaki od „a do z” (wielkie i małe litery) oraz cyfry, wykluczę wszystko inne:

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

Oznacza to „zamień pusty znak na każdy znak, który nie jest liczbą, lub znak z zakresu od„ a do z ”lub„ A do Z ”.

W rzeczywistości, jeśli wstawisz znak specjalny ^na pierwszym miejscu wyrażenia regularnego, otrzymasz negację.

Dodatkowa wskazówka: jeśli musisz również pomniejszyć wynik, możesz sprawić, że wyrażenie regularne będzie jeszcze szybsze i łatwiejsze, o ile nie znajdziesz teraz wielkich liter.

import re
s = re.sub(r"[^a-z0-9]","",s.lower())
Andrea
źródło
9

Zakładając, że chcesz użyć wyrażenia regularnego i potrzebujesz / potrzebujesz kodu rozpoznającego Unicode 2.x, który jest gotowy na 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
źródło
7
s = re.sub(r"[-()\"#/@;:<>{}`+=~|.!?,]", "", s)
sneha
źródło
6

Najbardziej ogólnym podejściem jest użycie „kategorii” tabeli unicodedata, która klasyfikuje każdy pojedynczy znak. Np. Poniższy kod filtruje tylko znaki drukowalne na podstawie ich kategorii:

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

Spójrz na podany powyżej adres URL dla wszystkich powiązanych kategorii. Możesz także oczywiście filtrować według kategorii interpunkcyjnych.

Andreas Jung
źródło
O co chodzi $na końcu każdej linii?
John Machin
Jeśli to problem z kopiowaniem i wklejaniem, czy to należy naprawić?
Olli
5

string.punctuation zawiera następujące znaki:

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

Możesz użyć funkcji translacji i maketrans do mapowania interpunkcji na puste wartości (zamień)

import string

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

Wynik:

'This is A test'
Vlad Bezden
źródło
4

Użyj tłumacza:

import string

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

Uwaga: Działa tylko na ciągach ascii.

jjmurre
źródło
Różnica wersji? Dostaję TypeError: translate() takes exactly one argument (2 given)z 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 

to samo co podwójne cudzysłowy. ”„ ”

# 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
źródło
0
import re
abc = "askhnl#$%askdjalsdk"
ddd = abc.replace("#$%","")
print (ddd)

i zobaczysz swój wynik jako

„askhnlaskdjalsdk

Dsw Wds
źródło
4
czekaj .... zaimportowałeś, reale nigdy go nie użyłeś. Twoje replacekryteria działają tylko dla tego określonego ciągu. Co jeśli twój ciąg jest abc = "askhnl#$%!askdjalsdk"? Nie sądzę, że zadziała na czymkolwiek innym niż #$%wzór. Może chcę to poprawić
JChao
0

Usuwanie interpunkcji, cyfr i znaków specjalnych

Przykład: -

wprowadź opis zdjęcia tutaj

Kod

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

Wynik:- wprowadź opis zdjęcia tutaj

Dzięki :)

Harish Kumawat
źródło