【问题标题】:Find string between two substrings [duplicate]在两个子字符串之间查找字符串[重复]
【发布时间】:2011-03-23 02:09:10
【问题描述】:

如何在两个子字符串之间找到一个字符串 ('123STRINGabc' -> 'STRING')?

我现在的方法是这样的:

>>> start = 'asdf=5;'
>>> end = '123jasd'
>>> s = 'asdf=5;iwantthis123jasd'
>>> print((s.split(start))[1].split(end)[0])
iwantthis

但是,这似乎非常低效且不符合 Python 风格。有什么更好的方法来做这样的事情?

忘了说: 字符串可能不以startend 开头和结尾。它们前后可能有更多字符。

【问题讨论】:

  • 您的附加信息使得几乎有必要使用正则表达式以获得最大的正确性。
  • 您自己的解决方案有什么问题?我实际上更喜欢你接受的那个。
  • 我也试图这样做,但对于多个实例,它看起来像使用 *?进行非贪婪搜索,然后用 s[s.find(end)] 切断字符串,用于跟踪多个实例

标签: string python substring


【解决方案1】:
import re

s = 'asdf=5;iwantthis123jasd'
result = re.search('asdf=5;(.*)123jasd', s)
print(result.group(1))

【讨论】:

  • @Jesse Dhillon -- @Tim McNamara 对''.join(start,test,end) in a_string 之类的建议怎么样?
  • 此方法较短,与javascript方法类似。
  • 如果我需要在 2 个子字符串之间查找并且第二个子字符串在第一个子字符串之后重复怎么办?像这样:s='asdf=5;I_WANT_ONLY_THIS123jasdNOT_THIS123jasd
  • 添加?使其不贪心result = re.search('asdf=5;(.*?)123jasd', s)
  • 如果开始/结束重复,如何修改以在开始/结束之间选择数据?例如假设我想在 i would like to send <message> to <name> 之间分别选择两个字符串并返回 result1='message' result2 = 'name'
【解决方案2】:
s = "123123STRINGabcabc"

def find_between( s, first, last ):
    try:
        start = s.index( first ) + len( first )
        end = s.index( last, start )
        return s[start:end]
    except ValueError:
        return ""

def find_between_r( s, first, last ):
    try:
        start = s.rindex( first ) + len( first )
        end = s.rindex( last, start )
        return s[start:end]
    except ValueError:
        return ""


print find_between( s, "123", "abc" )
print find_between_r( s, "123", "abc" )

给予:

123STRING
STRINGabc

我认为应该注意 - 根据您需要的行为,您可以混合使用 indexrindex 调用或使用上述版本之一(它相当于正则表达式 (.*)(.*?) 组) .

【讨论】:

  • 他说他想要一种更 Pythonic 的方式,但显然不是这样。我不确定为什么选择这个答案,即使是 OP 自己的解决方案也更好。
  • 同意。我会使用@Tim McNamara 的解决方案,或者类似start+test+end in substring 的建议
  • 对,所以它不那么 Pythonic,好吧。它也比正则表达式效率低吗?还有@Prabhu 的回答你需要投反对票,因为它提出了相同的解决方案。
  • +1,以获得更通用和可重用(通过导入)的解决方案。
  • +1 因为在多次找到end 的情况下,它比其他解决方案效果更好。但我确实同意 OP 的解决方案更简单。
【解决方案3】:
start = 'asdf=5;'
end = '123jasd'
s = 'asdf=5;iwantthis123jasd'
print s[s.find(start)+len(start):s.rfind(end)]

给予

iwantthis

【讨论】:

  • 我对此表示赞成,因为无论输入字符串大小如何,它都能正常工作。其他一些方法假设您提前知道长度。
  • 是的,它可以在没有输入大小的情况下工作,但它确实假设字符串存在
【解决方案4】:
s[len(start):-len(end)]

【讨论】:

  • 这很好,假设 start 和 end 总是在字符串的开头和结尾。否则,我可能会使用正则表达式。
  • 我对我能想到的原始问题给出了最 Pythonic 的答案。使用in 运算符进行测试可能会比正则表达式更快。
