Come rimuovo una sottostringa dalla fine di una stringa in Python?


382

Ho il codice seguente:

url = 'abcdc.com'
print(url.strip('.com'))

Mi aspettavo: abcdc

Ho ottenuto: abcd

Ora faccio

url.rsplit('.com', 1)

Esiste un modo migliore?


6
strip toglie i caratteri dati da entrambe le estremità della stringa, nel tuo caso rimuove ".", "c", "o" e "m".
truppo,

6
Rimuoverà anche quei caratteri dalla parte anteriore della stringa. Se vuoi solo rimuoverlo dalla fine, usa rstrip ()
Andre Miller il

42
Si. str.strip non fa quello che pensi che faccia. str.strip rimuove uno qualsiasi dei caratteri specificati dall'inizio e dalla fine della stringa. Quindi, "acbacda" .strip ("annuncio") dà "cbac"; la a all'inizio e la da alla fine erano spogliate. Saluti.
scvalex,

2
Inoltre, ciò rimuove i caratteri in qualsiasi ordine : "site.ocm"> "site".
Eric O Lebigot,

1
@scvalex, wow mi sono appena reso conto di averlo usato per così tanto tempo - è pericoloso perché il codice spesso funziona comunque
Flash

Risposte:


556

stripnon significa "rimuovi questa sottostringa". x.strip(y)tratta ycome un set di caratteri e rimuove tutti i personaggi di quel set dalle estremità di x.

Invece, puoi usare endswithe tagliare:

url = 'abcdc.com'
if url.endswith('.com'):
    url = url[:-4]

O usando espressioni regolari :

import re
url = 'abcdc.com'
url = re.sub('\.com$', '', url)

4
Sì, io stesso penso che il primo esempio, con il test di endwith (), sarebbe il migliore; quello regex comporterebbe una certa penalità prestazionale (analisi della regex, ecc.). Non andrei con quello rsplit (), ma è perché non so cosa stai esattamente cercando di ottenere. Immagino stia rimuovendo il .com se e solo se appare alla fine dell'URL? La soluzione rsplit ti darebbe problemi se la usassi su nomi di dominio come "www.commercialthingie.co.uk"
Steef

13
url = url[:-4] if any(url.endswith(x) for x in ('.com','.net')) else url
Burhan Khalid,

1
cosa succede se scrivo EXAMLPLE.COMnomi di dominio non fanno distinzione tra maiuscole e minuscole. (Questo è un voto per la soluzione regex)
Jasen,

3
Non è una riscrittura, la rsplit()soluzione non ha lo stesso comportamento di endswith()quella quando la stringa originale non ha la sottostringa alla fine, ma da qualche parte nel mezzo. Ad esempio: "www.comeandsee.com".rsplit(".com",1)[0] == "www.comeandsee"ma"www.comeandsee.net".rsplit(".com",1)[0] == "www"
Steef

1
La sintassi s[:-n]ha un avvertimento: per n = 0, questo non restituisce la stringa con gli ultimi zero caratteri tagliati, ma invece la stringa vuota.
BlenderBender,

90

Se sei sicuro che la stringa appare solo alla fine, il modo più semplice sarebbe usare 'sostituisci':

url = 'abcdc.com'
print(url.replace('.com',''))

56
che sostituirà anche l'URL come www.computerhope.com. fare un controllo con endswith()e dovrebbe andare bene.
ghostdog74

72
"www.computerhope.com".endswith(".com")è vero, si romperà ancora!

1
"Se sei sicuro che la stringa appare solo alla fine" intendi "Se sei sicuro che la sottostringa appare una sola volta"? sostituire sembra funzionare anche quando la sottostringa è nel mezzo, ma come l'altro commento suggerisce che sostituirà qualsiasi occorrenza della sottostringa, perché dovrebbe essere alla fine non capisco
idclev 463035818

49
def strip_end(text, suffix):
    if not text.endswith(suffix):
        return text
    return text[:len(text)-len(suffix)]

4
Se sai che il suffisso non è vuoto (come quando è una costante), allora: return text [: - len (suffix)]
MarcH

4
Grazie. L'ultima riga potrebbe essere abbreviata:return text[:-len(suffix)]
Jabba

3
@Jabba: Purtroppo, non funzionerà con suffissi vuoti, come ha detto fuenfundachtzig.
yairchu,

46

Dal momento che sembra che nessuno lo abbia ancora sottolineato:

url = "www.example.com"
new_url = url[:url.rfind(".")]

Questo dovrebbe essere più efficiente dei metodi che utilizzano split()poiché non viene creato alcun nuovo oggetto elenco e questa soluzione funziona per stringhe con più punti.


