374 Stimmen

Wie erhält man eine Zeichenkette nach einer bestimmten Teilzeichenkette?

Wie kann ich eine Zeichenkette nach einer bestimmten Teilzeichenkette erhalten?

Ich möchte zum Beispiel die Zeichenkette nach "world" in

my_string="hello python world, I'm a beginner"

...und das ist in diesem Fall: ", I'm a beginner" )

607voto

Joran Beasley Punkte 102210

Am einfachsten ist es wahrscheinlich, wenn Sie Ihr Zielwort aufteilen

my_string="hello python world , i'm a beginner"
print(my_string.split("world",1)[1])

split nimmt das Wort (oder das Zeichen), an dem gesplittet werden soll, und optional einen Grenzwert für die Anzahl der Splits.

In diesem Beispiel teilen Sie auf "Welt" auf und beschränken Sie es auf nur einen Split.

100voto

shx2 Punkte 57459

Ich bin überrascht, dass niemand erwähnt hat partition .

def substring_after(s, delim):
    return s.partition(delim)[2]

s1="hello python world, I'm a beginner"
substring_after(s1, "world")

# ", I'm a beginner"

IMHO ist diese Lösung besser lesbar als die von @arshajii. Abgesehen davon denke ich, dass die Lösung von @arshajii die schnellste ist, da sie keine unnötigen Kopien/Substrings erstellt.

78voto

arshajii Punkte 125945
s1 = "hello python world , i'm a beginner"
s2 = "world"

print(s1[s1.index(s2) + len(s2):])

Wenn Sie den Fall behandeln wollen, dass s2 es pas vorhanden in s1 verwenden, dann s1.find(s2) im Gegensatz zu index . Wenn der Rückgabewert dieses Aufrufs -1 entonces s2 ist nicht in s1 .

61voto

Martijn Pieters Punkte 953257

Sie möchten Folgendes verwenden str.partition() :

>>> my_string.partition("world")[2]
" , i'm a beginner "

denn diese Option ist schneller als die Alternativen .

Beachten Sie, dass dies eine leere Zeichenkette ergibt, wenn das Trennzeichen fehlt:

>>> my_string.partition("Monty")[2]  # delimiter missing
''

Wenn Sie die ursprüngliche Zeichenkette haben wollen, dann testen Sie, ob die zweite Wert zurückgegeben von str.partition() nicht leer ist:

prefix, success, result = my_string.partition(delimiter)
if not success: result = prefix

Sie können auch Folgendes verwenden str.split() mit einer Grenze von 1:

>>> my_string.split("world", 1)[-1]
" , i'm a beginner "
>>> my_string.split("Monty", 1)[-1]  # delimiter missing
"hello python world , i'm a beginner "

Diese Option ist jedoch Langsamer . Im günstigsten Fall, str.partition() ist leicht über 15% schneller im Vergleich zu str.split() :

                                missing        first         lower         upper          last
      str.partition(...)[2]:  [3.745 usec]  [0.434 usec]  [1.533 usec]  <3.543 usec>  [4.075 usec]
str.partition(...) and test:   3.793 usec    0.445 usec    1.597 usec    3.208 usec    4.170 usec
      str.split(..., 1)[-1]:  <3.817 usec>  <0.518 usec>  <1.632 usec>  [3.191 usec]  <4.173 usec>
            % best vs worst:         1.9%         16.2%          6.1%          9.9%          2.3%

Dies zeigt die Zeitangaben pro Ausführung bei Eingaben, bei denen das Trennzeichen entweder fehlt (im schlimmsten Fall), an erster Stelle steht (im besten Fall) oder in der unteren Hälfte, der oberen Hälfte oder an letzter Stelle. Die schnellste Zeit ist markiert mit [...] y <...> markiert das Schlimmste.

Die obige Tabelle wurde durch einen umfassenden Zeitversuch für alle drei Optionen erstellt, der unten aufgeführt ist. Ich habe die Tests mit Python 3.7.4 auf einem 15" Macbook Pro Modell 2017 mit 2,9 GHz Intel Core i7 und 16 GB Arbeitsspeicher durchgeführt.

Dieses Skript generiert zufällige Sätze mit und ohne das zufällig ausgewählte Trennzeichen, und wenn es vorhanden ist, an verschiedenen Positionen im generierten Satz, führt die Tests in zufälliger Reihenfolge mit Wiederholungen durch (wodurch die fairsten Ergebnisse unter Berücksichtigung zufälliger OS-Ereignisse während des Tests erzielt werden), und gibt dann eine Tabelle mit den Ergebnissen aus:

