Como faço para remover uma substring do final de uma string no Python?


382

Eu tenho o seguinte código:

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

Eu esperava: abcdc

Eu tenho: abcd

Agora eu faço

url.rsplit('.com', 1)

Existe uma maneira melhor?


6
strip retira os caracteres dados das duas extremidades da string; no seu caso, retira ".", "c", "o" e "m".
truppo

6
Ele também removerá esses caracteres da frente da string. Se você quiser apenas para remover a partir do final, RSTRIP uso ()
Andre Miller

42
Sim. str.strip não faz o que você pensa que faz. str.strip remove qualquer um dos caracteres especificados desde o início e o final da string. Então, "acbacda" .strip ("ad") fornece 'cbac'; o a no início e o da no final foram retirados. Felicidades.
scvalex

2
Além disso, isso remove os caracteres em qualquer ordem : "site.ocm"> "site".
Eric O Lebigot

11
@scvalex, wow só percebi isso ter usado dessa maneira para as idades - é perigoso porque o código muitas vezes acontece de trabalho de qualquer maneira
o Flash

Respostas:


556

stripnão significa "remover esta substring". x.strip(y)trata ycomo um conjunto de caracteres e retira todos os caracteres desse conjunto dos fins de x.

Em vez disso, você pode usar endswithe fatiar:

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

Ou usando expressões regulares :

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

4
Sim, acho que o primeiro exemplo, com o teste endswith (), seria o melhor; a regex envolveria alguma penalidade de desempenho (analisando a regex etc.). Eu não aceitaria o rsplit (), mas é porque não sei o que você está exatamente tentando alcançar. Eu acho que está removendo o .com se e somente se ele aparece no final do URL? A solução rsplit iria dar-lhe problemas se você usá-lo em nomes de domínio como 'www.commercialthingie.co.uk'
Steef

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

11
e se eu escrever EXAMLPLE.COMnomes de domínio não diferenciam maiúsculas de minúsculas. (Este é um voto para a solução regex)
Jasen

3
Não é uma reescrita, a rsplit()solução não tem o mesmo comportamento que a endswith()string original não possui a substring no final, mas em algum lugar no meio. Por exemplo: "www.comeandsee.com".rsplit(".com",1)[0] == "www.comeandsee"mas"www.comeandsee.net".rsplit(".com",1)[0] == "www"
Steef

11
A sintaxe s[:-n]tem uma ressalva: pois n = 0, isso não retorna a string com os últimos zero caracteres cortados, mas a string vazia.
BlenderBender

90

Se você tem certeza de que a string aparece apenas no final, a maneira mais simples seria usar 'replace':

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

56
que também substituirá o URL como www.computerhope.com. faça uma verificação com endswith()e deve ficar bem.
ghostdog74

72
"www.computerhope.com".endswith(".com")é verdade, ainda vai quebrar!

11
"Se você tem certeza de que a string aparece apenas no final", você quer dizer "Se você tem certeza de que a substring aparece apenas uma vez"? substituir parece funcionar também quando o substring está no meio, mas como o outro comentário sugere que irá substituir qualquer ocorrência do substring, por que deveria ser no final Eu não entendo
idclev 463035818

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

4
Se você sabe que sufixo não está vazia (como quando é uma constante), então: texto retorno [: - len (sufixo)]
Março

4
Obrigado. A última linha pode ser abreviada:return text[:-len(suffix)]
Jabba

3
@Jabba: Infelizmente, isso não funciona para sufixos vazios, como o fuenfundachtzig mencionou.
Yairchu

46

Como parece que ninguém apontou isso ainda:

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

Isso deve ser mais eficiente do que os métodos utilizados, split()pois nenhum novo objeto de lista é criado e esta solução funciona para cadeias de caracteres com vários pontos.


Uau, isso é um bom truque. Não consegui fazer com que isso falhasse, mas também tive dificuldade em pensar em como isso poderia falhar. Eu gosto, mas é muito "mágico", difícil de saber o que isso faz apenas olhando para ele. Eu tive que processar mentalmente cada parte da linha para "entender".
DevPlayer

14
Isso falhará se a seqüência de caracteres pesquisada NÃO estiver presente e, erroneamente, o último caractere será removido.
precisa saber é o seguinte

25

Depende do que você sabe sobre o seu URL e exatamente o que você está tentando fazer. Se você souber que sempre terminará em '.com' (ou '.net' ou '.org'),

 url=url[:-4]

é a solução mais rápida. Se for um URL mais geral, é melhor procurar na biblioteca urlparse que acompanha o python.

