Comment supprimer une sous-chaîne à la fin d'une chaîne en Python?

383

J'ai le code suivant:

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

J'esperais: abcdc

J'ai eu: abcd

Maintenant oui

url.rsplit('.com', 1)

Y a-t-il une meilleure façon?

Ramya
la source
6
strip supprime les caractères donnés aux deux extrémités de la chaîne, dans votre cas, il supprime ".", "c", "o" et "m".
truppo
6
Il supprimera également ces caractères à l'avant de la chaîne. Si vous voulez juste le supprimer de la fin, utilisez rstrip ()
Andre Miller
42
Ouais. str.strip ne fait pas ce que vous pensez qu'il fait. str.strip supprime l'un des caractères spécifiés depuis le début et la fin de la chaîne. Ainsi, "acbacda" .strip ("ad") donne 'cbac'; le a au début et le da à la fin ont été dépouillés. À votre santé.
scvalex
2
De plus, cela supprime les caractères dans n'importe quel ordre : "site.ocm"> "site".
Eric O Lebigot
1
@scvalex, wow vient de réaliser cela après l'avoir utilisé de cette façon depuis des lustres - c'est dangereux parce que le code fonctionne souvent de toute façon
Flash

Réponses:

557

stripne signifie pas "supprimer cette sous-chaîne". x.strip(y)traite ycomme un ensemble de caractères et supprime tous les caractères de cet ensemble depuis la fin de x.

Au lieu de cela, vous pouvez utiliser endswithet découper:

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

Ou en utilisant des expressions régulières :

import re
url = 'abcdc.com'
url = re.sub('\.com$', '', url)
Steef
la source
4
Oui, je pense moi-même que le premier exemple, avec le test endswith (), serait le meilleur; le regex impliquerait une certaine pénalité de performance (analyse du regex, etc.). Je n'irais pas avec le rsplit (), mais c'est parce que je ne sais pas ce que vous essayez exactement de réaliser. Je suppose que cela supprime le .com si et seulement s'il apparaît à la fin de l'url? La solution rsplit vous poserait des problèmes si vous l'utilisiez sur des noms de domaine comme 'www.commercialthingie.co.uk'
Steef
13
url = url[:-4] if any(url.endswith(x) for x in ('.com','.net')) else url
Burhan Khalid
1
que faire si j'écris des EXAMLPLE.COMnoms de domaine ne sont pas sensibles à la casse. (Ceci est un vote pour la solution regex)
Jasen
3
Ce n'est pas une réécriture, la rsplit()solution n'a pas le même comportement que endswith()celle lorsque la chaîne d'origine n'a pas la sous-chaîne à la fin, mais quelque part au milieu. Par exemple: "www.comeandsee.com".rsplit(".com",1)[0] == "www.comeandsee"mais"www.comeandsee.net".rsplit(".com",1)[0] == "www"
Steef
1
La syntaxe s[:-n]a une mise en garde: car n = 0, cela ne renvoie pas la chaîne avec le dernier zéro coupé, mais la chaîne vide à la place.
BlenderBender
90

Si vous êtes sûr que la chaîne n'apparaît qu'à la fin, alors le moyen le plus simple serait d'utiliser 'replace':

url = 'abcdc.com'
print(url.replace('.com',''))
Charles Collis
la source
56
qui remplacera également l'URL comme www.computerhope.com. vérifiez avec endswith()et ça devrait aller.
ghostdog74
72
"www.computerhope.com".endswith(".com")c'est vrai, ça va encore casser!
1
"Si vous êtes sûr que la chaîne n'apparaît qu'à la fin" voulez-vous dire "Si vous êtes sûr que la sous-chaîne n'apparaît qu'une seule fois"? remplacer semble fonctionner également lorsque la sous-chaîne est au milieu, mais comme l'autre commentaire le suggère, il remplacera toute occurrence de la sous-chaîne, pourquoi cela devrait être à la fin, je ne comprends pas
idclev 463035818
49
def strip_end(text, suffix):
    if not text.endswith(suffix):
        return text
    return text[:len(text)-len(suffix)]