【解决方案5】:

字符串格式为 Nikolaus Gradwohl 的建议增加了一些灵活性。 startend 现在可以根据需要进行修改。

import re

s = 'asdf=5;iwantthis123jasd'
start = 'asdf=5;'
end = '123jasd'

result = re.search('%s(.*)%s' % (start, end), s).group(1)
print(result)

【讨论】:

  • 我收到了这个:'NoneType' object has no attribute 'group'
  • 这意味着没有找到匹配项。检查你的正则表达式。
  • @Dentrax 是对的:不应该返回任何错误
  • 我认为 Tim 的意思是搜索应该返回 None,因为没有匹配项。由于搜索返回 'None',最后应用 .group(1) 会导致错误。
【解决方案6】:

如果你不想导入任何东西,试试字符串方法.index()

text = 'I want to find a string between two substrings'
left = 'find a '
right = 'between two'

# Output: 'string'
print(text[text.index(left)+len(left):text.index(right)])

【讨论】:

  • 我很喜欢它。简单,单行,足够清晰,没有额外的导入并且开箱即用。我不知道上面过度设计的答案是怎么回事。
  • 这不是检查“正确”文本是否实际上在文本的右侧。如果在文本之前出现任何“正确”,它将不起作用。
  • @AndreFeijo 我同意你的观点,这是我尝试提取文本时的第一个解决方案,我想避免正则表达式奇怪的语法。但是,在您提到的情况下,我会改用正则表达式。
【解决方案7】:

只需将 OP 自己的解决方案转换为答案:

def find_between(s, start, end):
    return (s.split(start))[1].split(end)[0]

【讨论】:

  • 如果您将其他人的解决方案作为您自己的解决方案,您可能应该将其设为社区 Wiki。
【解决方案8】:
source='your token _here0@df and maybe _here1@df or maybe _here2@df'
start_sep='_'
end_sep='@df'
result=[]
tmp=source.split(start_sep)
for par in tmp:
  if end_sep in par:
    result.append(par.split(end_sep)[0])

print result

必须显示: 这里0,这里1,这里2

正则表达式更好,但它需要额外的库,您可能只想使用 python

【讨论】:

  • 这对我有用。感谢您为多次出现扩展解决方案。
  • 我正是在寻找这个,它有助于多次出现,这个帖子需要更多的支持:p。
【解决方案9】:

这是一种方法

_,_,rest = s.partition(start)
result,_,_ = rest.partition(end)
print result

使用正则表达式的另一种方式

import re
print re.findall(re.escape(start)+"(.*)"+re.escape(end),s)[0]

print re.search(re.escape(start)+"(.*)"+re.escape(end),s).group(1)

