Как получить строку после определенной подстроки?

228

Как я могу получить строку после определенной подстроки?

Например, я хочу , чтобы получить строку после того, как "world"вmy_string="hello python world , i'm a beginner "

havox
источник

Ответы:

401

Самый простой способ, вероятно, просто разделить на целевое слово

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

split принимает слово (или символ) для разделения и, по желанию, ограничение на количество разделений.

В этом примере разделить на «мир» и ограничить его только одним разделением.

Джоран Бизли
источник
Если мне нужно разделить текст словом «low», и перед ним будет слово «low», это не сработает!
Леонардо Эрмосо
1
Вы бы просто разделились 2xtarget.split('lower',1)[-1].split('low',1)[-1]
Джоран Бизли
Что делать, если предложение было «Привет, мир мега-мира Python, я новичок». Как я могу заставить это смотреть на все слово, а не на часть другого как «Мегамир»? Спасибо
ПОБ
1
тогда искомая строка - "мир" ... или используйте регулярное выражение для границ слова
Beasley
6
my_string.partition("world")[-1](или ...[2]) быстрее.
Мартин Питерс
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.

arshajii
источник
вы получаете разные идентификаторы (которые разделены несколькими тысячами) ... я не уверен, что вы не создадите ненужные подстроки с этим
Joran Beasley
@JoranBeasley, мы вызываем только index (), len () и slice. Нет никаких причин для index () и len () создавать подстроки, и если они это делают (мне трудно в это поверить), это просто ненужная деталь реализации. То же самое для слайса - нет причин для создания подстрок, отличных от возвращенной.
shx2
@ shx2print( s1[s1.index(s2) + len(s2):] is s1[s1.index(s2) + len(s2):])
Джоран Бизли
@JoranBeasley, что ты пытаешься сделать с помощью этого фрагмента? Что при множественных вызовах возвращаются разные объекты? Под «ненужными подстроками» я подразумеваю подстроки, отличные от возвращенной, то есть подстроки, которые не нужно создавать для получения результата.
shx2
57

Я удивлен, что никто не упомянул partition.

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

ИМХО, это решение более читабельно, чем @ arshajii's. Кроме этого, я думаю, что @ arshajii's лучше всего подходит для того, чтобы быть самым быстрым - он не создает ненужных копий / подстрок.

shx2
источник
2
Это хорошее решение, и оно прекрасно обрабатывает случай, когда подстрока не является частью базовой строки.
mattmc3
вы получаете разные идентификаторы (которые разделены несколькими тысячами) ... я не уверен, что вы не создадите ненужные подстроки с этим (и мне лень правильно его профилировать)
Joran Beasley
1
@JoranBeasley, он явно делает создавать ненужные substings. Я думаю, что вы неправильно поняли мой ответ.
shx2
(как и Араши, я думаю ...)
Джоран Бизли
3
Более того, это быстрее, чем str.split(..., 1).
Мартин Питерс
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%

Это показывает время выполнения на входе, здесь разделитель отсутствует (сценарий наихудшего случая), помещается первым (сценарий наивысшего варианта) или в нижней половине, верхней половине или последней позиции. Самое быстрое время помечено [...]и <...>отмечает худшее.

Приведенная выше таблица составлена ​​путем комплексного испытания времени для всех трех вариантов, представленных ниже. Я провел тесты на Python 3.7.4 на модели MacBook Pro с диагональю 15 дюймов в 2017 году, Intel Core i7 с частотой 2,9 ГГц и оперативной памятью 16 ГБ.

Этот сценарий генерирует случайные предложения с наличием случайно выбранного разделителя и без него, и, если он присутствует, в разных позициях сгенерированного предложения, запускает тесты в случайном порядке с повторениями (производя самые точные результаты, учитывающие случайные события ОС, происходящие во время тестирования), а затем печатает таблицу результатов:

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="  ")
Мартейн Питерс
источник
отличный ответ! особенно потому, что вы
Joran Beasley
18

Если вы хотите сделать это с помощью регулярных выражений, вы можете просто использовать группу без захвата , чтобы получить слово «мир», а затем захватить все после, например, так

(?:world).*

Пример строки проверяется здесь

Tadgh
источник
28
некоторые люди, столкнувшись с проблемой, думают: «Я знаю, я буду использовать регулярное выражение». ... теперь у вас 2 проблемы ...
Joran Beasley
2
ха-ха, моя ошибка, я думал, что это было помечено регулярное выражение, поэтому я попытался дать ответ регулярного выражения. Ну что ж, сейчас там.
Tadgh
1
это все хорошо ... это, конечно, один из способов снятия шкуры с этой кошки ... хотя это слишком для этой проблемы (imho)
Joran Beasley
Ссылка на группу без захвата больше не указывает на правильную вещь.
Аптерикс
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

Это старый вопрос, но я столкнулся с тем же сценарием, мне нужно разбить строку, используя в качестве демилитера слово «низкий», проблема для меня заключалась в том, что у меня в одной строке слово ниже и ниже.

Я решил это с помощью повторного модуля таким образом

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 "]
Hadij
источник