Rimuovi caratteri specifici da una stringa in Python


548

Sto cercando di rimuovere caratteri specifici da una stringa usando Python. Questo è il codice che sto usando in questo momento. Sfortunatamente sembra non fare nulla alla stringa.

for char in line:
    if char in " ?.!/;:":
        line.replace(char,'')

Come posso farlo correttamente?


23
Sono passati più di 5 anni, ma come sull'utilizzo della filterfunzione e un'espressione Lambda: filter(lambda ch: ch not in " ?.!/;:", line). Abbastanza conciso ed efficiente, penso. Ovviamente, restituisce una nuova stringa a cui dovrai assegnare un nome.
John Red,

3
@JohnRed: In realtà restituisce un iteratore che restituisce un elenco di caratteri, ma se lo inserissi in una risposta, alcuni di noi sarebbero lieti di votarlo.
Bill Bell,


@BillBell: PS: è un iteratore in Python3 e una stringa, una tupla o un elenco in Python2
serv-inc,

Risposte:


628

Le stringhe in Python sono immutabili (non possono essere modificate). Per questo motivo, l'effetto di line.replace(...)è solo quello di creare una nuova stringa, anziché cambiare quella vecchia. È necessario ricollegarlo (assegnarlo) a per fare linein modo che quella variabile prenda il nuovo valore, con quei caratteri rimossi.

Inoltre, il modo in cui lo fai sarà un po 'lento, relativamente. È anche probabile che sia un po 'confuso per i pitoni esperti, che vedranno una struttura doppiamente annidata e penseranno per un momento che sta succedendo qualcosa di più complicato.

A partire da Python 2.6 e versioni successive di Python 2.x *, puoi invece utilizzare str.translate(ma continua a leggere per le differenze di Python 3):

line = line.translate(None, '!@#$')

o sostituzione di espressioni regolari con re.sub

import re
line = re.sub('[!@#$]', '', line)

I caratteri racchiusi tra parentesi costituiscono una classe di caratteri . Tutti i caratteri in linequella classe vengono sostituiti con il secondo parametro in sub: una stringa vuota.

In Python 3, le stringhe sono Unicode. Dovrai tradurre in modo leggermente diverso. kevpie menziona questo in un commento su una delle risposte, ed è annotato nella documentazione distr.translate .

Quando si chiama il translatemetodo di una stringa Unicode, non è possibile passare il secondo parametro che abbiamo usato sopra. Inoltre, non puoi passare Nonecome primo parametro. Invece, si passa una tabella di traduzione (di solito un dizionario) come unico parametro. Questa tabella mappa i valori ordinali dei caratteri (cioè il risultato della ordloro chiamata ) ai valori ordinali dei caratteri che dovrebbero sostituirli o - utilmente a noi - Noneper indicare che dovrebbero essere eliminati.

Quindi per fare la danza sopra con una stringa Unicode chiameresti qualcosa del genere

translation_table = dict.fromkeys(map(ord, '!@#$'), None)
unicode_line = unicode_line.translate(translation_table)

Qui dict.fromkeyse mapvengono utilizzati per generare in modo succinto un dizionario contenente

{ord('!'): None, ord('@'): None, ...}

Ancora più semplice, come dice un'altra risposta , crea la tabella di traduzione in atto:

unicode_line = unicode_line.translate({ord(c): None for c in '!@#$'})

Oppure crea la stessa tabella di traduzione con str.maketrans:

unicode_line = unicode_line.translate(str.maketrans('', '', '!@#$'))

* per compatibilità con Pythons precedenti, è possibile creare una tabella di traduzione "null" da passare al posto di None:

import string
line = line.translate(string.maketrans('', ''), '!@#$')

Qui string.maketransviene utilizzato per creare una tabella di traduzione , che è solo una stringa contenente i caratteri con valori ordinali da 0 a 255.


26
In Python3, line.translateaccetta solo un argomento e la prima soluzione non funzionerà
marczoid,

33
In python3, str.translate () non accetta il secondo argomento. Quindi, la tua risposta diventerà line.translate({ord(i):None for i in '!@#$'})
naveen, il