yairchu
la source
4
Si vous savez que le suffixe n'est pas vide (comme quand c'est une constante) alors: retournez le texte [: - len (suffixe)]
MarcH
4
Merci. La dernière ligne pourrait être raccourcie:return text[:-len(suffix)]
Jabba
3
@Jabba: Malheureusement, cela ne fonctionnera pas pour les suffixes vides, comme l'a mentionné fuenfundachtzig.
yairchu
46

Puisqu'il semble que personne ne l'a encore souligné:

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

Cela devrait être plus efficace que les méthodes utilisant split()car aucun nouvel objet de liste n'est créé, et cette solution fonctionne pour les chaînes avec plusieurs points.

user3129181
la source
Wow, c'est un bon truc. Je n'arrivais pas à faire en sorte que cela échoue, mais j'ai également eu du mal à trouver des moyens pour que cela échoue. Je l'aime bien mais c'est très "magique", difficile de savoir ce que ça fait en le regardant. J'ai dû traiter mentalement chaque partie de la ligne pour "l'obtenir".
DevPlayer
14
Cela échoue si la chaîne recherchée n'est PAS présente et supprime à tort le dernier caractère à la place.
robbat2
25

Cela dépend de ce que vous savez sur votre URL et de ce que vous essayez de faire. Si vous savez qu'il se terminera toujours par «.com» (ou «.net» ou «.org»), alors

 url=url[:-4]

est la solution la plus rapide. S'il s'agit d'URL plus générales, vous feriez probablement mieux de consulter la bibliothèque urlparse fournie avec python.

Si vous, par contre, vous voulez simplement tout supprimer après la finale "." dans une chaîne puis

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

marchera. Ou si vous voulez juste tout vouloir jusqu'au premier '.' Alors essaye

url.split('.',1)[0]
dagw
la source
16

Si vous savez que c'est une extension, alors

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

Cela fonctionne aussi bien avec abcdc.comou www.abcdc.comou abcdc.[anything]et est plus extensible.

JohnMetta
la source
12

En une seule ligne:

text if not text.endswith(suffix) or len(suffix) == 0 else text[:-len(suffix)]
David Foster
la source
8

Et alors url[:-4]?

Daren Thomas
la source
Semble presque garanti de conduire à un bug une fois que vous êtes touché par un .caou une .co.ukURL.
Peter
7

Pour les URL (comme cela semble faire partie du sujet par l'exemple donné), on peut faire quelque chose comme ceci:

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)

Les deux produiront: ('http://www.stackoverflow', '.com')

Cela peut également être combiné avec str.endswith(suffix)si vous avez juste besoin de diviser ".com", ou quelque chose de spécifique.

JHolta
la source
5

url.rsplit ('. com', 1)

n'est pas tout à fait raison.

Ce que vous auriez réellement besoin d'écrire est

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

, et il semble IMHO assez succinct.

Cependant, ma préférence personnelle est cette option car elle n'utilise qu'un seul paramètre:

url.rpartition('.com')[0]
winni2k
la source
1
La partition +1 est préférée lorsqu'une seule division est nécessaire car elle renvoie toujours une réponse, une IndexError ne se produira pas.
Gringo Suave
4

À partir de Python 3.9, vous pouvez utiliser à la removesuffixplace:

'abcdc.com'.removesuffix('.com')
# 'abcdc'
Xavier Guihot
la source
2

Si vous devez supprimer une fin de chaîne si elle existe, ne faites rien. Mes meilleures solutions. Vous voudrez probablement utiliser l'une des 2 premières implémentations, mais j'ai inclus la 3e pour être complet.

Pour un suffixe constant:

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'

Pour une expression régulière:

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"

Pour une collection de suffixes constants, le moyen asymptotiquement le plus rapide pour un grand nombre d'appels:

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

