¿Cómo quitar la parte izquierda de una cadena?


144

Tengo un código python simple que busca archivos en una cadena path=c:\path, por ejemplo , donde la c:\pathparte puede variar. El código actual es:

def find_path(i_file):
    lines = open(i_file).readlines()
    for line in lines:
        if line.startswith("Path="):
            return # what to do here in order to get line content after "Path=" ?

¿Cuál es una manera simple de obtener el texto después Path=?


Tenga en cuenta que está regresando en la aparición de la primera línea dentro del archivo que comienza con "Ruta =". Otras respuestas a esta publicación también lo hacen. Pero si el archivo es algo así como un archivo por lotes de DOS, es posible que desee la última aparición de línea de dicho archivo dependiendo de si el "lote" o el archivo de comando no está lleno de condicionales.
DevPlayer el

Respuestas:



196

Si la cadena es fija, simplemente puede usar:

if line.startswith("Path="):
    return line[5:]

que le da todo desde la posición 5 en adelante en la cadena (una cadena también es una secuencia, por lo que estos operadores de secuencia también funcionan aquí).

O puede dividir la línea al principio =:

if "=" in line:
    param, value = line.split("=",1)

Entonces param es "Path" y el valor es el resto después de first =.


3
+1 para el método de división, evita la leve fealdad del corte manual en len (prefijo).
bobince 01 de

1
Pero también arroja si su entrada no está en la forma "algo = algo así".
Dan Olson

1
Es por eso que pongo la condición al frente para que solo se use si hay un "=" en la cadena. De lo contrario, también puede probar la longitud del resultado de split () y si es == 2.
MrTopf

77
Como Dan Olson dice que splitarroja una excepción si el delimitador no está presente. partitiones más estable, también divide una cadena y siempre devuelve una tupla de tres elementos con pre, delimitador y contenido posterior (algunos de los cuales pueden ser ''si el delimitador no estaba presente). Ej value = line.partition('=').
Anders Johansson

1
Split no genera una excepción si el delimitado no está presente, devuelve una lista con toda la cadena. Al menos bajo python 2.7
Maxim

122

Eliminar el prefijo de una cadena

# ...
if line.startswith(prefix):
   return line[len(prefix):]

Split en la primera aparición del separador a través de str.partition()

def findvar(filename, varname="Path", sep="=") :
    for line in open(filename):
        if line.startswith(varname + sep):
           head, sep_, tail = line.partition(sep) # instead of `str.split()`
           assert head == varname
           assert sep_ == sep
           return tail

Analizar archivos tipo INI con ConfigParser

from ConfigParser import SafeConfigParser
config = SafeConfigParser()
config.read(filename) # requires section headers to be present

path = config.get(section, 'path', raw=1) # case-insensitive, no interpolation

Otras opciones


1
Una rara razón para sangrar tres espacios en lugar de cuatro.
Bob Stein

25
def remove_prefix(text, prefix):
    return text[len(prefix):] if text.startswith(prefix) else text

1
Me gusta este porque puedes reemplazar "else text" con "else False" o "else None" o lo que sea -tipo- que quieras devolver para indicar que la línea en el archivo no comenzó con "Path =". Personalmente, me gusta rodear a mis operadores ternarios con paréntesis para destacar visualmente.
DevPlayer

19

Para cortar (condicional o no condicional) en general, prefiero lo que sugirió recientemente un colega; Use reemplazo con una cadena vacía. Es más fácil leer el código, menos código (a veces) y menos riesgo de especificar el número incorrecto de caracteres. Okay; No uso Python, pero en otros idiomas prefiero este enfoque:

rightmost = full_path.replace('Path=', '', 1)

o - para seguir el primer comentario de esta publicación - si esto solo se debe hacer si la línea comienza con Path:

rightmost = re.compile('^Path=').sub('', full_path)

La principal diferencia con algo de lo que se ha sugerido anteriormente es que no hay un "número mágico" (5) involucrado, ni ninguna necesidad de especificar tanto ' 5' como la cadena ' Path='. En otras palabras, prefiero este enfoque desde un mantenimiento de código punto de vista.


No funciona: 'c = Path = a'.replace ("Path =", "", 1) ->' c = a '.
jfs 01 de

3
Eso no cumple con el requisito original de la cadena que comienza con "Ruta =".
Cachorro

1
Puede reemplazar el código regex con solo rightmost = re.sub('^Path=', '', fullPath). El propósito del compile()método es hacer las cosas más rápido si reutiliza el objeto compilado, pero dado que lo tira después de usarlo, no tiene ningún efecto aquí de todos modos. Por lo general, no vale la pena preocuparse por esta optimización de todos modos.
Jim Oldfield

13

Prefiero popindexar [-1]:

value = line.split("Path=", 1).pop()

a

value = line.split("Path=", 1)[1]
param, value = line.split("Path=", 1)

2
Buena alternativa sin "números mágicos". Vale la pena señalar que esto funciona porque startswithya se ha probado, por splitlo que dividirá "nada" antes y todo lo demás después. split("Path=", 1)es más preciso (en caso de que el prefijo vuelva a aparecer más adelante en la cadena) pero reintroduce un número mágico.
2013

1
Versión más corta del comentario anterior (muy importante): esto funciona SOLO si primero prueba con beginwith ().
MarcH

12

O porque no

if line.startswith(prefix):
    return line.replace(prefix, '', 1)

5

Qué tal si..

>>> line = r'path=c:\path'
>>> line.partition('path=')
('', 'path=', 'c:\\path')

Este triplete es la cabeza, el separador y la cola .


Esto no funciona en todos los casos de la misma manera. Si el separador está presente, el resultado es el tercer elemento. De lo contrario, el resultado es el primer elemento.
Ioannis Filippidis

5

La forma más simple en que puedo pensar es en cortar:

def find_path(i_file): 
    lines = open(i_file).readlines() 
    for line in lines: 
        if line.startswith("Path=") : 
            return line[5:]

Una nota rápida sobre la notación de corte, utiliza dos índices en lugar del habitual. El primer índice indica el primer elemento de la secuencia que desea incluir en el segmento y el último índice es el índice inmediatamente posterior al último elemento que desea incluir en el segmento.
P.ej:

sequence_obj[first_index:last_index]

El segmento consta de todos los elementos entre first_indexy last_index, incluidos first_indexy no last_index. Si se omite el primer índice, el valor predeterminado es el inicio de la secuencia. Si se omite el último índice, incluye todos los elementos hasta el último elemento de la secuencia. Los índices negativos también están permitidos. Use Google para aprender más sobre el tema.


4
>>> import re

>>> p = re.compile(r'path=(.*)', re.IGNORECASE)

>>> path = "path=c:\path"

>>> re.match(p, path).group(1)
'c:\\path'

1. Use r''cadenas para las rutas de Windows. 2. re.match()puede devolver None
jfs el

3

Otra línea simple que no se ha mencionado aquí:

value = line.split("Path=", 1)[-1]

Esto también funcionará correctamente para varios casos extremos:

>>> print("prefixfoobar".split("foo", 1)[-1])
"bar"

>>> print("foofoobar".split("foo", 1)[-1])
"foobar"

>>> print("foobar".split("foo", 1)[-1])
"bar"

>>> print("bar".split("foo", 1)[-1])
"bar"

>>> print("".split("foo", 1)[-1])
""



1

Si conoce la lista de comprensiones:

lines = [line[5:] for line in file.readlines() if line[:5] == "Path="]

Hubo una edición que sugiere que line.startswith(...)es 10 veces más rápido. Mi prueba no confirmó esto. Feliz de cambiarlo si se proporciona evidencia que respalde esa afirmación.
Matthew Schinckel

0

La versión pop no estaba del todo bien. Creo que quieres:

>>> print('foofoobar'.split('foo', 1).pop())
foobar

0

¿Por qué no usar regex con escape? ^coincide con la parte inicial de una línea y re.MULTILINEcoincide con cada línea. re.escapeasegura que la coincidencia sea exacta.

>>> print(re.sub('^' + re.escape('path='), repl='', string='path=c:\path\nd:\path2', flags=re.MULTILINE))
c:\path
d:\path2

0

Intenta seguir el código

if line.startswith("Path="): return line[5:]

1
¿Cuál es la diferencia entre su respuesta y la respuesta aceptada? Veo que está en la primera parte de la otra respuesta.
eyllanesc

-1

Supongo que esto es lo que estás buscando exactamente

    def findPath(i_file) :
        lines = open( i_file ).readlines()
        for line in lines :
            if line.startswith( "Path=" ):
                output_line=line[(line.find("Path=")+len("Path=")):]
                return output_line

-1

sin tener que escribir una función, esto se dividirá de acuerdo a la lista, en este caso 'Mr. | Dr. | Mrs.', seleccione todo después de dividir con [1], luego divida nuevamente y tome cualquier elemento. En el caso a continuación, se devuelve 'Morris'.

re.split('Mr.|Dr.|Mrs.', 'Mr. Morgan Morris')[1].split()[1]

-1

Esto es muy similar en técnica a otras respuestas, pero sin operaciones de cadena repetidas, capacidad para saber si el prefijo estaba allí o no, y aún es bastante legible:

parts = the_string.split(prefix_to_remove, 1):
    if len(parts) == 2:
        #  do things with parts[1]
        pass
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.