1
Come qualsiasi altro personaggio. Python ti consente di usare coppie di virgolette singole o doppie. Quindi scrivi solo "'"per il set di caratteri.
intuito il

2
Il commento di @ naveen sopra ha funzionato per me. Pythony 2.7.13. Nel mio caso volevo eliminare "e 'i personaggi:notes = notes.translate({ord(i):None for i in '\"\''})
RyanG

1
In Python 3, puoi usare unicode_line.translate(str.maketrans('', '', '!@#$')). Oppureunicode_line.translate(dict.fromkeys(map(ord, '!@#$')))
Martijn Pieters

234

Mi manca il punto qui, o è solo il seguente:

string = "ab1cd1ef"
string = string.replace("1","") 

print string
# result: "abcdef"

Mettilo in un ciclo:

a = "a!b@c#d$"
b = "!@#$"
for char in b:
    a = a.replace(char,"")

print a
# result: "abcd"

26
Questo farà una copia della stringa in ogni ciclo, che potrebbe non essere desiderabile. Inoltre non è molto buono Python. In Python invece for char in b: a=a.replace(char,"")
andresti in

2
usare variabili definite dall'utente che si sovrappongono alle classi di sistema non è una buona idea. Dovresti usare la variabile STRING invece di STR e C invece di CHAR.
Ayrat,

Deve essere string=string.replace("1","")invece. Hai detto questo nella parte del ciclo del tuo esempio, ma la maggior parte delle persone non leggerà così tanto nella tua risposta fino a quando non avranno manipolato il codice un po 'prima per una domanda così semplice.
CodeMed

Una buona soluzione ma non come Python-esk come una delle altre.
Steve

45
>>> line = "abc#@!?efg12;:?"
>>> ''.join( c for c in line if  c not in '?:!/;' )
'abc#@efg12'

usa un altro delimitatore di stringa come '' 'o "
ALisboa

1
Se hai molti caratteri proibiti, puoi velocizzare il tuo codice trasformandolo prima in un set. blacklist = set('?:!/;')e poi''.join(c for c in line if c not in blacklist)
Boris

32

Peasy facile con re.subespressione regolare a partire da Python 3.5

re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)

Esempio

>>> import re

>>> line = 'Q: Do I write ;/.??? No!!!'

>>> re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)
'QDoIwriteNo'

Spiegazione

Nelle espressioni regolari (regex), |è un OR logico e \sfugge a spazi e caratteri speciali che potrebbero essere veri e propri comandi regex. Considerando che substa per la sostituzione, in questo caso con la stringa vuota ''.


22

Per il requisito inverso di consentire solo determinati caratteri in una stringa, è possibile utilizzare espressioni regolari con un operatore complemento set [^ABCabc]. Ad esempio, per rimuovere tutto tranne le lettere ASCII, le cifre e il trattino:

>>> import string
>>> import re
>>>
>>> phrase = '  There were "nine" (9) chick-peas in my pocket!!!      '
>>> allow = string.letters + string.digits + '-'
>>> re.sub('[^%s]' % allow, '', phrase)

'Therewerenine9chick-peasinmypocket'

Dalla documentazione sull'espressione regolare di Python :

I personaggi che non si trovano in un intervallo possono essere abbinati completando il set. Se il primo carattere del set è '^', verranno abbinati tutti i personaggi che non sono nel set. Ad esempio, [^5]corrisponderà a qualsiasi carattere tranne "5" e [^^]corrisponderà a qualsiasi carattere tranne '^'. ^non ha alcun significato speciale se non è il primo personaggio nel set.


19

L'assassino ce l'aveva quasi. Come la maggior parte delle cose in Python, la risposta è più semplice di quanto pensi.

>>> line = "H E?.LL!/;O:: "  
>>> for char in ' ?.!/;:':  
...  line = line.replace(char,'')  
...
>>> print line
HELLO

Non devi fare la cosa nidificata if / for loop, ma devi controllare ogni personaggio individualmente.


