如何提取两个标记之间的子字符串?

假设我有一个字符串'gfgfdAAA1234ZZZuijjk',我只想提取'1234'部分。

我只知道在AAA之前的几个字符是什么,在ZZZ之后的部分是我感兴趣的1234

使用sed可以对字符串执行如下操作:

echo "$STRING" | sed -e "s|.*AAA\(.*\)ZZZ.*|\1|"

这将给我1234作为结果。

如何在Python中做同样的事情?

1101442 次浏览
>>> s = 'gfgfdAAA1234ZZZuijjk'
>>> start = s.find('AAA') + 3
>>> end = s.find('ZZZ', start)
>>> s[start:end]
'1234'

然后,如果您愿意,也可以在re模块中使用regexp,但在您的情况下这不是必要的。

import re
print re.search('AAA(.*?)ZZZ', 'gfgfdAAA1234ZZZuijjk').group(1)

使用正则表达式- 文档作进一步参考

import re


text = 'gfgfdAAA1234ZZZuijjk'


m = re.search('AAA(.+?)ZZZ', text)
if m:
found = m.group(1)


# found: 1234

或者:

import re


text = 'gfgfdAAA1234ZZZuijjk'


try:
found = re.search('AAA(.+?)ZZZ', text).group(1)
except AttributeError:
# AAA, ZZZ not found in the original string
found = '' # apply your error handling


# found: 1234

你可以使用再保险模块:

>>> import re
>>> re.compile(".*AAA(.*)ZZZ.*").match("gfgfdAAA1234ZZZuijjk").groups()
('1234,)

正则表达式

import re


re.search(r"(?<=AAA).*?(?=ZZZ)", your_text).group(0)

如果your_text中没有"AAA"和"ZZZ",上述as-is将在AttributeError中失败

字符串的方法

your_text.partition("AAA")[2].partition("ZZZ")[0]

如果"AAA"或"ZZZ"在your_text中不存在,上述方法将返回空字符串。

PS Python挑战?

以防有人要做和我一样的事。我必须在一行中提取圆括号内的所有内容。例如,如果我有这样一句话,‘美国总统(巴拉克·奥巴马)会见了……,我只想得到“巴拉克·奥巴马”,这是解决方案:

regex = '.*\((.*?)\).*'
matches = re.search(regex, line)
line = matches.group(1) + '\n'

也就是说,你需要用slash \符号来阻止括号。尽管这是一个关于更多正则表达式的问题。

此外,在某些情况下,你可能会在正则表达式定义之前看到'r'符号。如果没有r前缀,则需要像c中那样使用转义字符。在这里对此有更多讨论。

>>> s = '/tmp/10508.constantstring'
>>> s.split('/tmp/')[1].split('constantstring')[0].strip('.')

使用sed,可以对字符串执行如下操作:

echo "$STRING" | sed -e "s|.*AAA\(.*\)ZZZ.*|\1|"

结果是1234。

你可以使用相同的正则表达式对re.sub函数做同样的事情。

>>> re.sub(r'.*AAA(.*)ZZZ.*', r'\1', 'gfgfdAAA1234ZZZuijjk')
'1234'

在基本sed中,捕获组由\(..\)表示,但在python中由(..)表示。

你可以在你的代码中找到这个函数的第一个子字符串(通过字符索引)。此外,还可以找到子字符串后面的内容。

def FindSubString(strText, strSubString, Offset=None):
try:
Start = strText.find(strSubString)
if Start == -1:
return -1 # Not Found
else:
if Offset == None:
Result = strText[Start+len(strSubString):]
elif Offset == 0:
return Start
else:
AfterSubString = Start+len(strSubString)
Result = strText[AfterSubString:AfterSubString + int(Offset)]
return Result
except:
return -1


# Example:


Text = "Thanks for contributing an answer to Stack Overflow!"
subText = "to"


print("Start of first substring in a text:")
start = FindSubString(Text, subText, 0)
print(start); print("")


print("Exact substring in a text:")
print(Text[start:start+len(subText)]); print("")


print("What is after substring \"%s\"?" %(subText))
print(FindSubString(Text, subText))


# Your answer:


Text = "gfgfdAAA1234ZZZuijjk"
subText1 = "AAA"
subText2 = "ZZZ"


AfterText1 = FindSubString(Text, subText1, 0) + len(subText1)
BeforText2 = FindSubString(Text, subText2, 0)


print("\nYour answer:\n%s" %(Text[AfterText1:BeforText2]))

如果没有匹配则返回其他字符串的一行。 编辑:改进版本使用next函数,如果需要,将"not-found"替换为其他函数:

import re
res = next( (m.group(1) for m in [re.search("AAA(.*?)ZZZ", "gfgfdAAA1234ZZZuijjk" ),] if m), "not-found" )

我的另一个方法来做这个,不太理想,使用regex第二次,仍然没有找到一个更短的方法:

import re
res = ( ( re.search("AAA(.*?)ZZZ", "gfgfdAAA1234ZZZuijjk") or re.search("()","") ).group(1) )

只需一行代码就可以做到

>>> import re


>>> re.findall(r'\d{1,5}','gfgfdAAA1234ZZZuijjk')


>>> ['1234']

结果将收到列表…

在python中,可以使用正则表达式(re)模块中的findall方法从字符串中提取子字符串。

>>> import re
>>> s = 'gfgfdAAA1234ZZZuijjk'
>>> ss = re.findall('AAA(.+)ZZZ', s)
>>> print ss
['1234']

令人惊讶的是,没有人提到这是我的一次性脚本的快速版本:

>>> x = 'gfgfdAAA1234ZZZuijjk'
>>> x.split('AAA')[1].split('ZZZ')[0]
'1234'

这里有一个没有regex的解决方案,它也适用于第一个子字符串包含第二个子字符串的场景。如果第二个标记在第一个标记之后,此函数将只查找子字符串。

def find_substring(string, start, end):
len_until_end_of_first_match = string.find(start) + len(start)
after_start = string[len_until_end_of_first_match:]
return string[string.find(start) + len(start):len_until_end_of_first_match + after_start.find(end)]
text = 'I want to find a string between two substrings'
left = 'find a '
right = 'between two'


print(text[text.index(left)+len(left):text.index(right)])

给了

string

另一种方法是使用列表(假设你正在寻找的子字符串是由数字组成的,只是):

string = 'gfgfdAAA1234ZZZuijjk'
numbersList = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
output = []


for char in string:
if char in numbersList: output.append(char)


print(f"output: {''.join(output)}")
### output: 1234

使用PyParsing

import pyparsing as pp


word = pp.Word(pp.alphanums)


s = 'gfgfdAAA1234ZZZuijjk'
rule = pp.nestedExpr('AAA', 'ZZZ')
for match in rule.searchString(s):
print(match)

收益率:

[['1234']]

打印稿。获取两个字符串之间的字符串。

搜索前缀和后缀之间的最短字符串

前缀-字符串/字符串数组/ null(意味着从开始搜索)。

Postfixes -字符串/字符串数组/ null(意味着搜索直到结束)。

public getStringInBetween(str: string, prefixes: string | string[] | null,
postfixes: string | string[] | null): string {


if (typeof prefixes === 'string') {
prefixes = [prefixes];
}


if (typeof postfixes === 'string') {
postfixes = [postfixes];
}


if (!str || str.length < 1) {
throw new Error(str + ' should contain ' + prefixes);
}


let start = prefixes === null ? { pos: 0, sub: '' } : this.indexOf(str, prefixes);
const end = postfixes === null ? { pos: str.length, sub: '' } : this.indexOf(str, postfixes, start.pos + start.sub.length);


let value = str.substring(start.pos + start.sub.length, end.pos);
if (!value || value.length < 1) {
throw new Error(str + ' should contain string in between ' + prefixes + ' and ' + postfixes);
}


while (true) {
try {
start = this.indexOf(value, prefixes);
} catch (e) {
break;
}
value = value.substring(start.pos + start.sub.length);
if (!value || value.length < 1) {
throw new Error(str + ' should contain string in between ' + prefixes + ' and ' + postfixes);
}
}


return value;
}

在Python 3.8中,如果text保证包含子字符串,则有一行代码:

text[text.find(start:='AAA')+len(start):text.find('ZZZ')]

此外,您可以在波纹函数中找到所有的组合

s = 'Part 1. Part 2. Part 3 then more text'
def find_all_places(text,word):
word_places = []
i=0
while True:
word_place = text.find(word,i)
i+=len(word)+word_place
if i>=len(text):
break
if word_place<0:
break
word_places.append(word_place)
return word_places
def find_all_combination(text,start,end):
start_places = find_all_places(text,start)
end_places = find_all_places(text,end)
combination_list = []
for start_place in start_places:
for end_place in end_places:
print(start_place)
print(end_place)
if start_place>=end_place:
continue
combination_list.append(text[start_place:end_place])
return combination_list
find_all_combination(s,"Part","Part")

结果:

['Part 1. ', 'Part 1. Part 2. ', 'Part 2. ']

如果你想寻找多次出现的情况。

content ="Prefix_helloworld_Suffix_stuff_Prefix_42_Suffix_andsoon"
strings = []
for c in content.split('Prefix_'):
spos = c.find('_Suffix')
if spos!=-1:
strings.append( c[:spos])
print( strings )

或者更快:

strings = [ c[:c.find('_Suffix')] for c in content.split('Prefix_') if c.find('_Suffix')!=-1 ]