Come rimuovere la parte sinistra di una stringa?


144

Ho un semplice codice Python che cerca i file per una stringa path=c:\path, ad esempio , dove la c:\pathparte può variare. Il codice attuale è:

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=" ?

Qual è un modo semplice per ottenere il testo dopo Path=?


Tieni presente che stai tornando alla prima occorrenza della riga all'interno del file che inizia con "Path =". Altre risposte a questo post lo fanno anche. Ma se il file è qualcosa di simile a un file batch DOS, in realtà potresti volere l'ultima occorrenza di riga da tale file a seconda che il "batch" o il file di comando non sia pieno di condizionali.
DevPlayer,

Risposte:



196

Se la stringa è fissa puoi semplicemente usare:

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

che ti dà tutto dalla posizione 5 in poi nella stringa (una stringa è anche una sequenza, quindi anche questi operatori di sequenza funzionano qui).

Oppure puoi dividere la linea all'inizio =:

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

Quindi param è "Path" e value è il resto dopo il primo =.


3
+1 per il metodo split, evita la leggera bruttezza del taglio manuale su len (prefisso).
Bobince,

1
Ma genera anche se il tuo input non è tutto nella forma "qualcosa = qualcosa".
Dan Olson,

1
Ecco perché metto la condizione in primo piano, quindi viene utilizzata solo se nella stringa è presente un "=". Altrimenti puoi anche testare la lunghezza del risultato di split () e se è == 2.
MrTopf

7
Come dice Dan Olson, splitgenera un'eccezione se il delimitatore non è presente. partitionè più stabile, divide anche una stringa e restituisce sempre una tupla a tre elementi con pre, delimitatore e post-contenuto (alcuni dei quali potrebbero essere ''se il delimitatore non era presente). Ad es value = line.partition('=').
Anders Johansson,

1
La divisione non genera un'eccezione se il delimitato non è presente, restituisce un elenco con l'intera stringa. Almeno con Python 2.7
Massimo

122

Rimuovi il prefisso da una stringa

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

Dividi alla prima occorrenza del separatore tramite 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

Analizza file simile a 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

Altre opzioni


1
Un motivo raro per indentare tre spazi anziché quattro.
Bob Stein,

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

1
Mi piace questo perché puoi sostituire "altro testo" con "altro Falso" o "altro Nessuno" o qualsiasi altro tipo che desideri restituire per indicare che la riga nel file non è iniziata con "Percorso =". Personalmente mi piace circondare i miei operatori ternari con parentesi per distinguermi visivamente.
DevPlayer,

19

Per il taglio (condizionale o non condizionale) in generale preferisco ciò che un collega ha suggerito di recente; Usa la sostituzione con una stringa vuota. Più facile da leggere il codice, meno codice (a volte) e meno rischi di specificare il numero errato di caratteri. Ok; Non uso Python, ma in altre lingue preferisco questo approccio:

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

oppure - per dare seguito al primo commento a questo post - se questo dovrebbe essere fatto solo se la riga inizia con Path:

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

La principale differenza rispetto ad alcuni di quelli che è stato suggerito sopra è che non vi è alcun "numero magico" (5) coinvolto, né alcuna necessità di specificare sia ' 5' che la stringa ' Path=', in altre parole preferisco questo approccio dal mantenimento del codice punto di vista.


Non funziona: 'c = Path = a'.replace ("Path =", "", 1) ->' c = a '.
jfs

3
Ciò non soddisfa il requisito originale della stringa che inizia con "Path =".
Cucciolo

1
Puoi sostituire il codice regex con just rightmost = re.sub('^Path=', '', fullPath). Lo scopo del compile()metodo è rendere le cose più veloci se riutilizzi l'oggetto compilato, ma poiché lo butti via dopo averlo usato, non ha comunque alcun effetto qui. Di solito non vale la pena preoccuparsi di questa ottimizzazione comunque.
Jim Oldfield,

13

Preferisco popindicizzare [-1]:

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

per

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

2
Bella alternativa senza "numeri magici". Vale la pena notare che questo funziona perché startswithè già stato testato, quindi splitdividerà "niente" prima e tutto il resto dopo. split("Path=", 1)è più preciso (nel caso in cui il prefisso riappaia più avanti nella stringa) ma reintroduce un numero magico.
Quornian,

1
Versione più breve del (molto importante) commento precedente: funziona SOLO se si prova prima con startwith ().
Marc

12

O perché no

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

5

Che ne dite di..

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

Questa tripletta è la testa, il separatore e la coda .


Questo non funziona in tutti i casi allo stesso modo. Se il separatore è presente, il risultato è il terzo elemento. Altrimenti, il risultato è il primo elemento.
Ioannis Filippidis,

5

Il modo più semplice a cui riesco a pensare è affettare:

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

Una breve nota sulla notazione delle sezioni, utilizza due indici anziché il solito. Il primo indice indica il primo elemento della sequenza che si desidera includere nella sezione e l'ultimo indice è l'indice immediatamente dopo l'ultimo elemento che si desidera includere nella sezione.
Per esempio:

sequence_obj[first_index:last_index]

La sezione è composta da tutti gli elementi tra first_indexe last_index, incluso first_indexe non last_index. Se il primo indice viene omesso, viene impostato automaticamente l'inizio della sequenza. Se l'ultimo indice viene omesso, include tutti gli elementi fino all'ultimo elemento della sequenza. Sono ammessi anche indici negativi. Usa Google per saperne di più sull'argomento.


4
>>> import re

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

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

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

1. Utilizzare le r''stringhe per i percorsi di Windows. 2. re.match()può restituire None
jfs

3

Un altro semplice one-liner che non è stato menzionato qui:

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

Questo funzionerà anche correttamente per vari casi limite:

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

Se conosci la comprensione dell'elenco:

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

C'è stata una modifica che suggerisce line.startswith(...)è 10 volte più veloce. I miei test non hanno confermato questo. Felice di cambiarlo se vengono fornite prove a sostegno di tale affermazione.
Matthew Schinckel,

0

La versione pop non era del tutto giusta. Penso che tu voglia:

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

0

Perché non usare regex con escape? ^corrisponde alla parte iniziale di una riga e re.MULTILINEcorrisponde a ciascuna riga. re.escapeassicura che la corrispondenza sia esatta.

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

0

Prova a seguire il codice

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

1
Qual è la differenza tra la tua risposta e la risposta accettata? Vedo che è nella prima parte dell'altra risposta.
Eyllanesc,

-1

Immagino che questo sia esattamente quello che stai cercando

    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

senza dover scrivere una funzione, questa si dividerà in base all'elenco, in questo caso 'Mr. | Dr. | Mrs.', seleziona tutto dopo la divisione con [1], quindi dividi di nuovo e prendi qualunque elemento. Nel caso seguente, viene restituito "Morris".

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

-1

Questo è molto simile nella tecnica ad altre risposte, ma senza ripetute operazioni sulle stringhe, capacità di dire se il prefisso era presente o meno, e ancora abbastanza leggibile:

parts = the_string.split(prefix_to_remove, 1):
    if len(parts) == 2:
        #  do things with parts[1]
        pass
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.