特定の部分文字列の後に文字列を取得するにはどうすればよいですか?


226

特定の部分文字列の後に文字列を取得するにはどうすればよいですか?

例えば、私は後の文字列を取得したいです"world"my_string="hello python world , i'm a beginner "

回答:


399

最も簡単な方法は、おそらくターゲット単語を分割することです

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

splitは、分割する単語(または文字)と、オプションで分割数の制限を取得します。

この例では、「world」で分割し、1つの分割のみに制限しています。


「低い」単語でテキストを分割する必要があり、その前に低い単語が含まれている場合、これは機能しません!
Leonardo Hermoso 2017年

1
単純に2倍に分割しますtarget.split('lower',1)[-1].split('low',1)[-1]
Beasley

センテンスが「こんにちはpythonメガワールドワールド、私は初心者」だったとしたらどうでしょう。「メガワールド」のように、単語全体ではなく一部だけを表示するにはどうすればよいですか?ありがとう
pbou 2018

1
次に、検索する文字列は「world」です...または、単語の境界に正規表現を使用します
Beasley

6
my_string.partition("world")[-1](または...[2])の方が高速です。
Martijn Pieters

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

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

に存在しない場合に対処する場合は、s2ではなくs1を使用s1.find(s2)してくださいindex。その呼び出しの戻り値がある場合は-1、その後s2ではありませんs1


(数千で区切られた)異なるIDを取得します...これで不要な部分文字列を作成しないかわかりません
Beasley

@ JoranBeasley、index()、len()、sliceのみを呼び出します。index()とlen()が部分文字列を作成する理由はありません。それらが作成された場合(信じられません)、それは単なる不必要な実装の詳細です。スライスについても同じです。返されるもの以外の部分文字列を作成する必要はありません。
shx2

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

@JoranBeasleyこのスニペットで何を作ろうとしているのですか?複数の呼び出しで異なるオブジェクトが返されますか?「不必要な部分文字列」とは、返されたもの以外の部分文字列、つまり結果を導き出すために作成する必要のない部分文字列を意味します。
shx2

57

誰も言及していないことに驚いていpartitionます。

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

私見、このソリューションは@arshajiiのものよりも読みやすいです。それ以外は、@ arshajiiが最速であるのに最適だと思います-不要なコピー/サブストリングを作成しません。


2
これは優れたソリューションであり、部分文字列がベース文字列の一部ではない場合を適切に処理します。
mattmc3

明確なID(数千で区切られている)を取得します...これで不要な部分文字列を作成しないと確信が持てません(そして、私は怠惰すぎて適切にプロファイルできません)
Joran Beasley

1
@JoranBeasley、それは明らかに不必要なサブスティングを作成ます。私の答えを誤解していると思います。
shx2

(アラシもそうだと思います...)
Joran Beasley

3
さらに、これはより高速ですstr.split(..., 1)
Martijn Pieters

20

あなたが使いたいstr.partition()

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

このオプションは他のオプションよりも速いためです。

区切り文字がない場合は、空の文字列が生成されることに注意してください。

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

元の文字列が必要な場合は、2番目の値がstr.partition()空でないかどうかをテストします。

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

str.split()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 "

ただし、このオプションは遅くなります。最良のシナリオでstr.partition()は、と比較して、約15%速くなります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%

これは、入力ごとの実行ごとのタイミングを示しています。ここでは、区切り文字が欠落している(最悪のシナリオ)、最初に配置されている(最良のシナリオ)、または下半分、上半分、または最後の位置に配置されています。最速タイムをマークしている[...]し、<...>最悪のマーク。

上記の表は、3つのオプションすべての包括的なタイムトライアルによって作成され、以下で作成されます。2017年モデルの15インチMacbook Pro、2.9 GHz Intel Core i7、16 GB RAMを搭載したPython 3.7.4でテストを実行しました。

このスクリプトは、ランダムに選択された区切り記号が存在する場合と存在しない場合のランダムな文を生成し、生成された文のさまざまな位置に存在する場合は、繰り返しでテストをランダムな順序で実行します(テスト中に発生するランダムなOSイベントを説明する最も公正な結果を生成します)。次に、結果の表を出力します。

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

すばらしい答えです!特に、これがより良い本当の理由を提供しているからです:P
Joran Beasley

18

正規表現を使用してこれを行う場合は、非キャプチャグループを使用して、「ワールド」という単語を取得し、その後すべてを取得することができます。

(?:world).*

文字列の例はここでテストされます


28
問題に直面したとき、一部の人々は「私は知っている、正規表現を使用する」と思います。... 2つの問題があります...
Joran Beasley

2
はは、私の間違い、これは正規表現のタグが付いていると思ったので、正規表現の答えを出そうとしました。まあ、それは今そこにあります。
Tadgh 2012

1
そのすべてが良い...確かにこの猫に皮をむく一つの方法...しかしこの問題にはやりすぎ(imho)
Beasley

非キャプチャグループリンクは、正しいものを指していません。
Apteryx 2015

1
興味のある方のために。これが完全なコードですresult = re.search(r"(?:world)(.*)", "hello python world , i'm a beginner ").group(1)
RaduS

5

「substring」と呼ばれるこのパッケージを使用できます。「pip install substring」と入力するだけです。開始文字と終了文字/インデックスに言及するだけで、部分文字列を取得できます。

例えば:

import substring

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

print(s)

出力:

s = defghijklmn


3

それは古い質問ですが、私は非常に同じシナリオに直面しました。「低」という単語を区切り文字として使用して文字列を分割する必要があります。私にとっての問題は、同じ文字列に下と下の単語があることです。

このようにreモジュールを使用して解決しました

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

正規表現でre.splitを使用して、正確な単語に一致させます

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

一般的なコードは次のとおりです。

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

これが誰かを助けることを願っています!


1
おそらく、次のように使用することもできstring.partition(" low ")[2]ます。(両側のスペースに注意してくださいlow
Mtl Dev

1

この一般的なアプローチを試してください:

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

#[" , i'm a beginner "]

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.