Caspita, è un bel trucco. Non riuscivo a far fallire questo, ma ho anche avuto difficoltà a pensare a come questo potrebbe fallire. Mi piace, ma è molto "magico", difficile sapere cosa fa semplicemente guardandolo. Ho dovuto elaborare mentalmente ogni parte della linea per "ottenerla".
DevPlayer

14
Ciò non riesce se la stringa cercata NON è presente e rimuove erroneamente l'ultimo carattere.
robbat2,

25

Dipende da ciò che sai sul tuo url ed esattamente cosa stai cercando di fare. Se sai che finirà sempre in '.com' (o '.net' o '.org'), allora

 url=url[:-4]

è la soluzione più rapida. Se si tratta di un URL più generale, probabilmente è meglio cercare nella libreria urlparse fornita con Python.

Se invece vuoi semplicemente rimuovere tutto dopo il '.' Finale in una stringa quindi

url.rsplit('.',1)[0]

funzionerà. O se vuoi solo tutto fino al primo "." quindi prova

url.split('.',1)[0]

16

Se sai che è un'estensione, allora

url = 'abcdc.com'
...
url.rsplit('.', 1)[0]  # split at '.', starting from the right, maximum 1 split

Funziona ugualmente bene con abcdc.como www.abcdc.como abcdc.[anything]ed è più estensibile.


12

In una riga:

text if not text.endswith(suffix) or len(suffix) == 0 else text[:-len(suffix)]

8

Che ne dici url[:-4]?


Sembra quasi garantito che porti a un bug una volta che vieni colpito con a .cao .co.ukurl.
Peter

7

Per gli URL (poiché sembra essere una parte dell'argomento dell'esempio fornito), si può fare qualcosa del genere:

import os
url = 'http://www.stackoverflow.com'
name,ext = os.path.splitext(url)
print (name, ext)

#Or:
ext = '.'+url.split('.')[-1]
name = url[:-len(ext)]
print (name, ext)

Entrambi produrranno: ('http://www.stackoverflow', '.com')

Questo può anche essere combinato con str.endswith(suffix)se hai solo bisogno di dividere ".com" o qualcosa di specifico.


5

url.rsplit ('. com', 1)

non è del tutto giusto.

Quello che dovresti effettivamente scrivere è

url.rsplit('.com', 1)[0]

, e sembra IMHO piuttosto conciso.

Tuttavia, la mia preferenza personale è questa opzione perché utilizza solo un parametro:

url.rpartition('.com')[0]

1
La partizione +1 è preferita quando è necessaria una sola divisione poiché restituisce sempre una risposta, non si verificherà un IndexError.
Gringo Suave,


2

Se hai bisogno di eliminare qualche estremità di una stringa se esiste, altrimenti non fare nulla. Le mie migliori soluzioni Probabilmente vorrai usare una delle prime 2 implementazioni, tuttavia ho incluso la terza per completezza.

Per un suffisso costante:

