¿Cómo elimino una subcadena del final de una cadena en Python?

383

Tengo el siguiente código:

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

Esperaba: abcdc

Tengo: abcd

Ahora lo hago

url.rsplit('.com', 1)

¿Hay una mejor manera?

Ramya
fuente
66
strip quita los caracteres dados de ambos extremos de la cadena, en su caso quita ".", "c", "o" y "m".
truppo
66
También eliminará esos caracteres del frente de la cadena. Si solo quiere que se elimine del final, use rstrip ()
Andre Miller
42
Si. str.strip no hace lo que crees que hace. str.strip elimina cualquiera de los caracteres especificados desde el principio y el final de la cadena. Entonces, "acbacda" .strip ("ad") da 'cbac'; la a al principio y la da al final fueron despojadas. Salud.
scvalex
2
Además, esto elimina los caracteres en cualquier orden : "site.ocm"> "site".
Eric O Lebigot
1
@scvalex, wow, me acabo de dar cuenta de que lo usé de esa manera durante años: es peligroso porque el código a menudo funciona de todos modos
Flash

Respuestas:

556

stripno significa "eliminar esta subcadena". x.strip(y)trata ycomo un conjunto de caracteres y elimina todos los caracteres de ese conjunto desde los extremos de x.

En su lugar, podría usar endswithy cortar:

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

O usando expresiones regulares :

import re
url = 'abcdc.com'
url = re.sub('\.com$', '', url)
Steef
fuente
44
Sí, creo que el primer ejemplo, con la prueba endswith (), sería el mejor; el regex implicaría alguna penalización de rendimiento (análisis del regex, etc.). No iría con el rsplit (), pero eso es porque no sé lo que estás tratando de lograr exactamente. Me imagino que está eliminando el .com si y solo si aparece al final de la url. La solución rsplit le daría problemas si la usara en nombres de dominio como 'www.commercialthingie.co.uk'
Steef
13
url = url[:-4] if any(url.endswith(x) for x in ('.com','.net')) else url
Burhan Khalid,
1
¿Qué pasa si escribo EXAMLPLE.COMnombres de dominio que no distinguen entre mayúsculas y minúsculas? (Este es un voto para la solución regex)
Jasen
3
No es una reescritura, la rsplit()solución no tiene el mismo comportamiento que endswith()cuando la cadena original no tiene la subcadena al final, sino en algún lugar en el medio. Por ejemplo: "www.comeandsee.com".rsplit(".com",1)[0] == "www.comeandsee"pero"www.comeandsee.net".rsplit(".com",1)[0] == "www"
Steef
1
La sintaxis s[:-n]tiene una advertencia: porque n = 0no devuelve la cadena con los últimos cero caracteres cortados, sino la cadena vacía.
BlenderBender
90

Si está seguro de que la cadena solo aparece al final, entonces la forma más simple sería usar 'reemplazar':

url = 'abcdc.com'
print(url.replace('.com',''))
Charles Collis
fuente
56
eso también reemplazará url like www.computerhope.com. hacer un chequeo con endswith()y debería estar bien.
ghostdog74
72
"www.computerhope.com".endswith(".com")es cierto, todavía se romperá!
1
"Si está seguro de que la cadena solo aparece al final", ¿quiere decir "Si está seguro de que la subcadena aparece solo una vez"? reemplazar parece funcionar también cuando la subcadena se encuentra en el centro, pero como el otro comentario sugiere que reemplazará cualquier ocurrencia de la subcadena, por lo que debe estar al final yo no entiendo
IDCLEV 463 035 818
49
def strip_end(text, suffix):
    if not text.endswith(suffix):
        return text
    return text[:len(text)-len(suffix)]
yairchu
fuente
44
Si sabe que el sufijo no está vacío (como cuando es una constante), entonces: devuelva el texto [: - len (sufijo)]
MarcH
44
Gracias. La última línea podría acortarse:return text[:-len(suffix)]
Jabba
3
@Jabba: Lamentablemente, eso no funcionará para sufijos vacíos, como mencionó fuenfundachtzig.
yairchu
46

Como parece que nadie ha señalado esto todavía:

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

Esto debería ser más eficiente que los métodos que se utilizan, split()ya que no se crea un nuevo objeto de lista, y esta solución funciona para cadenas con varios puntos.

usuario3129181
fuente
Wow, ese es un buen truco. No pude lograr que esto fallara, pero también tuve dificultades para pensar en formas en que esto podría fallar. Me gusta, pero es muy "mágico", es difícil saber qué hace con solo mirarlo. Tuve que procesar mentalmente cada parte de la línea para "entenderlo".
DevPlayer
14
Esto falla si la cadena buscada NO está presente, y elimina erróneamente el último carácter.
robbat2
25

Depende de lo que sepa sobre su URL y de lo que está tratando de hacer exactamente. Si sabe que siempre terminará en '.com' (o '.net' o '.org'), entonces

 url=url[:-4]

Es la solución más rápida. Si se trata de una URL más general, entonces probablemente sea mejor que busques en la biblioteca urlparse que viene con python.

Si, por otro lado, simplemente desea eliminar todo después del '' final. en una cuerda entonces

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

trabajará. O si quieres solo quieres todo hasta el primer '.' entonces intenta

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

