특정 부분 문자열 다음에 문자열을 얻는 방법?


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"로 분할하여 하나의 분할로만 제한합니다.


'낮은'단어로 텍스트를 분할해야하고 그 앞에 낮은 단어가 포함되어 있으면 작동하지 않습니다!
Leonardo Hermoso

1
당신은 간단하게 2 배를 분할합니다target.split('lower',1)[-1].split('low',1)[-1]
Joran Beasley

문장이 "hello python Megaworld world, 나는 초보자입니다"라면 어떨까요? 단어 전체를 다른 단어의 일부가 아닌 '메가 월드'로 보도록하려면 어떻게해야합니까? 감사
pbou

1
검색 문자열은 "world"... 또는 단어 경계에 정규식을 사용합니다.
Joran 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.


당신은 (수천로 구분됩니다) 별개의 아이디의이 ... 메신저하지 않도록이 함께 불필요한 문자열을 작성 해달라고 얻을
Joran 비즐리

@JoranBeasley, 우리는 index (), len () 및 slice 만 호출합니다. index ()와 len ()이 서브 스트링을 생성 할 이유가 없으며, 만약 그렇게한다면 (믿기 어렵다), 그것은 불필요한 구현 세부 사항 일뿐입니다. slice와 동일-반환 된 문자열 이외의 하위 문자열을 생성 할 이유가 없습니다.
shx2

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

@JoranBeasley이 스 니펫으로 어떤 점을 만들려고하십니까? 여러 호출에서 다른 객체가 반환됩니까? "불필요한 부분 문자열"이란 반환 된 것 이외의 부분 문자열, 즉 결과를 도출하기 위해 만들 필요가없는 부분 문자열을 의미합니다.
shx2

56

아무도 언급하지 않은 것에 놀랐습니다 partition.

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

IMHO,이 솔루션은 @arshajii보다 더 읽기 쉽습니다. 그 외에는 @arshajii가 가장 빠른 것이 가장 좋다고 생각합니다. 불필요한 사본 / 하위 문자열을 만들지 않습니다.


2
이것은 훌륭한 솔루션이며 하위 문자열이 기본 문자열의 일부가 아닌 경우를 처리합니다.
mattmc3

당신은 (수천로 구분됩니다) 별개의 아이디의이 ... 메신저하지 않도록이 함께 불필요한 문자열을 작성 해달라고 수 (및 메신저가 너무 게으른 제대로 프로파일)
Joran 비즐리

1
@JoranBeasley, 명확 하지 불필요한 substings을 만들 수 있습니다. 내 대답을 잘못 읽은 것 같아
shx2

(그래서 ... 내가 생각하는 아라시의 작업을 수행)
Joran 비즐리

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

원래 문자열을 원하면 반환 된 두 번째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%

여기에는 구분 기호가 없거나 (최악의 시나리오), 첫 번째 (최고의 시나리오) 또는 아래쪽, 위쪽 또는 마지막 위치에 입력이있는 실행 당 타이밍이 표시 됩니다. 가장 빠른 시간이 표시되어 [...]<...>마크 최악.

위의 표는 아래에서 생성 된 세 가지 옵션 모두에 대한 포괄적 인 타임 트라이얼에 의해 생성됩니다. 2.9GHz Intel Core i7 및 16GB 램이 장착 된 2017 년 모델 15 인치 Macbook Pro에서 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 비즐리

18

정규 표현식을 사용 하여이 작업을 수행하려면 캡처하지 않는 그룹을 사용하여 "world"라는 단어를 얻은 다음 모든 것을 잡을 수 있습니다.

(?:world).*

예제 문자열은 여기에서 테스트 됩니다


28
어떤 사람들은 문제에 직면했을 때 "나는 정규 표현식을 사용하겠다"고 생각합니다. ... 지금 당신은 두 가지 문제가 있습니다 ...
Joran Beasley

2
하하, 내 실수, 나는 이것이 정규 표현식으로 태그되었다고 생각했기 때문에 정규 표현식 답변을 시도했다. 잘 지내고 있습니다.
Tadgh

1
그것의 모든 좋은 ... 확실히이 고양이를 스키닝하는 한 가지 방법 ...하지만이 문제에 대한 과잉 (imho)
Joran Beasley

캡처하지 않은 그룹 링크가 더 이상 올바른 것을 가리 키지 않습니다.
Apteryx

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 데브

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.