Se você, por outro lado, simplesmente deseja remover tudo após o final '.' em uma corda então

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

vai funcionar. Ou se você quiser apenas quer tudo até o primeiro '.' Então tente

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

16

Se você sabe que é uma extensão, então

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

Isso funciona igualmente bem com abcdc.comou www.abcdc.comou abcdc.[anything]e é mais extensível.


12

Em uma linha:

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

8

Que tal url[:-4]?


Parece quase garantido levar a um bug quando você é atingido por um .caou um .co.ukURL.
Peter

7

Para urls (como parece fazer parte do tópico pelo exemplo dado), pode-se fazer algo assim:

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)

Ambos produzirão: ('http://www.stackoverflow', '.com')

Isso também pode ser combinado str.endswith(suffix)se você precisar apenas dividir ".com" ou qualquer coisa específica.


5

url.rsplit ('. com', 1)

não está certo.

O que você realmente precisa escrever é

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

, e parece IMHO bastante sucinto.

No entanto, minha preferência pessoal é essa opção porque ela usa apenas um parâmetro:

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

11
A partição +1 é preferida quando apenas uma divisão é necessária, pois sempre retorna uma resposta, um IndexError não ocorrerá.
Gringo Suave


2

Se você precisar remover algum final de uma string, caso exista, não faça nada. Minhas melhores soluções. Você provavelmente desejará usar uma das 2 primeiras implementações, no entanto, incluímos a 3ª por integridade.

Para um sufixo constante:

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'

Para uma 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"

Para uma coleção de sufixos constantes, o caminho assintoticamente mais rápido para um grande número de chamadas:

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

o final provavelmente é significativamente mais rápido no pypy do que no cpython. A variante regex provavelmente é mais rápida que isso para praticamente todos os casos que não envolvam dicionários enormes de sufixos em potencial que não podem ser facilmente representados como regex pelo menos no cPython.

No PyPy, a variante regex é quase certamente mais lenta para um grande número de chamadas ou seqüências longas, mesmo que o módulo re use um mecanismo regex de compilação do DFA, pois a grande maioria da sobrecarga do lambda será otimizada pelo JIT.

No cPython, no entanto, o fato de o código c em execução para o regex comparar quase certamente as vantagens algorítmicas da versão da coleção de sufixos em quase todos os casos.


2

Se você deseja apenas remover a extensão:

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

Ele funciona com qualquer extensão, com outros pontos potenciais existentes no nome do arquivo também. Simplesmente divide a string como uma lista de pontos e junta-a sem o último elemento.


2
import re

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

Quero repetir esta resposta como a maneira mais expressiva de fazê-lo. Obviamente, o seguinte levaria menos tempo de CPU:

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

No entanto, se a CPU é o gargalo, por que escrever em Python?

Quando a CPU é um gargalo, afinal? Nos motoristas, talvez.

As vantagens do uso de expressão regular são a reutilização do código. E se você quiser remover o '.me', que possui apenas três caracteres?

O mesmo código faria o truque:

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

1

No meu caso, eu precisava criar uma exceção, então fiz:

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

Supondo que você deseja remover o domínio, não importa o que seja (.com, .net, etc). Eu recomendo encontrar .e remover tudo a partir desse ponto.

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

Aqui estou usando rfindpara resolver o problema de URLs como o abcdc.com.netque deve ser reduzido ao nome abcdc.com.

Se você também estiver preocupado com www.s, verifique-os explicitamente:

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

O 1 em substituir é para edgecases estranhos como www.net.www.com

Se o seu URL ficar mais selvagem do que o visual, as respostas com regex com as quais as pessoas responderam.


1

Eu usei a função rstrip embutida para fazer o seguinte:

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

Péssima ideia. Tente "test.ccom".
Shital Shah

Mas este não é o ponto da questão. Foi solicitado apenas a remoção de uma substring conhecida do final de outra. Isso funciona exatamente como o esperado.
Alex

1

Você pode usar split:

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

5
Quando a = 'www.computerbugs.com'isso resulta com 'www'
yairchu

0

Este é um uso perfeito para expressões regulares:

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

5
Você também deve adicionar um $ para garantir que você esteja correspondendo aos nomes de host que terminam em ".com".
Cristian Ciupitu 24/06/2009

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

11
Sua resposta para o Python 3.9 é uma duplicata desta resposta acima. Sua resposta para versões anteriores também foi respondida várias vezes neste segmento e não retornaria nada se a sequência não tivesse o sufixo.
Xavier Guihot
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.