Bagaimana cara mendapatkan string setelah substring tertentu?

226

Bagaimana saya bisa mendapatkan string setelah substring tertentu?

Sebagai contoh, saya ingin mendapatkan string setelah "world"masukmy_string="hello python world , i'm a beginner "

havox
sumber

Jawaban:

399

Cara termudah mungkin hanya dengan membagi kata target Anda

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

split mengambil kata (atau karakter) untuk dibagi dan secara opsional membatasi jumlah split.

Dalam contoh ini, perpecahan pada "dunia" dan batasi hanya untuk satu pemisahan.

Joran Beasley
sumber
Jika saya perlu membagi teks dengan kata 'rendah' ​​dan berisi kata lebih rendah dari itu, ini tidak akan berfungsi!
Leonardo Hermoso
1
Anda akan simpley membagi 2xtarget.split('lower',1)[-1].split('low',1)[-1]
Joran Beasley
bagaimana jika kalimatnya adalah "hello python dunia Megaworld, saya seorang pemula". Bagaimana saya bisa membuatnya melihat seluruh kata dan bukan bagian dari yang lain sebagai 'Megaworld'? Terima kasih
pbou
1
maka string yang Anda cari adalah "dunia" ... atau gunakan regex untuk kata boundrys
Joran Beasley
6
my_string.partition("world")[-1](atau ...[2]) lebih cepat.
Martijn Pieters
66
s1 = "hello python world , i'm a beginner "
s2 = "world"

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

Jika Anda ingin menangani kasing s2yang tidak ada s1, gunakan s1.find(s2)sebagai lawan index. Jika nilai balik dari panggilan itu adalah -1, maka s2tidak ada dalam s1.

arshajii
sumber
Anda mendapatkan id berbeda (yang dipisahkan oleh beberapa ribu) ... saya tidak yakin Anda tidak membuat substring yang tidak perlu dengan ini
Joran Beasley
@JoranBeasley, kami hanya memanggil index (), len () dan slice. Tidak ada alasan untuk index () dan len () untuk membuat substring, dan jika mereka lakukan (saya merasa sulit untuk percaya), itu hanya detail implementasi yang tidak perlu. Sama untuk slice - tidak ada alasan untuk membuat substring selain yang dikembalikan.
shx2
@ shx2print( s1[s1.index(s2) + len(s2):] is s1[s1.index(s2) + len(s2):])
Joran Beasley
@JoranBeasley poin apa yang ingin Anda buat dengan cuplikan ini Bahwa pada beberapa panggilan objek yang berbeda dikembalikan? dengan "substring yang tidak perlu" Maksud saya substring selain yang dikembalikan, yaitu substring yang tidak perlu dibuat untuk mendapatkan hasil.
shx2
57

Saya terkejut tidak ada yang disebutkan partition.

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

IMHO, solusi ini lebih mudah dibaca daripada @ arshajii. Selain itu, saya pikir @ arshajii's adalah yang terbaik untuk menjadi yang tercepat - tidak membuat salinan / substring yang tidak perlu.

shx2
sumber
2
Ini adalah solusi yang bagus, dan menangani kasus di mana substring bukan bagian dari string dasar dengan baik.
mattmc3
Anda mendapatkan id berbeda (yang dipisahkan oleh beberapa ribu) ... saya tidak yakin Anda tidak membuat substring yang tidak perlu dengan ini (dan saya terlalu malas untuk benar profil itu)
Joran Beasley
1
@JoranBeasley, itu jelas tidak membuat substings yang tidak perlu. Saya pikir Anda salah membaca jawaban saya.
shx2
(begitu juga arashi, saya pikir ...)
Joran Beasley
3
Selain itu, ini lebih cepat daripada str.split(..., 1).
Martijn Pieters
20

Anda ingin menggunakan str.partition():

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

karena opsi ini lebih cepat daripada alternatifnya .

Perhatikan bahwa ini menghasilkan string kosong jika pembatas tidak ada:

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

Jika Anda ingin memiliki string asli, maka uji apakah nilai kedua yang dikembalikan dari str.partition()adalah tidak kosong:

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

Anda juga dapat menggunakan str.split()dengan batas 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 "