sì, lo so, probabilmente è troppo tardi, ma dovrebbe funzionare se si evita. In questo modo: line = line.replace ('' ',' ') continua a leggere: learnpythonthehardway.org/book/ex10.html
Aiyion.Prime,

Questo probabilmente non è performante perché stai allocando una nuova stringa per ogni personaggio
OneCricketeer


11
>>> s = 'a1b2c3'
>>> ''.join(c for c in s if c not in '123')
'abc'

2
La mia risposta fornisce una soluzione alla domanda originale, ma ero anche interessato (forse anche al PO) al feedback sul perché la mia soluzione potrebbe non essere l'ideale. Avrei dovuto creare una nuova domanda e fare riferimento a questa per contesto?
Eatkin,

Questo ottiene il mio voto. Python conciso
Steve

9

Le stringhe sono immutabili in Python. Il replacemetodo restituisce una nuova stringa dopo la sostituzione. Provare:

for char in line:
    if char in " ?.!/;:":
        line = line.replace(char,'')

Come puoi iterare sulla linea e modificarla allo stesso tempo?
eumiro,

1
@eumiro: l'iterazione procede sull'originale line .
Greg Hewgill,

buono a sapersi! Quindi, se eseguo l'iterazione su un array, eseguo l'iterazione su un array originale. L'iterazione su un iteratore non sarebbe possibile.
eumiro,

9

Sono rimasto sorpreso dal fatto che nessuno avesse ancora raccomandato di utilizzare la funzione di filtro integrata.

    import operator
    import string # only for the example you could use a custom string

    s = "1212edjaq"

Supponiamo di voler filtrare tutto ciò che non è un numero. L'uso del metodo del filtro incorporato "... equivale all'espressione del generatore (elemento per elemento in iterabile se funzione (oggetto))" [ Python 3 Builtins: Filter ]

    sList = list(s)
    intsList = list(string.digits)
    obj = filter(lambda x: operator.contains(intsList, x), sList)))

In Python 3 questo ritorna

    >>  <filter object @ hex>

Per ottenere una stringa stampata,

    nums = "".join(list(obj))
    print(nums)
    >> "1212"

Non sono sicuro di come filtro classifica il in termini di efficienza, ma è una buona cosa sapere come usare quando si fanno le liste e simili.

AGGIORNARE

Logicamente, poiché il filtro funziona, puoi anche usare la comprensione dell'elenco e da quello che ho letto dovrebbe essere più efficiente perché lambda sono i gestori di hedge fund di Wall Street nel mondo delle funzioni di programmazione. Un altro vantaggio è che si tratta di un one-liner che non richiede alcuna importazione. Ad esempio, utilizzando le stesse stringhe definite sopra,

      num = "".join([i for i in s if i.isdigit()])

Questo è tutto. Il ritorno sarà una stringa di tutti i caratteri che sono cifre nella stringa originale.

Se si dispone di un elenco specifico di caratteri accettabili / inaccettabili, è necessario solo modificare la parte "if" della comprensione dell'elenco.

      target_chars = "".join([i for i in s if i in some_list]) 

o in alternativa,

      target_chars = "".join([i for i in s if i not in some_list])

Non c'è motivo di utilizzare operator.containsse si utilizza lambdacomunque un . lambda x: operator.contains(intsList, x)dovrebbe essere scritto lambda x: x in intsList, o se stai cercando di ottenere il controllo del livello C, intsList.__contains__(no lambda) farà il trucco.
ShadowRanger

8

Usando filter, avresti solo bisogno di una riga

line = filter(lambda char: char not in " ?.!/;:", line)

Questo considera la stringa come iterabile e controlla ogni carattere se lambdarestituisce True:

>>> help(filter)
Help on built-in function filter in module __builtin__:

filter(...)
    filter(function or None, sequence) -> list, tuple, or string

    Return those items of sequence for which function(item) is true.  If
    function is None, return the items that are true.  If sequence is a tuple
    or string, return the same type, else return a list.

4

Ecco alcuni modi possibili per raggiungere questo obiettivo:

def attempt1(string):
    return "".join([v for v in string if v not in ("a", "e", "i", "o", "u")])


def attempt2(string):
    for v in ("a", "e", "i", "o", "u"):
        string = string.replace(v, "")
    return string


