Як отримати рядок після певної підрядки?


227

Як я можу отримати рядок після певної підрядки?

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

Відповіді:


400

Найпростіший спосіб - це, мабуть, просто розділити цільове слово

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

split - це слово (або символ), щоб розділити на нього та, можливо, обмежити кількість розбитків.

У цьому прикладі розділіть на "світ" і обмежте його лише одним розколом.


Якщо мені потрібно розділити текст на "низьке" слово, і воно містить слово нижче перед ним, це не вийде!
Леонардо Гермосо

1
Ви б просто розділили 2xtarget.split('lower',1)[-1].split('low',1)[-1]
Joran Beasley

що робити, якщо речення було "привіт пітон мегасвіту, я початківець". Як я можу змусити це виглядати на все слово, а не на частину іншого, як на "Мегасвіті"? Спасибі
pbou

1
то рядок, яку ви шукаєте, є "світовою" ... або використовуйте регулярні вирази для меж слова
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 Beasley,

@JoranBeasley, ми називаємо лише індекс (), len () та фрагмент. Немає підстав для створення index () та len () створювати підрядки, а якщо вони є (мені важко повірити), це просто непотрібна деталь реалізації. Те ж саме для фрагмента - немає підстав для його створення підрядів, окрім повернутого.
shx2

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

@JoranBeasley Яку точку ти намагаєшся зробити з цим фрагментом? Що при кількох викликах повертаються різні об'єкти? Під "непотрібними підрядками" я маю на увазі підрядки, відмінні від повернутого, тобто підрядки, які не потрібно створювати для отримання результату.
shx2

57

Я здивований, що ніхто не згадав partition.

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

ІМХО, це рішення є більш читабельним, ніж рішення @ aršajii. Крім цього, я думаю, що @ arshajii's найкращий для того, щоб бути найшвидшим - він не створює зайвих копій / підрядків.


2
Це приємне рішення, і обробляє випадок, коли підрядок не є частиною базового рядка.
mattmc3

ви отримуєте виразні ідентифікатори (які розділені кількома тисячами) ... я не впевнений, що ви не створюєте непотрібні підрядки з цим (і я занадто лінивий, щоб правильно його профілювати)
Joran Beasley

1
@JoranBeasley, він явно робить створювати непотрібні substings. Я думаю, ви неправильно прочитали мою відповідь.
shx2

(так я думаю про
Біслі,

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%

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

Наведена вище таблиця складається з вичерпного випробування часом для всіх трьох варіантів, наведених нижче. Я провів тести на Python 3.7.4 на моделі MacBook Pro 15 "на 15" з 2,9 ГГц Intel Core i7 та 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

Якщо ви хочете зробити це за допомогою regex, ви можете просто скористатися групою , яка не захоплює , щоб отримати слово "world", а потім схопити все після, як так

(?:world).*

Приклад рядка тестується тут


28
деякі люди, стикаючись з проблемою, думають: "Я знаю, я вживаю регулярний вираз". ... тепер у вас є 2 проблеми ...
Джоран Біслі,

2
ха-ха, моя помилка, я подумав, що це позначено регулярним виразом, тому я спробував дати відповідь на регулярний вираз. Ну добре, це там зараз.
Tadgh

1
все добре ... це, безумовно, один із способів зняти цю кішку ... хоч надмірність для цієї проблеми (imho)
Joran Beasley

Група, що не захоплює, більше не вказує на правильну річ.
Аптерикс

1
Для зацікавлених. Ось повний кодresult = re.search(r"(?:world)(.*)", "hello python world , i'm a beginner ").group(1)
RaduS

5

Ви можете використовувати цей пакет під назвою "підрядка". Просто введіть "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 "]

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.