如何在特定子字符串之后获取字符串?

Posted

技术标签:

【中文标题】如何在特定子字符串之后获取字符串?【英文标题】:How to get a string after a specific substring? 【发布时间】:2012-09-16 08:17:34 【问题描述】:

比如我想获取"world"之后的字符串

my_string="hello python world, I'm a beginner"

...在这种情况下是:", I'm a beginner")

【问题讨论】:

【参考方案1】:

最简单的方法可能就是拆分目标词

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

split 接受要拆分的单词(或字符),并且可以选择限制拆分的数量。

在本例中,在“世界”上拆分并将其限制为仅一个拆分。

【讨论】:

如果我需要用 'low' 字分割一个文本,并且它前面包含了 lower 字,这将不起作用! 你可以简单地拆分 2x target.split('lower',1)[-1].split('low',1)[-1] 如果句子是“hello python Megaworld world,我是初学者”怎么办。我怎样才能让它看到整个词而不是另一个词的一部分作为“Megaworld”?谢谢 那么您搜索的字符串是“world” ...或使用正则表达式作为单词边界 my_string.partition("world")[-1](或...[2])更快。【参考方案2】:
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(被几千个分隔)......我不确定你不会用这个创建不必要的子字符串 @JoranBeasley,我们只调用 index()、len() 和 slice。 index() 和 len() 没有理由创建子字符串,如果他们这样做(我觉得很难相信),那只是不必要的实现细节。 slice 也一样——除了返回的子字符串之外,没有理由创建子字符串。 @shx2 print( s1[s1.index(s2) + len(s2):] is s1[s1.index(s2) + len(s2):]) @JoranBeasley 你想用这个 sn-p 做什么?在多次调用中返回不同的对象? “不必要的子字符串”是指返回的子字符串以外的子字符串,即不需要创建子字符串以得出结果。【参考方案3】:

我很惊讶没有人提到partition

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

恕我直言,这个解决方案比@arshajii 的更具可读性。除此之外,我认为@arshajii 是最快的——它不会创建任何不必要的副本/子字符串。

【讨论】:

这是一个很好的解决方案,可以很好地处理子字符串不是基本字符串的一部分的情况。 你得到不同的 id(被几千个分隔)......我不确定你不会用这个创建不必要的子字符串(而且我懒得正确分析它) @JoranBeasley,它显然确实创建了不必要的替换。我想你误读了我的回答。 (我认为 arashi 也是如此......) 而且,这比str.split(..., 1)【参考方案4】:

你想使用str.partition():

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

因为此选项比其他选项更快

请注意,如果缺少分隔符,这会产生一个空字符串:

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

如果你想要原始字符串,那么测试从str.partition()返回的second值是否为非空:

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()str.split() 相比,速度轻松15%

                                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%

这显示了每次执行的时间,这里的输入分隔符要么缺失(最坏情况),要么放在首位(最好情况),要么位于下半部分、上半部分或最后一个位置。最快的时间用[...] 标记,&lt;...&gt; 标记最差的时间。

上表是通过对所有三个选项的综合计时试验产生的,如下所示。我在配备 2.9 GHz Intel Core i7 和 16 GB 内存的 2017 型号 15" Macbook Pro 上运行 Python 3.7.4 测试。

此脚本生成随机句子,有和没有随机选择的分隔符,如果存在,在生成的句子的不同位置,以随机顺序重复运行测试(产生最公平的结果,说明在testing),然后打印结果表:

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【参考方案5】:

如果您想使用正则表达式执行此操作,您可以简单地使用 non-capturing group 来获取“世界”这个词,然后抓取之后的所有内容,就像这样

(?:world).*

示例字符串经过测试here

【讨论】:

有些人在遇到问题时会想“我知道,我会使用正则表达式”。 ...现在你有 2 个问题... 哈哈,我的错,我以为这是正则表达式,所以我试图给出一个正则表达式的答案。哦,好吧,它现在就在那里。 这一切都很好......这肯定是给这只猫剥皮的一种方法......不过这个问题有点过头了(恕我直言) 非捕获组链接不再指向正确的东西。 对于那些感兴趣的人。这是完整代码result = re.search(r"(?:world)(.*)", "hello python world , i'm a beginner ").group(1) 【参考方案6】:

在 Python 3.9 中,正在添加一个新的 removeprefix 方法:

>>> 'TestHook'.removeprefix('Test')
'Hook'
>>> 'BaseTestCase'.removeprefix('Test')
'BaseTestCase'
文档:https://docs.python.org/3.9/library/stdtypes.html#str.removeprefix 公告:https://docs.python.org/3.9/whatsnew/3.9.html

【讨论】:

【参考方案7】:

这是一个老问题,但我遇到了一个非常相同的情况,我需要使用分隔符“low”这个词来分割一个字符串,对我来说,问题是我在同一个字符串中包含下面和更低的单词。

我是这样用 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]

希望这可以帮助别人!

【讨论】:

也许你也可以使用:string.partition(" low ")[2]? (注意low两边的空格【参考方案8】:

您可以使用名为substring 的包。只需使用命令pip install substring 安装即可。您只需提及开始和结束字符/索引即可获取子字符串。

例如:

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

输出:

# s = defghijklmn

【讨论】:

【参考方案9】:

试试这个通用方法:

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

#[" , i'm a beginner "]

【讨论】:

以上是关于如何在特定子字符串之后获取字符串?的主要内容,如果未能解决你的问题,请参考以下文章

在特定子字符串之后隔离字符串末尾的子字符串

匹配两个特定子字符串之一之前或之后的数字子字符串

Java:从特定字符后开始的字符串中获取子字符串

有没有办法在bash中的特定子字符串之后提取子字符串?

在特定单词之后选择子字符串

如何从字符中获取子字符串