Python 提取2个特定标记之间的行
对于一个常规编程问题,我需要提取两个标记之间的一些文本行(分隔符,如果需要更具体的话) 文件如下所示:Python 提取2个特定标记之间的行,python,regex,Python,Regex,对于一个常规编程问题,我需要提取两个标记之间的一些文本行(分隔符,如果需要更具体的话) 文件如下所示: *some random text* ... ... ... tag/delimiter 1 text 1 #extract text 2 #extract ... #extract ... #extract text n #extract tag/ending_delimiter *some random text* ... ...
*some random text*
...
...
...
tag/delimiter 1
text 1 #extract
text 2 #extract
... #extract
... #extract
text n #extract
tag/ending_delimiter
*some random text*
...
...
...
tag/delimiter 2
text 1 #extract
text 2 #extract
... #extract
... #extract
text n #extract
tag/ending_delimiter
*some random text*
...
...
...
tag/delimiter n
text 1 #extract
text 2 #extract
... #extract
... #extract
text n #extract
tag/ending_delimiter
*some random text until the file ends*
结尾分隔符在任何地方都是相同的
起始分隔符,即分隔符1、分隔符2到n取自列表
问题是,在文件中,每个起始分隔符后面都有几个(少于3个)字符,这些字符与起始分隔符结合起来,作为文本行的标识符,直到结束分隔符(从技术上讲是一种“uid”)为止
到目前为止,我尝试的是:
data_file = open("file_name")
block = []
found = False
for elem in list_of_starting_delimiters:
for line in data_file:
if found:
block.append(line)
if re.match(attribute_end, line.strip()):
break
else:
if re.match(elem, line.strip()):
found = True
block = elem
data_file.close()
我还尝试实施以下建议的答案:
但是没有成功
我目前正在尝试的实现就是上面链接的答案之一
感谢您的帮助
注:在PyCharm和Windows 10上使用Python2.7。我会用以下方式来实现:例如,让
和
和
作为我们的起始分隔符,让
结束delimeter和字符串作为您正在处理的文本。然后是以下代码行:
re.findall('(| |)(.+?)()',string,re.DOTALL)
将给出元组列表,每个元组包含起始分隔符、正文和结束分隔符。此代码在正则表达式(括号)内使用分组,正则表达式中的管道(|)的行为类似于或,点(.)与点所有标志组合匹配任何字符,加(+)表示1或多个,问题(?)以非贪婪方式(在这种情况下,这一点很重要,否则您将获得从第一个起始分隔符开始到最后一个结束分隔符结束的单个匹配)如何
import re
with open(file, 'r') as f:
txt = f.read()
losd = '|'.join(list_of_starting_delimiters)
enddel = 'attribute_end'
block = re.findall('(?:' + losd + r')([\s\S]*?)' + enddel, txt)
我建议用以下方法修复代码:
block = []
found = False
list_of_starting_delimiters = ['tag/delimiter']
attribute_end = 'tag/ending_delimiter'
curr = []
for elem in list_of_starting_delimiters:
for line in data_file:
if found:
curr.append(line)
if line.strip().startswith(attribute_end):
found = False
block.append("\n".join(curr)) # Add merged list to final list
curr = [] # Zero out current list
else:
if line.strip().startswith(elem): # If line starts with start delimiter
found = True
curr.append(line.strip()) # Append line to current list
if len(curr) > 0: # If there are still lines in the current list
block.append(curr) # Add them to the final list
见
您当前的代码有很多问题:
block=elem
生成block
一个字节字符串,进一步的.append
导致异常
- 您只抓取了块的一个匹配项,因为在完成一个匹配项时,您有一个
break
语句
- 所有行都作为单独的项添加,而您需要将它们收集到列表中,然后使用
\n
将它们连接起来,以获得要粘贴到结果列表中的字符串
- 无需正则表达式即可检查字符串是否出现在字符串开头,请使用
str.startswith
方法
当我意识到这一点时,已经有相当数量的良好响应,但我的方法是,您可以通过以下方式解决此问题:
import re
pattern = re.compile(r"(^tag\/delimiter) (.{0,3})\n\n((^[\w\d #\.]*$\n)+)^(tag\/ending_delimiter)", re.M)
然后,您可以通过执行以下任一操作来查找文本中的所有匹配项:
for i in pattern.finditer(<target_text>):
#do something with each match
pattern.findAll(<target_text>) - returns a list of strings of all matches
模式中的i的。finditer():
#对每一场比赛都做些什么
pattern.findAll()-返回所有匹配字符串的列表
这当然有一条规定,即您需要指定不同的分隔符,并使用@SpghttCd在其答案中所示的变量和字符串连接,为每个不同的分隔符编译不同的正则表达式模式(re.compile)
有关更多信息,请参见pythonMyre
——较少的解决方案如下:
list_of_starting_delimiters = ['tag/delimiter 1', 'tag/delimiter 2', 'tag/delimiter n']
enddel = 'tag/ending_delimiter'
block ={}
section = ''
with open(file, 'r') as f:
for line in f:
if line.strip() == enddel:
section = ''
if section:
block[section] = block.get(section, '') + line
if line.strip() in list_of_starting_delimiters:
section = line.strip()
print(block)
它将块提取到字典中,起始分隔符标记作为键,相应部分作为值。
它要求开始和结束标记是其各自行的唯一内容
输出:
{'tag/delimiter 1':
'\ntext 1 #extract\n\ntext 2 #extract\n\n... #extract\n\n... #extract\n\ntext n #extract\n\n',
'tag/delimiter 2':
'\ntext 1 #extract\n\ntext 2 #extract\n\n... #extract\n\n... #extract\n\ntext n #extract\n\n',
'tag/delimiter n':
'\ntext 1 #extract\n\ntext 2 #extract\n\n... #extract\n\n... #extract\n\ntext n #extract\n\n'}
注意re.match
仅在字符串开头匹配。你的意思是吗?如果不是,请使用re.search
。我确实不太了解如何使用正则表达式,但我会尝试re.search
并返回给你。编辑:我确实使用了re.search
而不是re.match
,但得到了一个空列表,与使用re.mat时一样ch
。什么是lncel\u dns
和attribute\u end
?下面的答案都意味着您需要将整个文件读入内存。从我的观点来看,此解决方案的一个缺点是,对于n个节提取,它会在整个文件上迭代n次。@SpghttCd如果分隔符重叠,它仍然是最有效的lution.Regex类似于(?=(…)
,如果文件太大,那就太过分了。我不再谈论Regex(请参阅下面我的最新答案,它只在文件中重复一次)。此外,我不明白你所说的重叠分隔符是什么意思