import random
from itertools import product
from operator import itemgetter
from pathlib import Path
from timeit import Timer

setup = "from __main__ import sentence as s, delimiter as d"
tests = {
    "str.partition(...)[2]": "r = s.partition(d)[2]",
    "str.partition(...) and test": (
        "prefix, success, result = s.partition(d)\n"
        "if not success: result = prefix"
    ),
    "str.split(..., 1)[-1]": "r = s.split(d, 1)[-1]",
}

placement = "missing first lower upper last".split()
delimiter_count = 3

wordfile = Path("/usr/dict/words")  # Linux
if not wordfile.exists():
    # macos
    wordfile = Path("/usr/share/dict/words")
words = [w.strip() for w in wordfile.open()]

def gen_sentence(delimiter, where="missing", l=1000):
    """Generate a random sentence of length l

    The delimiter is incorporated according to the value of where:

    "missing": no delimiter
    "first":   delimiter is the first word
    "lower":   delimiter is present in the first half
    "upper":   delimiter is present in the second half
    "last":    delimiter is the last word

    """
    possible = [w for w in words if delimiter not in w]
    sentence = random.choices(possible, k=l)
    half = l // 2
    if where == "first":
        # best case, at the start
        sentence[0] = delimiter
    elif where == "lower":
        # lower half
        sentence[random.randrange(1, half)] = delimiter
    elif where == "upper":
        sentence[random.randrange(half, l)] = delimiter
    elif where == "last":
        sentence[-1] = delimiter
    # else: worst case, no delimiter

    return " ".join(sentence)

delimiters = random.choices(words, k=delimiter_count)
timings = {}
sentences = [
    # where, delimiter, sentence
    (w, d, gen_sentence(d, w)) for d, w in product(delimiters, placement)
]
test_mix = [
    # label, test, where, delimiter sentence
    (*t, *s) for t, s in product(tests.items(), sentences)
]
random.shuffle(test_mix)

for i, (label, test, where, delimiter, sentence) in enumerate(test_mix, 1):
    print(f"\rRunning timed tests, {i:2d}/{len(test_mix)}", end="")
    t = Timer(test, setup)
    number, _ = t.autorange()
    results = t.repeat(5, number)
    # best time for this specific random sentence and placement
    timings.setdefault(
        label, {}
    ).setdefault(
        where, []
    ).append(min(dt / number for dt in results))

print()

scales = [(1.0, 'sec'), (0.001, 'msec'), (1e-06, 'usec'), (1e-09, 'nsec')]
width = max(map(len, timings))
rows = []
bestrow = dict.fromkeys(placement, (float("inf"), None))
worstrow = dict.fromkeys(placement, (float("-inf"), None))

for row, label in enumerate(tests):
    columns = []
    worst = float("-inf")
    for p in placement:
        timing = min(timings[label][p])
        if timing < bestrow[p][0]:
            bestrow[p] = (timing, row)
        if timing > worstrow[p][0]:
            worstrow[p] = (timing, row)
        worst = max(timing, worst)
        columns.append(timing)

    scale, unit = next((s, u) for s, u in scales if worst >= s)
    rows.append(
        [f"{label:>{width}}:", *(f" {c / scale:.3f} {unit} " for c in columns)]
    )

colwidth = max(len(c) for r in rows for c in r[1:])
print(' ' * (width + 1), *(p.center(colwidth) for p in placement), sep="  ")
for r, row in enumerate(rows):
    for c, p in enumerate(placement, 1):
        if bestrow[p][1] == r:
            row[c] = f"[{row[c][1:-1]}]"
        elif worstrow[p][1] == r:
            row[c] = f"<{row[c][1:-1]}>"
    print(*row, sep="  ")

percentages = []
for p in placement:
    best, worst = bestrow[p][0], worstrow[p][0]
    ratio = ((worst - best) / worst)
    percentages.append(f"{ratio:{colwidth - 1}.1%} ")

print("% best vs worst:".rjust(width + 1), *percentages, sep="  ")

25voto

Tadgh Punkte 1979

Wenn Sie dies mit Regex machen wollen, können Sie einfach eine nicht fangende Gruppe , um das Wort "Welt" zu erhalten und dann alles danach zu erfassen, etwa so

(?:world).*

Die Beispielzeichenkette wird getestet aquí

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X