Si sabes que es una extensión, entonces

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

Esto funciona igualmente bien con abcdc.como www.abcdc.como abcdc.[anything]y es más extensible.

JohnMetta
fuente
12

En una linea:

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

¿Qué tal url[:-4]?

Daren Thomas
fuente
Parece casi seguro que conducirá a un error una vez que sea golpeado con una .cao .co.ukurl.
Peter
7

Para las URL (como parece ser parte del tema en el ejemplo dado), se puede hacer algo como esto:

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 generarán: ('http://www.stackoverflow', '.com')

Esto también se puede combinar str.endswith(suffix)si solo necesita dividir ".com", o algo específico.

JHolta
fuente
5

url.rsplit ('. com', 1)

No está del todo bien.

Lo que realmente necesitarías escribir es

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

, y se ve bastante sucinto en mi humilde opinión.

Sin embargo, mi preferencia personal es esta opción porque usa solo un parámetro:

url.rpartition('.com')[0]
winni2k
fuente
1
Se prefiere la partición +1 cuando solo se necesita una división, ya que siempre devuelve una respuesta, no se producirá un IndexError.
Gringo Suave
4

Comenzando Python 3.9, puede usar removesuffixen su lugar:

'abcdc.com'.removesuffix('.com')
# 'abcdc'
Xavier Guihot
fuente
2

Si necesita quitar algún extremo de una cadena si existe, de lo contrario no haga nada. Mis mejores soluciones Probablemente querrá usar una de las primeras 2 implementaciones, sin embargo, he incluido la tercera para completar.

Para un sufijo 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 una expresión regular:

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 una colección de sufijos constantes, la forma asintóticamente más rápida para una gran cantidad de llamadas:

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

el último es probablemente significativamente más rápido en pypy que en cpython. Es probable que la variante de expresiones regulares sea más rápida que esta para prácticamente todos los casos que no impliquen grandes diccionarios de posibles sufijos que no pueden representarse fácilmente como expresiones regulares, al menos en cPython.

En PyPy, la variante regex es casi con certeza más lenta para un gran número de llamadas o cadenas largas, incluso si el módulo re utiliza un motor regex de compilación DFA ya que la gran mayoría de los gastos generales de los lambda serán optimizados por el JIT.

En cPython, sin embargo, el hecho de que su código c en ejecución para la expresión regular compare casi seguramente las ventajas algorítmicas de la versión de colección de sufijos en casi todos los casos.

usuario1424589
fuente
2

Puedes usar split:

'abccomputer.com'.split('.com',1)[0]
# 'abccomputer'
Lucas
fuente
55
Cuando a = 'www.computerbugs.com'esto resulta con 'www'
yairchu
2

Si solo quiere quitar la extensión:

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

Funciona con cualquier extensión, con otros posibles puntos existentes en el nombre del archivo también. Simplemente divide la cadena como una lista en puntos y la une sin el último elemento.

Dcs
fuente
2
import re

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

Quiero repetir esta respuesta como la forma más expresiva de hacerlo. Por supuesto, lo siguiente tomaría menos tiempo de CPU:

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

Sin embargo, si la CPU es el cuello de botella, ¿por qué escribir en Python?

¿Cuándo es la CPU un cuello de botella de todos modos? En los conductores, tal vez.

Las ventajas de usar la expresión regular es la reutilización del código. ¿Qué pasa si luego quieres eliminar '.me', que solo tiene tres caracteres?

El mismo código haría el truco:

>>> rm_sub('abcdc.me','.me')
'abcdc'
usuario1854182
fuente
1

En mi caso, necesitaba plantear una excepción, así que hice:

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
fuente
1

Aquí, tengo un código más simple.

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

Suponiendo que desea eliminar el dominio, sin importar cuál sea (.com, .net, etc.). Recomiendo encontrar .y eliminar todo a partir de ese momento.

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

Aquí estoy usando rfindpara resolver el problema de las URL como las abcdc.com.netque deberían reducirse al nombre abcdc.com.

Si también le preocupan los www.s, debe verificarlos explícitamente:

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

El 1 en reemplazo es para bordes extraños como www.net.www.com

Si su URL se vuelve más salvaje que eso, mire las respuestas de expresiones regulares con las que la gente ha respondido.

Xavier Guay
fuente
1

Utilicé la función rstrip incorporada para hacerlo como sigue:

string = "test.com"
suffix = ".com"
newstring = string.rstrip(suffix)
print(newstring)
test
Alex
fuente
Mala idea. Tratar "test.ccom".
Shital Shah
Pero este no es el punto de la pregunta. Simplemente se le pidió que eliminara una subcadena conocida del final de otra. Esto funciona exactamente como se esperaba.
Alex
0

Este es un uso perfecto para expresiones regulares:

>>> import re
>>> re.match(r"(.*)\.com", "hello.com").group(1)
'hello'
Aaron Maenpaa
fuente
55
También debe agregar un $ para asegurarse de que coincida con los nombres de host que terminan en ".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')
infinito
fuente
2
Su respuesta para Python 3.9 es un duplicado de esta respuesta anterior. Su respuesta para versiones anteriores también ha sido respondida muchas veces en este hilo y no devolvería nada si la cadena no tiene el sufijo.
Xavier Guihot