Belirli bir alt dizeden sonra dize nasıl alınır?


227

Belirli bir alt dizeden sonra nasıl dize alabilirim?

Örneğin, sonra dize almak istiyorum "world"içindemy_string="hello python world , i'm a beginner "

Yanıtlar:


400

En kolay yol muhtemelen sadece hedef kelimenizi ayırmaktır

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

split, bölünecek kelimeyi (veya karakteri) ve isteğe bağlı olarak ayırma sayısı için bir sınır alır.

Bu örnekte "dünya" ya bölün ve onu sadece bir bölünmeyle sınırlayın.


Bir metni 'düşük' kelimeyle bölmem gerekiyorsa ve daha önce daha düşük kelimeyi içeriyorsa, bu çalışmaz!
Leonardo Hermoso

1
2x simpley splittarget.split('lower',1)[-1].split('low',1)[-1]
Joran Beasley

ya cümle "merhaba python Megaworld dünyası, ben bir acemiyim". Sözcüğün tamamını 'Megaworld' olarak değil, bütün kelimeye bakmasını nasıl sağlayabilirim? Teşekkürler
pbou

1
aradığınız dize "dünya" dır ... ya da kelime sınırlaması için regex kullanın
Joran Beasley

6
my_string.partition("world")[-1](veya ...[2]) daha hızlıdır.
Martijn Pieters

66
s1 = "hello python world , i'm a beginner "
s2 = "world"

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

Nereye dava ile uğraşmak istiyorsanız s2olduğu değil mevcut s1, daha sonra kullanmak s1.find(s2)yerine index. Bu aramanın dönüş değeri ise -1, o zaman s2değil s1.


farklı kimlikleri (birkaç bin ile ayrılmış) alırsınız ... bununla gereksiz alt dizeler oluşturmadığınızdan emin değilim
Joran Beasley

@JoranBeasley, biz sadece index (), len () ve dilim çağırıyoruz. İndex () ve len () alt dizeleri oluşturmak için bir neden yoktur ve eğer yaparlarsa (inanmak zor bulursam), bu sadece gereksiz bir uygulama detayıdır. Dilim için aynı - döndürülenden başka alt dizeler oluşturmasının bir nedeni yoktur.
shx2

@ shx2print( s1[s1.index(s2) + len(s2):] is s1[s1.index(s2) + len(s2):])
Joran Beasley

@JoranBeasley bu pasajla hangi noktayı yapmaya çalışıyorsunuz? Birden fazla çağrıda farklı nesneler döndürülür mü? "gereksiz alt dizeler" ile, geri dönenin dışındaki alt dizeleri, yani sonucu türetmek için oluşturulması gerekmeyen alt dizeleri kastediyorum.
shx2

57

Kimsenin bahsetmediğine şaşırdım partition.

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

IMHO, bu çözüm @ arshajii'den daha okunabilir. Bunun dışında, @ arshajii's en hızlı olmak için en iyisi olduğunu düşünüyorum - gereksiz kopya / alt dizeleri oluşturmaz.


2
Bu güzel bir çözümdür ve alt dizenin temel dizenin bir parçası olmadığı durumu ele alır.
mattmc3

farklı kimlikleri (birkaç bin ile ayrılmış) alırsınız ... bununla gereksiz alt dizeler oluşturmadığınızdan emin değilim (ve düzgün bir şekilde profil oluşturmak için çok tembelim)
Joran Beasley

1
@JoranBeasley, açıkça yapar gereksiz substings oluşturun. Sanırım cevabımı yanlış okudun.
shx2

(sanırım arashi de öyle ...)
Joran Beasley

3
Üstelik bu hızlı daha str.split(..., 1).
Martijn Pieters

20

Kullanmak istediğiniz str.partition():

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

çünkü bu seçenek alternatiflerden daha hızlı .

Sınırlayıcı eksikse bunun boş bir dize oluşturduğunu unutmayın:

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

Orijinal dizeye sahip olmak istiyorsanız, döndürülen ikinci değerin str.partition()boş olup olmadığını test edin :

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

str.split()1'lik bir sınırla da kullanabilirsiniz :

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

Ancak, bu seçenek daha yavaştır . En iyi senaryo için str.partition()aşağıdakilere kıyasla kolayca yaklaşık % 15 daha hızlıdırstr.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%

Bu, sınırlayıcıda eksik olan (en kötü senaryo), önce yerleştirilen (en iyi senaryo) veya alt yarı, üst yarı veya son konumda girişlerle yürütme başına zamanlamaları gösterir . En hızlı zaman ile işaretlenir [...]ve <...>en kötüsü işaretlenir.

Yukarıdaki tablo, aşağıdaki üç seçenek için kapsamlı bir zaman denemesi ile üretilmiştir. Testleri 2.9 GHz Intel Core i7 ve 16 GB ram ile 2017 model 15 "Macbook Pro'da Python 3.7.4'te gerçekleştirdim.

Bu komut dosyası, rasgele seçilen sınırlayıcı olan ve olmayan rastgele cümleler oluşturur ve varsa, oluşturulan cümlenin farklı konumlarında, testleri tekrarlarla rastgele sırayla çalıştırır (test sırasında meydana gelen rastgele işletim sistemi olayları için en adil sonuçları üreterek), ve sonra sonuçların bir tablosunu yazdırır:

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

mükemmel cevap! özellikle bunun daha iyi bir gerçek nedeni
sunduğunuz için

18

Bunu regex kullanarak yapmak istiyorsanız, sadece "dünya" kelimesini almak için yakalamayan bir grup kullanabilirsiniz ve sonra her şeyi,

(?:world).*

Örnek dize burada test edilir


28
bazı insanlar bir sorunla karşılaştıklarında "Biliyorum, düzenli bir ifade kullanacağım" diye düşünüyorlar. ... şimdi 2 probleminiz var ...
Joran Beasley

2
haha, benim hatam, bunun normal ifade olarak etiketlendiğini düşündüm, bu yüzden normal ifade cevabı vermeye çalıştım. Ah, şimdi orada.
Tadgh

1
hepsi iyi ... kesinlikle bu kedi derisi bir yolu ... olsa da bu sorun için overkill (imho)
Joran Beasley

Yakalamayan grup bağlantısı artık doğru şeyi işaret etmiyor.
Apteryx

1
İlgilenenler için. İşte tam kodresult = re.search(r"(?:world)(.*)", "hello python world , i'm a beginner ").group(1)
RaduS

5

"Substring" adlı bu paketi kullanabilirsiniz. Sadece "pip install substring" yazın. Alt dizeyi yalnızca başlangıç ​​ve bitiş karakterlerinden / dizinlerinden bahsederek alabilirsiniz.

Örneğin:

import substring

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

print(s)

Çıktı:

s = defghijklmn


3

Bu eski bir soru ama ben çok aynı senaryo ile karşı karşıya, demiliter kelime "düşük" kullanarak bir dizeyi bölmek gerekir benim için sorun ben aynı dize aşağıdaki kelime ve daha düşük olması oldu.

Bu şekilde re modülünü kullanarak çözdüm

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

tam kelimeyi eşleştirmek için regex ile re.split kullanın

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

genel kod:

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

Umarım bu birine yardımcı olabilir!


1
Belki de sadece kullanabilirsiniz: string.partition(" low ")[2]? (Her iki taraftaki boşluklara dikkat edinlow
Mtl Dev

1

Bu genel yaklaşımı deneyin:

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

#[" , i'm a beginner "]

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.