def attempt3(string):
    import re
    for v in ("a", "e", "i", "o", "u"):
        string = re.sub(v, "", string)
    return string


def attempt4(string):
    return string.replace("a", "").replace("e", "").replace("i", "").replace("o", "").replace("u", "")


for attempt in [attempt1, attempt2, attempt3, attempt4]:
    print(attempt("murcielago"))

PS: Invece usando "?.! / ;:" gli esempi usano le vocali ... e sì, "murcielago" è la parola spagnola per dire pipistrello ... parola divertente in quanto contiene tutte le vocali :)

PS2: se sei interessato alle prestazioni potresti misurare questi tentativi con un semplice codice come:

import timeit


K = 1000000
for i in range(1,5):
    t = timeit.Timer(
        f"attempt{i}('murcielago')",
        setup=f"from __main__ import attempt{i}"
    ).repeat(1, K)
    print(f"attempt{i}",min(t))

Nella mia scatola troverai:

attempt1 2.2334518376057244
attempt2 1.8806643818474513
attempt3 7.214925774955572
attempt4 1.7271184513757465

Quindi sembra che il tentativo4 sia il più veloce per questo particolare input.


1
Stai creando un inutile listin attempt1e la tupla può essere riscritta "aeiou"per semplicità (rimuovendola [e ]trasformandola in un generatore senza creare un elenco). Si creano tonnellate di stringhe intermedie attemt2usa e getta , si utilizzano più applicazioni di regex in attempt3cui è possibile utilizzare r'[aeiou]'in un passaggio. ognuno ha dei difetti - è bello vedere modi diversi di fare le cose, ma per favore correggili anche come buoni tentativi
Patrick Artner,

1
@PatrickArtner Hai assolutamente ragione ... dai dozzine di modi che ho in mente per realizzare questo compito, ho raccolto quelli più lenti (volevo mostrarne alcuni più facili) ... Detto questo, dopo di te ragazzi ho chiuso l'altro thread Ho perso la motivazione a fare uno sforzo maggiore su questo vecchio thread già risposto, quindi ... :). Grazie per i punti però.
BPL,

@PatrickArtner Ok ... solo per amor di più ne ha aggiunto uno nuovo, "tentativo4" ... non ho misurato ma penso che uno dovrebbe essere il più veloce
BPL

1
@PatrickArtner Edited ... try4 è stato il più veloce tra i pochi tentativi. Comunque, non sto perdendo altro tempo con queste cose :)
BPL

3

Ecco la mia versione compatibile con Python 2/3. Da quando l'API di traduzione è cambiata.

def remove(str_, chars):
    """Removes each char in `chars` from `str_`.

    Args:
        str_: String to remove characters from
        chars: String of to-be removed characters

    Returns:
        A copy of str_ with `chars` removed

    Example:
            remove("What?!?: darn;", " ?.!:;") => 'Whatdarn'
    """
    try:
        # Python2.x
        return str_.translate(None, chars)
    except TypeError:
        # Python 3.x
        table = {ord(char): None for char in chars}
        return str_.translate(table)

Userei dict.fromkeys(map(ord, '!@#$'))per creare la mappa.
Martijn Pieters

mapè generalmente meno leggibile di un elenco / dict / set / comprensione del generatore. Tanto che Guido voleva rimuoverlo dalla lingua . L'uso fromkeysè anche un po 'intelligente e richiede un controllo del documento.
Bryce Guinta,

1
@MartijnPieters: per Python 3, dovrebbe essere str.maketrans('', '', chars), che gestisce la ordconversione e la dictcostruzione tutto in una volta (per non parlare dell'essere piuttosto più ovvio nell'intento, poiché è progettato per accoppiarsi str.translate).
ShadowRanger

1
#!/usr/bin/python
import re

strs = "how^ much for{} the maple syrup? $20.99? That's[] ricidulous!!!"
print strs
nstr = re.sub(r'[?|$|.|!|a|b]',r' ',strs)#i have taken special character to remove but any #character can be added here
print nstr
nestr = re.sub(r'[^a-zA-Z0-9 ]',r'',nstr)#for removing special character
print nestr