le dernier est probablement beaucoup plus rapide en pypy qu'en cpython. La variante regex est probablement plus rapide que cela pour pratiquement tous les cas qui n'impliquent pas d'énormes dictionnaires de suffixes potentiels qui ne peuvent pas être facilement représentés comme une expression régulière au moins dans cPython.

Dans PyPy, la variante d'expression régulière est presque certainement plus lente pour un grand nombre d'appels ou de longues chaînes même si le module re utilise un moteur d'expression régulière de compilation DFA car la grande majorité des frais généraux des lambda sera optimisée par le JIT.

En cPython cependant, le fait que votre code c en cours d'exécution pour l'expression régulière compare presque certainement les avantages algorithmiques de la version de la collection de suffixes dans presque tous les cas.

user1424589
la source
2

Vous pouvez utiliser split:

'abccomputer.com'.split('.com',1)[0]
# 'abccomputer'
Lucas
la source
5
Lorsque a = 'www.computerbugs.com'cela résulte avec 'www'
yairchu
2

Si vous souhaitez supprimer uniquement l'extension:

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

Il fonctionne avec n'importe quelle extension, avec d'autres points potentiels existant également dans le nom de fichier. Il fractionne simplement la chaîne sous forme de liste sur des points et la joint sans le dernier élément.

Dcs
la source
2
import re

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

Je veux répéter cette réponse comme la manière la plus expressive de le faire. Bien sûr, ce qui suit prendrait moins de temps CPU:

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

Cependant, si le CPU est le goulot d'étranglement, pourquoi écrire en Python?

Quand est-ce que le CPU est un goulot d'étranglement? Dans les pilotes, peut-être.

Les avantages de l'utilisation d'une expression régulière sont la réutilisation du code. Que faire si vous souhaitez ensuite supprimer «.me», qui ne comporte que trois caractères?

Le même code ferait l'affaire:

>>> rm_sub('abcdc.me','.me')
'abcdc'
user1854182
la source
1

Dans mon cas, je devais lever une exception, alors j'ai fait:

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)]
juan Isaza
la source
1

Ici, j'ai un code le plus simple.

url=url.split(".")[0]
Anshuman Jayaprakash
la source
1

En supposant que vous souhaitiez supprimer le domaine, quel qu'il soit (.com, .net, etc.). Je recommande de trouver .et de supprimer tout à partir de ce moment.

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

Ici, j'utilise rfindpour résoudre le problème des URL comme celles abcdc.com.netqui devraient être réduites au nom abcdc.com.

Si vous êtes également préoccupé par les www.s, vous devez les vérifier explicitement:

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

Le 1 en remplacement est pour les cas étranges comme www.net.www.com

Si votre URL devient plus sauvage que cela, regardez les réponses regex avec lesquelles les gens ont répondu.

Xavier Guay
la source
1

J'ai utilisé la fonction rstrip intégrée pour le faire comme suit:

string = "test.com"
suffix = ".com"
newstring = string.rstrip(suffix)
print(newstring)
test
Alex
la source
Mauvaise idée. Essayez "test.ccom".
Shital Shah
Mais ce n'est pas le point de la question. Il a juste été demandé de supprimer une sous-chaîne connue de la fin d'une autre. Cela fonctionne exactement comme prévu.
Alex
0

C'est une utilisation parfaite pour les expressions régulières:

>>> import re
>>> re.match(r"(.*)\.com", "hello.com").group(1)
'hello'
Aaron Maenpaa
la source
5
Vous devez également ajouter un $ pour vous assurer que vous correspondez aux noms d'hôtes se terminant par ".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')
Infini
la source
2
Votre réponse pour Python 3.9 est un double de cette réponse ci-dessus. Votre réponse pour les versions précédentes a également été répondue plusieurs fois dans ce fil et ne retournerait rien si la chaîne n'a pas le suffixe.
Xavier Guihot