Wie entferne ich den linken Teil einer Zeichenfolge?

144

Ich habe einen einfachen Python-Code, der Dateien nach einer Zeichenfolge durchsucht, z. B. path=c:\pathwo der c:\pathTeil variieren kann. Der aktuelle Code lautet:

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

Was ist ein einfacher Weg, um den Text danach zu bekommen Path=?

grigoryvp
quelle
Beachten Sie, dass Sie in der ersten Zeile der Datei, die mit "Path =" beginnt, zurückkehren. Andere Antworten auf diesen Beitrag auch. Wenn es sich bei der Datei jedoch um eine DOS-Batchdatei handelt, möchten Sie möglicherweise tatsächlich das Auftreten der letzten Zeile aus einer solchen Datei, je nachdem, ob die "Batch" - oder Befehlsdatei nicht mit Bedingungen gefüllt ist.
DevPlayer

Antworten:

21

Ab Python 3.9können Sie verwenden removeprefix:

'Path=helloworld'.removeprefix('Path=')
# 'helloworld'
Xavier Guihot
quelle
4
viel Zeitreisen? ;-) von PEP 596 - Python 3.9 Release-Zeitplan : 3.9.0 final: Montag, 2020-10-05
ssc
Ich wollte die Lösung für Python 3.9 schreiben, aber anscheinend haben Sie Python 3.9-Lösungen überall erwähnt. :)
Pygirl
196

Wenn die Zeichenfolge festgelegt ist, können Sie einfach Folgendes verwenden:

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

Dies gibt Ihnen alles ab Position 5 in der Zeichenfolge (eine Zeichenfolge ist auch eine Sequenz, sodass diese Sequenzoperatoren auch hier funktionieren).

Oder Sie können die Linie zuerst teilen =:

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

Dann ist param "Path" und value ist der Rest nach dem ersten =.

MrTopf
quelle
3
+1 für die Split-Methode vermeidet die leichte Hässlichkeit des manuellen Schneidens auf len (Präfix).
Bobince
1
Aber wirft auch, wenn Ihre Eingabe nicht alle in der Form "etwas = etwas anderes" ist.
Dan Olson
1
Deshalb habe ich die Bedingung vorangestellt, damit sie nur verwendet wird, wenn sich ein "=" in der Zeichenfolge befindet. Andernfalls können Sie auch die Länge des Ergebnisses von split () testen und prüfen, ob es == 2 ist.
MrTopf
7
Wie Dan Olson sagt, wird spliteine Ausnahme ausgelöst, wenn das Trennzeichen nicht vorhanden ist. partitionist stabiler, teilt auch eine Zeichenfolge und gibt immer ein Tupel mit drei Elementen mit Vor-, Trennzeichen und Nachinhalt zurück (einige davon können sein, ''wenn das Trennzeichen nicht vorhanden war). ZB , value = line.partition('=').
Anders Johansson
1
Split löst keine Ausnahme aus, wenn das Trennzeichen nicht vorhanden ist. Es gibt eine Liste mit der gesamten Zeichenfolge zurück. Zumindest unter Python 2.7
Maxim
122

Entfernen Sie das Präfix aus einer Zeichenfolge

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

Beim ersten Auftreten des Separators über teilen 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

Analysieren Sie eine INI-ähnliche Datei mit 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

Andere Optionen

jfs
quelle
1
Ein seltener Grund, drei statt vier Leerzeichen einzurücken.
Bob Stein
25
def remove_prefix(text, prefix):
    return text[len(prefix):] if text.startswith(prefix) else text
David Foster
quelle
1
Ich mag dieses, weil Sie "else text" durch "else False" oder "else None" oder einen beliebigen Typ ersetzen können, den Sie zurückgeben möchten, um anzuzeigen, dass die Zeile in der Datei nicht mit "Path =" begonnen hat. Persönlich mag ich es, meine ternären Operatoren mit Klammern zu umgeben, um mich optisch hervorzuheben.
DevPlayer
19

Für das Schneiden (bedingt oder nicht bedingt) im Allgemeinen bevorzuge ich, was ein Kollege kürzlich vorgeschlagen hat; Verwenden Sie Ersatz durch eine leere Zeichenfolge. Einfacher zu lesen, weniger Code (manchmal) und weniger Risiko, die falsche Anzahl von Zeichen anzugeben. OK; Ich benutze kein Python, aber in anderen Sprachen bevorzuge ich diesen Ansatz:

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

oder - um dem ersten Kommentar zu diesem Beitrag nachzugehen - wenn dies nur erfolgen soll, wenn die Zeile beginnt mit Path:

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

Der Hauptunterschied zu einigen der oben vorgeschlagenen Punkte besteht darin, dass weder eine "magische Zahl" (5) beteiligt ist noch die Notwendigkeit besteht, sowohl ' 5' als auch die Zeichenfolge ' Path=' anzugeben. Mit anderen Worten, ich bevorzuge diesen Ansatz gegenüber einer Codepflege Standpunkt.