Namun, opsi ini lebih lambat . Untuk skenario kasus terbaik, str.partition()dengan mudah sekitar 15% lebih cepat dibandingkan dengan 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%

Ini menunjukkan timing per eksekusi dengan input di sini pembatas tidak ada (skenario terburuk), ditempatkan pertama (skenario kasus terbaik), atau di bagian bawah, setengah atas atau posisi terakhir. Waktu tercepat ditandai dengan [...]dan <...>menandai yang terburuk.

Tabel di atas dihasilkan oleh uji waktu komprehensif untuk ketiga opsi, yang diproduksi di bawah ini. Saya menjalankan tes pada Python 3.7.4 pada model 2017 15 "Macbook Pro dengan 2,9 GHz Intel Core i7 dan 16 GB ram.

Script ini menghasilkan kalimat acak dengan dan tanpa hadir pembatas yang dipilih secara acak, dan jika ada, pada posisi yang berbeda dalam kalimat yang dihasilkan, menjalankan tes secara acak dengan pengulangan (menghasilkan hasil yang paling adil untuk peristiwa OS acak yang terjadi selama pengujian), dan kemudian mencetak tabel hasil:

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="  ")
Martijn Pieters
sumber
jawaban bagus! terutama karena Anda memberikan alasan sebenarnya ini lebih baik: P
Joran Beasley
18

Jika Anda ingin melakukan ini menggunakan regex, Anda bisa menggunakan grup yang tidak menangkap , untuk mendapatkan kata "dunia" dan kemudian mengambil semuanya setelahnya, seperti

(?:world).*

Contoh string diuji di sini

Tadgh
sumber
28
beberapa orang ketika dihadapkan dengan masalah berpikir "Saya tahu, saya akan menggunakan ekspresi reguler." ... sekarang Anda memiliki 2 masalah ...
Joran Beasley
2
haha, kesalahan saya, saya pikir ini ditandai regex jadi saya mencoba memberikan jawaban regex. Oh well, itu ada di sana sekarang.
Tadgh
1
itu semua baik ... itu pasti salah satu cara menguliti kucing ini ... terlalu banyak kesulitan untuk masalah ini (imho)
Joran Beasley
Tautan grup yang tidak menangkap tidak lagi menunjuk ke hal yang benar.
Apteryx
1
Bagi yang berminat. Ini kode lengkapnyaresult = re.search(r"(?:world)(.*)", "hello python world , i'm a beginner ").group(1)
RaduS
5

Anda dapat menggunakan paket ini yang disebut "substring". Cukup ketikkan "pip install substring". Anda bisa mendapatkan substring dengan hanya menyebutkan awal / akhir karakter / indeks.

Sebagai contoh:

import substring

s = substring.substringByChar("abcdefghijklmnop", startChar="d", endChar="n")

print(s)

Keluaran:

s = defghijklmn

Sriram Veturi
sumber
3

Ini adalah pertanyaan lama tetapi saya menghadapi skenario yang sangat sama, saya perlu membagi string menggunakan sebagai demiliter kata "rendah" masalah bagi saya adalah bahwa saya memiliki string yang sama kata di bawah dan lebih rendah.

Saya memecahkannya menggunakan modul re dengan cara ini

import re

string = '...below...as higher prices mean lower demand to be expected. Generally, a high reading is seen as negative (or bearish), while a low reading is seen as positive (or bullish) for the Korean Won.'

gunakan re.split dengan regex untuk mencocokkan kata yang tepat

stringafterword = re.split('\\blow\\b',string)[-1]
print(stringafterword)
' reading is seen as positive (or bullish) for the Korean Won.'

kode generiknya adalah:

re.split('\\bTHE_WORD_YOU_WANT\\b',string)[-1]

Semoga ini bisa membantu seseorang!

Leonardo Hermoso
sumber
1
Mungkin Anda juga bisa menggunakan string.partition(" low ")[2]:? (Perhatikan spasi di kedua sisilow
Mtl Dev
1

Coba pendekatan umum ini:

import re
my_string="hello python world , i'm a beginner "
p = re.compile("world(.*)")
print (p.findall(my_string))

#[" , i'm a beginner "]
Hadij
sumber