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


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:



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


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


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

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.


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)

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)

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 .


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.


4
>>> import re

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

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

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

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])
""



1

Wenn Sie Listenverständnis kennen:

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

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

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

0

Versuchen Sie folgenden Code

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

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

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

-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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.