对于一个常规的编程问题,我需要提取2个标签(如果需要更具体,请使用定界符)之间的一些文本行。
文件如下:
*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*
Ending_delimiter到处都是一样的。
起始定界符,即定界符1,直到n的定界符2均来自列表。
捕获的是,在文件中,每个起始定界符后面都有几个(少于3个)字符,这些字符与起始定界符结合在一起,用作文本行的标识符,直到ending_delimiter,这是一种“ 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()
我还尝试实现以下建议的答案:
python - Read file from and to specific lines of text
但没有成功。
我当前正在尝试的实现是上面链接的答案之一。
感谢您的帮助。
P.S:在Windows 10上的PyCharm上使用Python 2.7。
答案 0 :(得分: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)
答案 1 :(得分:1)
我建议通过以下方式修复您的代码:
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
请参见Python demo
您当前的代码存在很多问题:
block = elem
将block
设为字节字符串,而另外的.append
导致了异常break
语句\n
合并以将字符串粘贴到结果列表中str.startswith
方法。答案 2 :(得分:1)
到我发现这个问题时,已经有了很多好的答复,但是我的方法是,您可以使用以下方法解决此问题:
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
这当然带有规定,您需要指定不同的定界符并为每个不同的定界符编译不同的正则表达式模式(re.compile),如@SpghttCd在其答案中所示,使用变量和字符串连接
有关更多信息,请参见python re module
答案 3 :(得分:0)
我将通过以下方式做到这一点:例如,让<d1>
和<d2>
和<d3>
成为我们的开始定界符,<d>
结束定界符和string
是您正在处理的文本。然后执行以下代码:
re.findall('(<d1>|<d2>|<d3>)(.+?)(<d>)',string,re.DOTALL)
将给出元组列表,每个元组包含开始定界符,主体和结束定界符。此代码使用正则表达式(方括号)内的分组,正则表达式中的竖线(|)的行为类似于或,点(。)与DOTALL标志结合使用可匹配任何字符,加号(+)表示1个或多个,问题(?)非-贪婪的方式(在这种情况下这很重要,否则您将获得从第一个开始的定界符开始到最后一个结束定界符结束的单个匹配)
答案 4 :(得分:0)
我的re
-less解决方案如下:
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'}