def remove_suffix(v, s):
    return v[:-len(s) if v.endswith(s) else v
remove_suffix("abc.com", ".com") == 'abc'
remove_suffix("abc", ".com") == 'abc'

Per una regex:

def remove_suffix_compile(suffix_pattern):
    r = re.compile(f"(.*?)({suffix_pattern})?$")
    return lambda v: r.match(v)[1]
remove_domain = remove_suffix_compile(r"\.[a-zA-Z0-9]{3,}")
remove_domain("abc.com") == "abc"
remove_domain("sub.abc.net") == "sub.abc"
remove_domain("abc.") == "abc."
remove_domain("abc") == "abc"

Per una raccolta di suffissi costanti il ​​modo asintoticamente più veloce per un gran numero di chiamate:

def remove_suffix_preprocess(*suffixes):
    suffixes = set(suffixes)
    try:
        suffixes.remove('')
    except KeyError:
        pass

    def helper(suffixes, pos):
        if len(suffixes) == 1:
            suf = suffixes[0]
            l = -len(suf)
            ls = slice(0, l)
            return lambda v: v[ls] if v.endswith(suf) else v
        si = iter(suffixes)
        ml = len(next(si))
        exact = False
        for suf in si:
            l = len(suf)
            if -l == pos:
                exact = True
            else:
                ml = min(len(suf), ml)
        ml = -ml
        suffix_dict = {}
        for suf in suffixes:
            sub = suf[ml:pos]
            if sub in suffix_dict:
                suffix_dict[sub].append(suf)
            else:
                suffix_dict[sub] = [suf]
        if exact:
            del suffix_dict['']
            for key in suffix_dict:
                suffix_dict[key] = helper([s[:pos] for s in suffix_dict[key]], None)
            return lambda v: suffix_dict.get(v[ml:pos], lambda v: v)(v[:pos])
        else:
            for key in suffix_dict:
                suffix_dict[key] = helper(suffix_dict[key], ml)
            return lambda v: suffix_dict.get(v[ml:pos], lambda v: v)(v)
    return helper(tuple(suffixes), None)
domain_remove = remove_suffix_preprocess(".com", ".net", ".edu", ".uk", '.tv', '.co.uk', '.org.uk')

quello finale è probabilmente molto più veloce in pypy che in cpython. La variante regex è probabilmente più veloce di questa per praticamente tutti i casi che non coinvolge enormi dizionari di potenziali suffissi che non possono essere facilmente rappresentati come regex almeno in cPython.

In PyPy la variante regex è quasi certamente più lenta per un gran numero di chiamate o stringhe lunghe anche se il modulo re utilizza un motore regex di compilazione DFA poiché la maggior parte del sovraccarico del lambda sarà ottimizzata dal JIT.

In cPython, tuttavia, il fatto che il codice c in esecuzione per il regex paragona quasi sicuramente i vantaggi algoritmici della versione della raccolta di suffissi in quasi tutti i casi.


2

Se intendi eliminare solo l'estensione:

'.'.join('abcdc.com'.split('.')[:-1])
# 'abcdc'

Funziona con qualsiasi estensione, con potenziali altri punti presenti anche nel nome file. Divide semplicemente la stringa come un elenco di punti e la unisce senza l'ultimo elemento.


2
import re

def rm_suffix(url = 'abcdc.com', suffix='\.com'):
    return(re.sub(suffix+'$', '', url))

Voglio ripetere questa risposta come il modo più espressivo per farlo. Ovviamente, il seguente richiederebbe meno tempo della CPU:

def rm_dotcom(url = 'abcdc.com'):
    return(url[:-4] if url.endswith('.com') else url)

Tuttavia, se la CPU è il collo di bottiglia, perché scrivere in Python?

Quando la CPU è comunque un collo di bottiglia? Nei driver, forse.

I vantaggi dell'utilizzo dell'espressione regolare sono la riusabilità del codice. Che cosa succede se si desidera rimuovere ".me", che ha solo tre caratteri?

Lo stesso codice farebbe il trucco:

>>> rm_sub('abcdc.me','.me')
'abcdc'

1

Nel mio caso avevo bisogno di sollevare un'eccezione, quindi ho fatto:

class UnableToStripEnd(Exception):
    """A Exception type to indicate that the suffix cannot be removed from the text."""

    @staticmethod
    def get_exception(text, suffix):
        return UnableToStripEnd("Could not find suffix ({0}) on text: {1}."
                                .format(suffix, text))


def strip_end(text, suffix):
    """Removes the end of a string. Otherwise fails."""
    if not text.endswith(suffix):
        raise UnableToStripEnd.get_exception(text, suffix)
    return text[:len(text)-len(suffix)]


1

Supponendo di voler rimuovere il dominio, qualunque esso sia (.com, .net, ecc.). Consiglio di trovare .e rimuovere tutto da quel momento in poi.

url = 'abcdc.com'
dot_index = url.rfind('.')
url = url[:dot_index]

Qui sto usando rfindper risolvere il problema di URL come abcdc.com.netche dovrebbe essere ridotto al nome abcdc.com.

Se sei anche preoccupato per www.s, dovresti verificarlo esplicitamente:

if url.startswith("www."):
   url = url.replace("www.","", 1)

Il 1 in sostituzione è per strane edgecase come www.net.www.com

Se il tuo URL diventa più selvaggio di quello, guarda le risposte regex con cui le persone hanno risposto.


1

Ho usato la funzione rstrip integrata per farlo come segue:

string = "test.com"
suffix = ".com"
newstring = string.rstrip(suffix)
print(newstring)
test

Cattiva idea. Prova "test.ccom".
Shital Shah,

Ma questo non è il punto della domanda. È stato appena chiesto di rimuovere una sottostringa nota dalla fine di un'altra. Funziona esattamente come previsto.
Alex,

1

Puoi usare la divisione:

'abccomputer.com'.split('.com',1)[0]
# 'abccomputer'

5
Quando a = 'www.computerbugs.com'questo risulta con 'www'
yairchu

0

Questo è un uso perfetto per le espressioni regolari:

>>> import re
>>> re.match(r"(.*)\.com", "hello.com").group(1)
'hello'

5
Dovresti anche aggiungere un $ per assicurarti di abbinare i nomi host che terminano con ".com".
Cristian Ciupitu,

0

Python> = 3.9:

'abcdc.com'.removesuffix('.com')

Python <3.9:

def remove_suffix(text, suffix):
    if text.endswith(suffix):
        text = text[:-len(suffix)]
    return text

remove_suffix('abcdc.com', '.com')

1
La tua risposta per Python 3.9 è un duplicato di questa risposta sopra. Anche la tua risposta per le versioni precedenti ha ricevuto molte risposte in questo thread e non restituirebbe nulla se la stringa non avesse il suffisso.
Xavier Guihot
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.