Fredarin
quelle
Es funktioniert nicht: 'c = Path = a'.replace ("Path =", "", 1) ->' c = a '.
JFS
3
Dies entspricht nicht der ursprünglichen Anforderung der Zeichenfolge, die mit "Path =" beginnt.
Welpe
1
Sie können den Regex-Code durch just ersetzen rightmost = re.sub('^Path=', '', fullPath). Der Zweck der compile()Methode besteht darin, die Dinge schneller zu machen, wenn Sie das kompilierte Objekt wiederverwenden. Da Sie es jedoch nach der Verwendung wegwerfen, hat es hier ohnehin keine Auswirkungen. Es lohnt sich normalerweise sowieso nicht, sich über diese Optimierung Gedanken zu machen.
Jim Oldfield
13

Ich ziehe popdie Indizierung vor [-1]:

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

zu

value = line.split("Path=", 1)[1]
param, value = line.split("Path=", 1)
Thomas Schreiber
quelle
2
Schöne Alternative ohne "magische Zahlen". Es ist erwähnenswert, dass dies funktioniert, weil startswithes bereits getestet wurde, so splitdass "nichts" vorher und alles andere danach geteilt wird. split("Path=", 1)ist genauer (falls das Präfix später in der Zeichenfolge wieder erscheint), führt jedoch eine magische Zahl wieder ein.
Quornian
1
Kürzere Version des (sehr wichtigen) vorherigen Kommentars: Dies funktioniert NUR, wenn Sie zuerst mit startwith () testen.
MarcH
12

Oder warum nicht

if line.startswith(prefix):
    return line.replace(prefix, '', 1)
John Damen
quelle
5

Wie wäre es mit..

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

Dieses Triplett ist der Kopf, der Separator und der Schwanz .

Floggedhorse
quelle
Dies funktioniert nicht in allen Fällen gleich. Wenn das Trennzeichen vorhanden ist, ist das Ergebnis das dritte Element. Andernfalls ist das Ergebnis das erste Element.
Ioannis Filippidis
5

Der einfachste Weg, den ich mir vorstellen kann, ist das Schneiden:

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

Ein kurzer Hinweis zur Slice-Notation: Es werden zwei Indizes anstelle des üblichen verwendet. Der erste Index gibt das erste Element der Sequenz an, die Sie in das Slice aufnehmen möchten, und der letzte Index ist der Index unmittelbar nach dem letzten Element, das Sie in das Slice aufnehmen möchten.
Z.B:

sequence_obj[first_index:last_index]

Das Slice besteht aus allen Elementen zwischen first_indexund last_index, einschließlich first_indexund nicht last_index. Wenn der erste Index weggelassen wird, wird standardmäßig der Anfang der Sequenz verwendet. Wenn der letzte Index weggelassen wird, enthält er alle Elemente bis zum letzten Element in der Sequenz. Negative Indizes sind ebenfalls zulässig. Verwenden Sie Google, um mehr über das Thema zu erfahren.

Batbrat
quelle
4
>>> import re

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

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

>>> re.match(p, path).group(1)
'c:\\path'
Riza
quelle
1. Verwenden Sie r''Zeichenfolgen für Windows-Pfade. 2. re.match()kann keine zurückgeben
jfs
3

Ein weiterer einfacher Einzeiler, der hier nicht erwähnt wurde:

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

Dies funktioniert auch ordnungsgemäß für verschiedene Randfälle:

>>> 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])
""
pR0Ps
quelle
2
line[5:]

gibt Ihnen Zeichen nach den ersten fünf.

Steven Huwig
quelle
1

line[5:]gibt den gewünschten Teilstring. Durchsuchen Sie die Einführung und suchen Sie nach "Slice Notation".

Pete Kirkham
quelle
1

Wenn Sie Listenverständnis kennen:

lines = [line[5:] for line in file.readlines() if line[:5] == "Path="]
Matthew Schinckel
quelle
Es gab eine Bearbeitung, die vorschlug, line.startswith(...)10x schneller zu sein. Meine Tests haben dies nicht bestätigt. Gerne ändern wir es, wenn Beweise für diese Behauptung vorliegen.
Matthew Schinckel
0

Die Pop-Version war nicht ganz richtig. Ich denke du willst:

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

Warum nicht Regex mit Escape verwenden? ^stimmt mit dem Anfangsteil einer Zeile re.MULTILINEüberein und stimmt mit jeder Zeile überein. re.escapestellt sicher, dass die Übereinstimmung genau ist.

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

Versuchen Sie folgenden Code

if line.startswith("Path="): return line[5:]
dipenparmar12
quelle
1
Was ist der Unterschied zwischen Ihrer Antwort und der akzeptierten Antwort? Ich sehe, dass es im ersten Teil der anderen Antwort steht.
eyllanesc
-1

Ich denke, genau das, wonach Sie suchen

    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
Pramod Bhat
quelle
-1

Ohne eine Funktion schreiben zu müssen, wird diese nach Liste aufgeteilt, in diesem Fall 'Mr. | Dr. | Mrs'. Wählen Sie alles nach dem Teilen mit [1] aus, teilen Sie es dann erneut und greifen Sie nach einem beliebigen Element. Im folgenden Fall wird 'Morris' zurückgegeben.

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

Dies ist in der Technik anderen Antworten sehr ähnlich, jedoch ohne wiederholte Zeichenfolgenoperationen, die Fähigkeit zu erkennen, ob das Präfix vorhanden war oder nicht, und dennoch gut lesbar:

parts = the_string.split(prefix_to_remove, 1):
    if len(parts) == 2:
        #  do things with parts[1]
        pass
Kiwi
quelle