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?

Ramya
fonte
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)
Steef
fonte
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',''))
Charles Collis
fonte
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)]
yairchu
fonte
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.

user3129181
fonte
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]
dagw
fonte
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.

JohnMetta
fonte
12

Em uma linha:

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

Que tal url[:-4]?

Daren Thomas
fonte
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.

JHolta
fonte
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]
winni2k
fonte
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
3

Começando em Python 3.9, você pode usar removesuffix:

'abcdc.com'.removesuffix('.com')
# 'abcdc'
Xavier Guihot
fonte
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.

user1424589
fonte
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.

Dcs
fonte
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'
user1854182
fonte
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)]
Juan Isaza
fonte
1

Aqui, eu tenho um código mais simples.

url=url.split(".")[0]
Anshuman Jayaprakash
fonte
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.

Xavier Guay
fonte
1

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

string = "test.com"
suffix = ".com"
newstring = string.rstrip(suffix)
print(newstring)
test
Alex
fonte
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'
Lucas
fonte
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'
Aaron Maenpaa
fonte
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')
Infinidade
fonte
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