在 Python 中从文件写入另一个文件,从某组字符写入另一组字符
Writing from file to another file in Python from certain set of characters to another one
我需要读取整个 .txt 文件,直到它找到字符“{{”(正好连续 2 个),从现在开始,它应该将所有内容保存到另一个 .txt 文件,直到它遇到“}}”。诀窍是这些字符不必位于行首,它们可以在任何地方。因此示例文件可能如下所示:
blablabla {{zzzzz
zzzzzz
zzzz
zzz
zz
}}blabla
它应该得到所有 'z'。在 python 2 中最简单的方法是什么?我发现了类似的问题,但对我的情况没有任何帮助。
我会使用正则表达式,re.findall()
:
with open('/tmp/in') as input_file:
with open('/tmp/out', 'w') as output_file:
input = input_file.read()
output_file.write(''.join(re.findall(r'(?s)(?<={{).*?(?=}})', input)))
分解:
with
行打开相关数据文件。你可能已经有了这个。
input_file.read()
创建一个包含文件内容的字符串。
- 对
re.findall()
的调用搜索:
{{
,但将其从结果中排除 ((?<={{)
)。
- 可能的最短 (
(?s)
) 匹配直到 }}
(.*?
)
}}
,但将其从结果中排除 ((?=}})
)
- 调用
''.join()
将所有字符串粘贴在一起。
- 对
output_file.write()
的调用将结果存储到输出文件中。
或者考虑使用类似下面的东西:
import sys
def save_lines(infile, outfile):
save = False
for line in infile:
if save:
pos = line.find('}}')
if pos > -1:
outfile.write(line[:pos] + '\n')
save = False
else:
outfile.write(line)
else:
pos = line.find('{{')
if pos > -1:
outfile.write('-----\n')
save = True
outfile.write(line[pos + 2:])
else:
pass
def test():
infile = open('tmp01.txt', 'r')
save_lines(infile, sys.stdout)
infile.close()
if __name__ == '__main__':
test()
Rob 是对的。上述方案有问题
并且,上面 Rob 给出的基于正则表达式的解决方案
我觉得不错。
这是一个变体:
def save_lines(infile, outfile):
bracket_pattern = re.compile(r'{{(.*?)}}', re.DOTALL)
content = infile.read()
for mo in bracket_pattern.finditer(content):
outchars = mo.group(1)
outfile.write('matched: "{}" at position {}\n'.format(
outchars, mo.start()))
但是,根据您的需要,您可能还需要考虑
以下:(1)基于正则表达式的方法提供了非常
语法错误检查的灵活性很小。 (2) 普通
表达式不支持递归文法,也就是说,如果
你需要解析的语法(我们正在谈论一个解析
问题)这里包含或扩展为包含嵌套句法
元素,正则表达式将无济于事。
这是另一种基于 FSM(有限状态机)的解决方案。它
可能会为错误报告提供更多的灵活性。但它是
更长,更复杂。这种复杂性是有代价的:(1)
开发时间(上面的正则表达式解决方案花了我
10~15分钟;这个 FSM 解决方案花了我几个小时);和 (2)
调试(有很多逻辑,主要是 if 语句)因为那里
有很多方法可能出错。
因为是基于FSM的,所以也无法扩展
(没有困难)支持处理嵌套的语法
(递归)构造。为此你可能想看看解析器
发电机。请参阅此列表:
https://wiki.python.org/moin/LanguageParsing
从积极的方面来说,因为下面的代码是基于 FSM,
你可以画一个状态转换图来阐明什么动作
代码假设在任何给定情况下(例如,只是
看到一个左大括号,在大括号内,刚刚看到一个
右花括号等)。在纸上,我把那个图画成
有向图(圆圈表示状态,圆圈之间的箭头表示
过渡)。我不认为我可以为此做 ascii-art,所以
这是状态转换图的文本表示
可能看起来像:
start:
[any] --> outside
outside:
"{" --> seen_left
[any] --> outside
seen_left:
"{" --> inside
[any] --> outside
inside:
"}" --> seen_right
[any] --> inside
[etc]
而且,这是代码:
#!/usr/bin/env python
"""
Synopsis:
Search for and write out text content occuring between '{{' and '}}'.
Usage:
python capture.py <infilename>
Args:
1. Input file name
Options:
None
Example:
python capture.py some_file.txt
"""
import sys
(
ST_start,
ST_seen_left_bracket,
ST_inside_brackets,
ST_seen_right_bracket,
ST_outside_brackets,
ST_end,
) = range(1, 7)
Left_bracket = '{'
Right_bracket = '}'
class ReaderWriter(object):
def __init__(self, infile, outfile):
self.infile = infile
self.outfile = outfile
self.line = ''
self.pos = 0
self.inchar = None
self.prevchar = None
self.char_count = 0
def get_char(self):
if self.pos >= len(self.line):
self.line = self.infile.readline()
if not self.line:
return None
self.pos = 0
self.prevchar = self.inchar
inchar = self.line[self.pos]
self.inchar = inchar
self.pos += 1
self.char_count += 1
return inchar
def write(self, outchars):
#self.outfile.write('found: "{}"\n'.format(outchar))
self.outfile.write(outchars)
def write_prev_char(self):
#self.outfile.write('found: "{}"\n'.format(self.prevchar))
self.outfile.write(self.prevchar)
def save_lines(infile, outfile):
state = ST_start
while True:
if state == ST_start:
reader_writer = ReaderWriter(infile, outfile)
inchar = reader_writer.get_char()
state = ST_outside_brackets
elif state == ST_outside_brackets:
if inchar == Left_bracket:
inchar = reader_writer.get_char()
state = ST_seen_left_bracket if inchar is not None else ST_end
else:
inchar = reader_writer.get_char()
state = ST_outside_brackets if inchar is not None else ST_end
elif state == ST_seen_left_bracket:
if inchar == Left_bracket:
reader_writer.write('found (pos {:d}): "'.format(
reader_writer.char_count))
inchar = reader_writer.get_char()
state = ST_inside_brackets if inchar is not None else ST_end
else:
inchar = reader_writer.get_char()
state = ST_outside_brackets if inchar is not None else ST_end
elif state == ST_inside_brackets:
if inchar == Right_bracket:
inchar = reader_writer.get_char()
state = ST_seen_right_bracket if inchar is not None else ST_end
else:
reader_writer.write(inchar)
inchar = reader_writer.get_char()
state = ST_inside_brackets if inchar is not None else ST_end
elif state == ST_seen_right_bracket:
if inchar == Right_bracket:
reader_writer.write('"\n')
inchar = reader_writer.get_char()
state = ST_outside_brackets if inchar is not None else ST_end
else:
reader_writer.write_prev_char()
reader_writer.write(inchar)
inchar = reader_writer.get_char()
state = ST_inside_brackets if inchar is not None else ST_end
elif state == ST_end:
return
else:
pass
def main():
args = sys.argv[1:]
if len(args) != 1:
sys.exit(__doc__)
if args[0] == '-h' or args[0] == '--help':
print __doc__
sys.exit()
infilename = args[0]
infile = open(infilename, 'r')
save_lines(infile, sys.stdout)
infile.close()
if __name__ == '__main__':
#import ipdb
#ipdb.set_trace()
main()
我需要读取整个 .txt 文件,直到它找到字符“{{”(正好连续 2 个),从现在开始,它应该将所有内容保存到另一个 .txt 文件,直到它遇到“}}”。诀窍是这些字符不必位于行首,它们可以在任何地方。因此示例文件可能如下所示:
blablabla {{zzzzz
zzzzzz
zzzz
zzz
zz
}}blabla
它应该得到所有 'z'。在 python 2 中最简单的方法是什么?我发现了类似的问题,但对我的情况没有任何帮助。
我会使用正则表达式,re.findall()
:
with open('/tmp/in') as input_file:
with open('/tmp/out', 'w') as output_file:
input = input_file.read()
output_file.write(''.join(re.findall(r'(?s)(?<={{).*?(?=}})', input)))
分解:
with
行打开相关数据文件。你可能已经有了这个。input_file.read()
创建一个包含文件内容的字符串。- 对
re.findall()
的调用搜索:{{
,但将其从结果中排除 ((?<={{)
)。- 可能的最短 (
(?s)
) 匹配直到}}
(.*?
) }}
,但将其从结果中排除 ((?=}})
)
- 调用
''.join()
将所有字符串粘贴在一起。 - 对
output_file.write()
的调用将结果存储到输出文件中。
或者考虑使用类似下面的东西:
import sys
def save_lines(infile, outfile):
save = False
for line in infile:
if save:
pos = line.find('}}')
if pos > -1:
outfile.write(line[:pos] + '\n')
save = False
else:
outfile.write(line)
else:
pos = line.find('{{')
if pos > -1:
outfile.write('-----\n')
save = True
outfile.write(line[pos + 2:])
else:
pass
def test():
infile = open('tmp01.txt', 'r')
save_lines(infile, sys.stdout)
infile.close()
if __name__ == '__main__':
test()
Rob 是对的。上述方案有问题
并且,上面 Rob 给出的基于正则表达式的解决方案 我觉得不错。
这是一个变体:
def save_lines(infile, outfile):
bracket_pattern = re.compile(r'{{(.*?)}}', re.DOTALL)
content = infile.read()
for mo in bracket_pattern.finditer(content):
outchars = mo.group(1)
outfile.write('matched: "{}" at position {}\n'.format(
outchars, mo.start()))
但是,根据您的需要,您可能还需要考虑 以下:(1)基于正则表达式的方法提供了非常 语法错误检查的灵活性很小。 (2) 普通 表达式不支持递归文法,也就是说,如果 你需要解析的语法(我们正在谈论一个解析 问题)这里包含或扩展为包含嵌套句法 元素,正则表达式将无济于事。
这是另一种基于 FSM(有限状态机)的解决方案。它 可能会为错误报告提供更多的灵活性。但它是 更长,更复杂。这种复杂性是有代价的:(1) 开发时间(上面的正则表达式解决方案花了我 10~15分钟;这个 FSM 解决方案花了我几个小时);和 (2) 调试(有很多逻辑,主要是 if 语句)因为那里 有很多方法可能出错。
因为是基于FSM的,所以也无法扩展 (没有困难)支持处理嵌套的语法 (递归)构造。为此你可能想看看解析器 发电机。请参阅此列表: https://wiki.python.org/moin/LanguageParsing
从积极的方面来说,因为下面的代码是基于 FSM, 你可以画一个状态转换图来阐明什么动作 代码假设在任何给定情况下(例如,只是 看到一个左大括号,在大括号内,刚刚看到一个 右花括号等)。在纸上,我把那个图画成 有向图(圆圈表示状态,圆圈之间的箭头表示 过渡)。我不认为我可以为此做 ascii-art,所以 这是状态转换图的文本表示 可能看起来像:
start:
[any] --> outside
outside:
"{" --> seen_left
[any] --> outside
seen_left:
"{" --> inside
[any] --> outside
inside:
"}" --> seen_right
[any] --> inside
[etc]
而且,这是代码:
#!/usr/bin/env python
"""
Synopsis:
Search for and write out text content occuring between '{{' and '}}'.
Usage:
python capture.py <infilename>
Args:
1. Input file name
Options:
None
Example:
python capture.py some_file.txt
"""
import sys
(
ST_start,
ST_seen_left_bracket,
ST_inside_brackets,
ST_seen_right_bracket,
ST_outside_brackets,
ST_end,
) = range(1, 7)
Left_bracket = '{'
Right_bracket = '}'
class ReaderWriter(object):
def __init__(self, infile, outfile):
self.infile = infile
self.outfile = outfile
self.line = ''
self.pos = 0
self.inchar = None
self.prevchar = None
self.char_count = 0
def get_char(self):
if self.pos >= len(self.line):
self.line = self.infile.readline()
if not self.line:
return None
self.pos = 0
self.prevchar = self.inchar
inchar = self.line[self.pos]
self.inchar = inchar
self.pos += 1
self.char_count += 1
return inchar
def write(self, outchars):
#self.outfile.write('found: "{}"\n'.format(outchar))
self.outfile.write(outchars)
def write_prev_char(self):
#self.outfile.write('found: "{}"\n'.format(self.prevchar))
self.outfile.write(self.prevchar)
def save_lines(infile, outfile):
state = ST_start
while True:
if state == ST_start:
reader_writer = ReaderWriter(infile, outfile)
inchar = reader_writer.get_char()
state = ST_outside_brackets
elif state == ST_outside_brackets:
if inchar == Left_bracket:
inchar = reader_writer.get_char()
state = ST_seen_left_bracket if inchar is not None else ST_end
else:
inchar = reader_writer.get_char()
state = ST_outside_brackets if inchar is not None else ST_end
elif state == ST_seen_left_bracket:
if inchar == Left_bracket:
reader_writer.write('found (pos {:d}): "'.format(
reader_writer.char_count))
inchar = reader_writer.get_char()
state = ST_inside_brackets if inchar is not None else ST_end
else:
inchar = reader_writer.get_char()
state = ST_outside_brackets if inchar is not None else ST_end
elif state == ST_inside_brackets:
if inchar == Right_bracket:
inchar = reader_writer.get_char()
state = ST_seen_right_bracket if inchar is not None else ST_end
else:
reader_writer.write(inchar)
inchar = reader_writer.get_char()
state = ST_inside_brackets if inchar is not None else ST_end
elif state == ST_seen_right_bracket:
if inchar == Right_bracket:
reader_writer.write('"\n')
inchar = reader_writer.get_char()
state = ST_outside_brackets if inchar is not None else ST_end
else:
reader_writer.write_prev_char()
reader_writer.write(inchar)
inchar = reader_writer.get_char()
state = ST_inside_brackets if inchar is not None else ST_end
elif state == ST_end:
return
else:
pass
def main():
args = sys.argv[1:]
if len(args) != 1:
sys.exit(__doc__)
if args[0] == '-h' or args[0] == '--help':
print __doc__
sys.exit()
infilename = args[0]
infile = open(infilename, 'r')
save_lines(infile, sys.stdout)
infile.close()
if __name__ == '__main__':
#import ipdb
#ipdb.set_trace()
main()