从文件到Python中的另一个文件从一些字符集写入到另一个文件

问题描述:

我需要读取整个.txt文件,直到找到字符'{{'(正好连续2个字符),从现在起它应该保存所有内容到另一个.txt文件,直到遇到'}}'。诀窍是这些角色不必处于行的起点,他们可以在任何地方。所以示例文件可能看起来像这样:从文件到Python中的另一个文件从一些字符集写入到另一个文件

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()                  
+0

考虑[此输入数据]会发生什么(http://ideone.com/NW8EdE)。 – 2015-01-27 03:23:16

罗布是正确的。上述解决方案存在问题。

而且,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)Regular 表达式不支持递归语法,也就是说,如果需要解析的 语法(以及我们正在讨论的解析 问题)此处包含或扩展为包含嵌套语法 元素,则正则表达式将会没有帮助。

这是另一种基于FSM(有限状态机)的解决方案。它 可能会给错误报告更多的灵活性。但是,这是更长,更复杂的 。这种复杂性的代价是:(1) 开发时间(上面的正则表达式解决方案花了我10分钟到15分钟;我的FSM解决方案花了我几个小时);和(2) 调试(有大量的逻辑,if语句大多),因为 有很多方法可以出错。

因为它基于FSM,所以它也不能被扩展为 (没有困难)来支持处理嵌套 (递归)构造的语法。为此,您可能需要查看解析器 生成器。对于列表,请参阅本: https://wiki.python.org/moin/LanguageParsing

从积极的一面,因为下面的代码是基于一个有限状态机, 可以画出状态转换图,以澄清什么行动 代码是假设采取在任何情况下(例如,只有 看到一个左花括号,在花括号内,并只看到一个 右花括号等)。在论文中,我将该图绘制为 有向图(用于状态的圆圈,用于 转换的圆圈之间的箭头)。我不认为我能做到的ASCII艺术的这一点,所以 这里是一个状态转换图 的文本表示可能是什么样子:

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()