【问题标题】: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")

【问题讨论】:

    标签: python string substring


    【解决方案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'
    

    【讨论】:

      【解决方案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 "]
        

        【讨论】:

          猜你喜欢
          • 2014-10-03
          • 1970-01-01
          • 2022-11-10
          • 1970-01-01
          • 1970-01-01
          • 2022-08-10
          • 1970-01-01
          相关资源
          最近更新 更多