【讨论】:

    【解决方案10】:

    要提取STRING,请尝试:

    myString = '123STRINGabc'
    startString = '123'
    endString = 'abc'
    
    mySubString=myString[myString.find(startString)+len(startString):myString.find(endString)]
    

    【讨论】:

      【解决方案11】:

      您可以简单地使用此代码或复制下面的函数。整齐地排成一行。

      def substring(whole, sub1, sub2):
          return whole[whole.index(sub1) : whole.index(sub2)]
      

      如果按如下方式运行函数。

      print(substring("5+(5*2)+2", "(", "("))
      

      你可能会得到输出:

      (5*2
      

      而不是

      5*2
      

      如果您想在输出末尾添加子字符串,代码必须如下所示。

      return whole[whole.index(sub1) : whole.index(sub2) + 1]
      

      但如果您不希望最后的子字符串,+1 必须在第一个值上。

      return whole[whole.index(sub1) + 1 : whole.index(sub2)]
      

      【讨论】:

        【解决方案12】:

        这是我用来返回一个列表的函数,该列表在 string1 和 string2 之间搜索了一个字符串。

        def GetListOfSubstrings(stringSubject,string1,string2):
            MyList = []
            intstart=0
            strlength=len(stringSubject)
            continueloop = 1
        
            while(intstart < strlength and continueloop == 1):
                intindex1=stringSubject.find(string1,intstart)
                if(intindex1 != -1): #The substring was found, lets proceed
                    intindex1 = intindex1+len(string1)
                    intindex2 = stringSubject.find(string2,intindex1)
                    if(intindex2 != -1):
                        subsequence=stringSubject[intindex1:intindex2]
                        MyList.append(subsequence)
                        intstart=intindex2+len(string2)
                    else:
                        continueloop=0
                else:
                    continueloop=0
            return MyList
        
        
        #Usage Example
        mystring="s123y123o123pp123y6"
        List = GetListOfSubstrings(mystring,"1","y68")
        for x in range(0, len(List)):
                       print(List[x])
        output:
        
        
        mystring="s123y123o123pp123y6"
        List = GetListOfSubstrings(mystring,"1","3")
        for x in range(0, len(List)):
                      print(List[x])
        output:
            2
            2
            2
            2
        
        mystring="s123y123o123pp123y6"
        List = GetListOfSubstrings(mystring,"1","y")
        for x in range(0, len(List)):
                       print(List[x])
        output:
        23
        23o123pp123
        

        【讨论】:

        • 非常好的和有用的答案。谢谢!
        • 非凡的答案。我会雇用像你这样的人
        【解决方案13】:

        这些解决方案假定起始字符串和最终字符串不同。这是我在初始指标和最终指标相同时用于整个文件的解决方案,假设使用 readlines() 读取整个文件:

        def extractstring(line,flag='$'):
            if flag in line: # $ is the flag
                dex1=line.index(flag)
                subline=line[dex1+1:-1] #leave out flag (+1) to end of line
                dex2=subline.index(flag)
                string=subline[0:dex2].strip() #does not include last flag, strip whitespace
            return(string)
        

        例子:

        lines=['asdf 1qr3 qtqay 45q at $A NEWT?$ asdfa afeasd',
            'afafoaltat $I GOT BETTER!$ derpity derp derp']
        for line in lines:
            string=extractstring(line,flag='$')
            print(string)
        

        给予:

        A NEWT?
        I GOT BETTER!
        

        【讨论】:

          【解决方案14】:

          这基本上是 cji 的回答 - 2010 年 7 月 30 日 5:58。 我更改了 try except 结构,以便更清楚地了解导致异常的原因。

          def find_between( inputStr, firstSubstr, lastSubstr ):
          '''
          find between firstSubstr and lastSubstr in inputStr  STARTING FROM THE LEFT
              http://stackoverflow.com/questions/3368969/find-string-between-two-substrings
                  above also has a func that does this FROM THE RIGHT   
          '''
          start, end = (-1,-1)
          try:
              start = inputStr.index( firstSubstr ) + len( firstSubstr )
          except ValueError:
              print '    ValueError: ',
              print "firstSubstr=%s  -  "%( firstSubstr ), 
              print sys.exc_info()[1]
          
          try:
              end = inputStr.index( lastSubstr, start )       
          except ValueError:
              print '    ValueError: ',
              print "lastSubstr=%s  -  "%( lastSubstr ), 
              print sys.exc_info()[1]
          
          return inputStr[start:end]    
          

          【讨论】:

            【解决方案15】:

            我的方法是做类似的事情,

            find index of start string in s => i
            find index of end string in s => j
            
            substring = substring(i+len(start) to j-1)
            

            【讨论】:

              【解决方案16】:

              这是我之前发布的code snippet in Daniweb

              # picking up piece of string between separators
              # function using partition, like partition, but drops the separators
              def between(left,right,s):
                  before,_,a = s.partition(left)
                  a,_,after = a.partition(right)
                  return before,a,after
              
              s = "bla bla blaa <a>data</a> lsdjfasdjöf (important notice) 'Daniweb forum' tcha tcha tchaa"
              print between('<a>','</a>',s)
              print between('(',')',s)
              print between("'","'",s)
              
              """ Output:
              ('bla bla blaa ', 'data', " lsdjfasdj\xc3\xb6f (important notice) 'Daniweb forum' tcha tcha tchaa")
              ('bla bla blaa <a>data</a> lsdjfasdj\xc3\xb6f ', 'important notice', " 'Daniweb forum' tcha tcha tchaa")
              ('bla bla blaa <a>data</a> lsdjfasdj\xc3\xb6f (important notice) ', 'Daniweb forum', ' tcha tcha tchaa')
              """
              

              【讨论】:

                【解决方案17】:
                from timeit import timeit
                from re import search, DOTALL
                
                
                def partition_find(string, start, end):
                    return string.partition(start)[2].rpartition(end)[0]
                
                
                def re_find(string, start, end):
                    # applying re.escape to start and end would be safer
                    return search(start + '(.*)' + end, string, DOTALL).group(1)
                
                
                def index_find(string, start, end):
                    return string[string.find(start) + len(start):string.rfind(end)]
                
                
                # The wikitext of "Alan Turing law" article form English Wikipeida
                # https://en.wikipedia.org/w/index.php?title=Alan_Turing_law&action=edit&oldid=763725886
                string = """..."""
                start = '==Proposals=='
                end = '==Rival bills=='
                
                assert index_find(string, start, end) \
                       == partition_find(string, start, end) \
                       == re_find(string, start, end)
                
                print('index_find', timeit(
                    'index_find(string, start, end)',
                    globals=globals(),
                    number=100_000,
                ))
                
                print('partition_find', timeit(
                    'partition_find(string, start, end)',
                    globals=globals(),
                    number=100_000,
                ))
                
                print('re_find', timeit(
                    're_find(string, start, end)',
                    globals=globals(),
                    number=100_000,
                ))
                

                结果:

                index_find 0.35047444528454114
                partition_find 0.5327825636197754
                re_find 7.552149639286381
                

                在此示例中,re_findindex_find 慢了近 20 倍。

                【讨论】:

                  【解决方案18】:

                  使用来自不同电子邮件平台的分隔符解析文本提出了这个问题的更大版本。他们通常有一个开始和一个停止。通配符的分隔符一直阻塞正则表达式。此处和其他地方都提到了拆分的问题 - 哎呀,分隔符消失了。我想到使用 replace() 给 split() 其他东西来消费。代码块:

                  nuke = '~~~'
                  start = '|*'
                  stop = '*|'
                  julien = (textIn.replace(start,nuke + start).replace(stop,stop + nuke).split(nuke))
                  keep = [chunk for chunk in julien if start in chunk and stop in chunk]
                  logging.info('keep: %s',keep)
                  

                  【讨论】:

                    【解决方案19】:

                    从 Nikolaus Gradwohl 的进一步回答中,我需要从下面的文件内容(文件名: docker-compose.yml):

                        version: '3.1'
                    services:
                      ui:
                        image: repo-pkg.dev.io:21/website/ui:0.0.2-QA1
                        #network_mode: host
                        ports:
                          - 443:9999
                        ulimits:
                          nofile:test
                    

                    这就是它对我的工作方式(python 脚本):

                    import re, sys
                    
                    f = open('docker-compose.yml', 'r')
                    lines = f.read()
                    result = re.search('ui:(.*)-', lines)
                    print result.group(1)
                    
                    
                    Result:
                    0.0.2
                    

                    【讨论】:

                    • 将 Docker 用于简单任务是不好的做法。
                    • @DmitryBubnenkov 上面的帖子与 Docker 使用/实现有什么关系?这就是在文件中的两个子字符串之间找到一个字符串。
                    【解决方案20】:

                    这对我来说似乎更直接:

                    import re
                    
                    s = 'asdf=5;iwantthis123jasd'
                    x= re.search('iwantthis',s)
                    print(s[x.start():x.end()])
                    

                    【讨论】:

                    • 这需要你知道你正在寻找的字符串,它没有找到两个子字符串之间的任何字符串,正如 OP 所要求的那样。 OP希望无论它是什么都能够获得中间值,而这个答案需要您在开始之前了解中间值。
                    猜你喜欢
                    • 2020-05-28
                    • 2017-07-07
                    • 2014-12-07
                    • 1970-01-01
                    • 2013-09-13
                    相关资源
                    最近更新 更多