Comment trouver une chaîne entre deux sous-chaînes ('123STRINGabc' -> 'STRING'
)?
Ma méthode actuelle est la suivante:
>>> start = 'asdf=5;'
>>> end = '123jasd'
>>> s = 'asdf=5;iwantthis123jasd'
>>> print((s.split(start))[1].split(end)[0])
iwantthis
Cependant, cela semble très inefficace et non pythonique. Quelle est la meilleure façon de faire quelque chose comme ça?
Oubli de mentionner: la chaîne peut ne pas commencer et se terminer par start
et end
. Ils peuvent avoir plus de caractères avant et après.
import re
s = 'asdf=5;iwantthis123jasd'
result = re.search('asdf=5;(.*)123jasd', s)
print(result.group(1))
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" )
donne:
123STRING
STRINGabc
Je pensais que cela devrait être noté - selon le comportement dont vous avez besoin, vous pouvez mélanger les appels index
et rindex
ou utiliser l'une des versions ci-dessus (c'est l'équivalent de regex (.*)
et (.*?)
groupes).
start = 'asdf=5;'
end = '123jasd'
s = 'asdf=5;iwantthis123jasd'
print s[s.find(start)+len(start):s.rfind(end)]
donne
iwantthis
s[len(start):-len(end)]
Le formatage des chaînes ajoute une certaine flexibilité à ce que Nikolaus Gradwohl a suggéré. start
et end
peuvent maintenant être modifiés à volonté.
import re
s = 'asdf=5;iwantthis123jasd'
start = 'asdf=5;'
end = '123jasd'
result = re.search('%s(.*)%s' % (start, end), s).group(1)
print(result)
Convertir simplement la solution du PO en réponse:
def find_between(s, start, end):
return (s.split(start))[1].split(end)[0]
Voici une façon de le faire
_,_,rest = s.partition(start)
result,_,_ = rest.partition(end)
print result
Une autre façon en utilisant regexp
import re
print re.findall(re.escape(start)+"(.*)"+re.escape(end),s)[0]
ou
print re.search(re.escape(start)+"(.*)"+re.escape(end),s).group(1)
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
doit montrer: here0, here1, here2
la regex est meilleure mais cela nécessitera une bibliothèque supplémentaire et vous voudrez peut-être utiliser uniquement python
Si vous ne souhaitez rien importer, essayez la méthode de chaîne .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)]
Pour extraire STRING
, essayez:
myString = '123STRINGabc'
startString = '123'
endString = 'abc'
mySubString=myString[myString.find(startString)+len(startString):myString.find(endString)]
Voici une fonction que j'ai créée pour renvoyer une liste contenant une ou plusieurs chaînes entre chaîne1 et chaîne2.
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
Vous pouvez simplement utiliser ce code ou copier la fonction ci-dessous. Tous parfaitement en une seule ligne.
def substring(whole, sub1, sub2):
return whole[whole.index(sub1) : whole.index(sub2)]
Si vous exécutez la fonction comme suit.
print(substring("5+(5*2)+2", "(", "("))
Vous allez probablement rester avec la sortie:
(5*2
plutôt que
5*2
Si vous voulez avoir les sous-chaînes à la fin de la sortie, le code doit ressembler à celui ci-dessous.
return whole[whole.index(sub1) : whole.index(sub2) + 1]
Mais si vous ne voulez pas les sous-chaînes à la fin, le +1 doit être sur la première valeur.
return whole[whole.index(sub1) + 1 : whole.index(sub2)]
Ma méthode sera de faire quelque chose comme,
find index of start string in s => i
find index of end string in s => j
substring = substring(i+len(start) to j-1)
Ces solutions supposent que la chaîne de départ et la chaîne finale sont différentes. Voici une solution que j'utilise pour un fichier entier lorsque les indicateurs initial et final sont identiques, en supposant que le fichier entier soit lu à l'aide de 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)
Exemple:
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)
Donne:
A NEWT?
I GOT BETTER!
Ceci est essentiellement la réponse de cji - 30 juillet 10 à 5:58. J'ai changé la structure try except pour un peu plus de clarté sur la cause de l'exception.
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]
L'analyse du texte avec des délimiteurs de différentes plates-formes de messagerie a posé une version plus grande de ce problème. Ils ont généralement un START et un STOP. Les caractères séparateurs pour les caractères génériques ont continué à étouffer les expressions rationnelles. Le problème de la scission est mentionné ici et ailleurs - oups, le caractère de délimiteur est parti. Il m'est arrivé d'utiliser replace () pour donner à split () quelque chose d'autre à consommer. Morceau de code:
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)
J'ai déjà posté ceci en tant que extrait de code dans 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')
"""
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,
))
Résultat:
index_find 0.35047444528454114
partition_find 0.5327825636197754
re_find 7.552149639286381
re_find
était presque 20 fois plus lent que index_find
dans cet exemple.
Plus loin de la réponse de Nikolaus Gradwohl, je devais obtenir le numéro de version (c'est-à-dire .0.2) entre ('ui:' et '-') du contenu du fichier ci-dessous (nom du fichier: 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
et voici comment cela a fonctionné pour moi (script 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