Intendi i segni del discorso? re ha una barra rovesciata per sfuggire al codice e considerarlo 'come una stringa. docs.python.org/2/library/re.html
JasTonAChair

1

Cosa ne pensi di questo:

def text_cleanup(text):
    new = ""
    for i in text:
        if i not in " ?.!/;:":
            new += i
    return new

1
Potresti elaborare di più la tua risposta aggiungendo un po 'più di descrizione della soluzione che offri?
Abarisone,

Aggiungere a un elenco, quindi utilizzare join sarebbe più efficiente della concatenazione
OneCricketeer,

1

È inoltre possibile utilizzare una funzione per sostituire diversi tipi di espressione regolare o altri schemi con l'uso di un elenco. Con ciò, puoi mescolare espressioni regolari, classe di caratteri e pattern di testo davvero basilari. È davvero utile quando è necessario sostituire molti elementi come quelli HTML.

* NB: funziona con Python 3.x

import re  # Regular expression library


def string_cleanup(x, notwanted):
    for item in notwanted:
        x = re.sub(item, '', x)
    return x

line = "<title>My example: <strong>A text %very% $clean!!</strong></title>"
print("Uncleaned: ", line)

# Get rid of html elements
html_elements = ["<title>", "</title>", "<strong>", "</strong>"]
line = string_cleanup(line, html_elements)
print("1st clean: ", line)

# Get rid of special characters
special_chars = ["[!@#$]", "%"]
line = string_cleanup(line, special_chars)
print("2nd clean: ", line)

Nella funzione string_cleanup, accetta la stringa x e l'elenco non desiderato come argomenti. Per ogni elemento in quell'elenco di elementi o pattern, se è necessario un sostituto, verrà fatto.

Il risultato:

Uncleaned:  <title>My example: <strong>A text %very% $clean!!</strong></title>
1st clean:  My example: A text %very% $clean!!
2nd clean:  My example: A text very clean

1

Il mio metodo che userei probabilmente non funzionerebbe in modo altrettanto efficiente, ma è enormemente semplice. Posso rimuovere contemporaneamente più personaggi in diverse posizioni, usando lo slicing e la formattazione. Ecco un esempio:

words = "things"
removed = "%s%s" % (words[:3], words[-1:])

Ciò si tradurrà in "rimosso" tenendo la parola "questo".

La formattazione può essere molto utile per stampare variabili a metà strada attraverso una stringa di stampa. Può inserire qualsiasi tipo di dati usando una % seguita dal tipo di dati della variabile; tutti i tipi di dati possono usare % s , e i float (ovvero i decimali) e gli interi possono usare % d .

L'affettatura può essere utilizzata per un controllo complesso delle stringhe. Quando inserisco le parole [: 3] , mi consente di selezionare tutti i caratteri nella stringa dall'inizio (i due punti sono prima del numero, questo significherà "dall'inizio a") al 4 ° carattere (include il 4 ° carattere). Il motivo 3 equivale fino alla quarta posizione è perché Python inizia da 0. Quindi, quando inserisco la parola [-1:] , significa il 2 ° ultimo carattere alla fine (i due punti sono dietro il numero). Mettere -1 farà contare Python dall'ultimo carattere, piuttosto che dal primo. Ancora una volta, Python inizierà da 0. Quindi, la parola [-1:] significa sostanzialmente "dal penultimo carattere alla fine della stringa.

Quindi, tagliando i personaggi prima del personaggio che voglio rimuovere e i personaggi dopo e inserendoli insieme, posso rimuovere il personaggio indesiderato. Pensalo come una salsiccia. Nel mezzo è sporco, quindi voglio liberarmene. Ho semplicemente tagliato le due estremità che desidero, quindi le ho unite senza la parte indesiderata nel mezzo.

Se voglio rimuovere più caratteri consecutivi, sposto semplicemente i numeri in giro nella [] (sezione di taglio). O se voglio rimuovere più personaggi da posizioni diverse, posso semplicemente mettere insieme più fette contemporaneamente.

Esempi:

 words = "control"
 removed = "%s%s" % (words[:2], words[-2:])

rimosso equivale a "cool".

words = "impacts"
removed = "%s%s%s" % (words[1], words[3:5], words[-1])

rimosso equivale a "mac".

In questo caso, [3: 5] indica il carattere nella posizione 3 attraverso il carattere nella posizione 5 (escluso il carattere nella posizione finale).

Ricorda, Python inizia a contare da 0 , quindi dovrai farlo anche tu.


0

Prova questo:

def rm_char(original_str, need2rm):
    ''' Remove charecters in "need2rm" from "original_str" '''
    return original_str.translate(str.maketrans('','',need2rm))

Questo metodo funziona bene in Python 3.5.2


0

È possibile utilizzare la sostituzione dell'espressione regolare del modulo re. L'uso dell'espressione ^ ti permette di scegliere esattamente quello che vuoi dalla tua stringa.

    import re
    text = "This is absurd!"
    text = re.sub("[^a-zA-Z]","",text) # Keeps only Alphabets
    print(text)

Il risultato sarebbe "Thisisabsurd". Appariranno solo le cose specificate dopo il simbolo ^.


0

Il metodo string replacenon modifica la stringa originale. Lascia l'originale da solo e restituisce una copia modificata.

Quello che vuoi è qualcosa di simile: line = line.replace(char,'')

def replace_all(line, )for char in line:
    if char in " ?.!/;:":
        line = line.replace(char,'')
    return line

Tuttavia, la creazione di una nuova stringa ogni volta che un carattere viene rimosso è molto inefficiente. Consiglio invece quanto segue:

def replace_all(line, baddies, *):
    """
    The following is documentation on how to use the class,
    without reference to the implementation details:

    For implementation notes, please see comments begining with `#`
    in the source file.

    [*crickets chirp*]

    """

    is_bad = lambda ch, baddies=baddies: return ch in baddies
    filter_baddies = lambda ch, *, is_bad=is_bad: "" if is_bad(ch) else ch
    mahp = replace_all.map(filter_baddies, line)
    return replace_all.join('', join(mahp))

    # -------------------------------------------------
    # WHY `baddies=baddies`?!?
    #     `is_bad=is_bad`
    # -------------------------------------------------
    # Default arguments to a lambda function are evaluated
    # at the same time as when a lambda function is
    # **defined**.
    #
    # global variables of a lambda function
    # are evaluated when the lambda function is
    # **called**
    #
    # The following prints "as yellow as snow"
    #
    #     fleece_color = "white"
    #     little_lamb = lambda end: return "as " + fleece_color + end
    #
    #     # sometime later...
    #
    #     fleece_color = "yellow"
    #     print(little_lamb(" as snow"))
    # --------------------------------------------------
replace_all.map = map
replace_all.join = str.join

-1

Sotto uno .. senza usare il concetto di espressione regolare ..

ipstring ="text with symbols!@#$^&*( ends here"
opstring=''
for i in ipstring:
    if i.isalnum()==1 or i==' ':
        opstring+=i
    pass
print opstring

-1

In Python 3.5

per esempio,

os.rename(file_name, file_name.translate({ord(c): None for c in '0123456789'}))

Per rimuovere tutto il numero dalla stringa



-1

Divisione ricorsiva: s = stringa; chars = chars da rimuovere

def strip(s,chars):
if len(s)==1:
    return "" if s in chars else s
return strip(s[0:int(len(s)/2)],chars) +  strip(s[int(len(s)/2):len(s)],chars)

esempio:

print(strip("Hello!","lo"))    #He!

-1

# per ciascun file in una directory, rinominare il nome file

   file_list = os.listdir (r"D:\Dev\Python")

   for file_name in file_list:

       os.rename(file_name, re.sub(r'\d+','',file_name))

-1

Anche l'approccio di seguito funziona

line = "a,b,c,d,e"
alpha = list(line)
        while ',' in alpha:
            alpha.remove(',')
finalString = ''.join(alpha)
print(finalString)

produzione: abcde


-2
>>> # Character stripping
>>> a = '?abcd1234!!'
>>> t.lstrip('?')
'abcd1234!!'
>>> t.strip('?!')
'abcd1234'

10
Rimuove solo i caratteri dall'inizio o dalla fine della stringa
divenex il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.