2015-09-07 33 views
3

的我试图从像输入捕获数据:正则表达式捕获不同类型的模式

... 
10 79 QUANT. DE ITENS A FORNECER  O N  9 0 67 75 
      E' a quantidade de itens que o fornecedor consegue suprir 
      o cliente para uma determinada data. As casa decimais estao 
      definidas no campo 022 (unid. casas decimais).    

11 24 DATA ENTREGA/EMBARQUE DO ITEM O N  6 0 76 81 
      Data de entrega/embarque do item. Nos casos em que este cam- 
      po nao contiver a data, seu conteudo devera ser ajustado en- 
      tre as partes. 
... 

我的目标是捕获: (“10”,“79”,“QUANT DE ITENS一个FORNECER ','O','N','9','0','67',75')等等...

我的第一次尝试是循环过去并捕获如下:

def parse_line(line): 
    pattern = r"\s(\d{1,6}|\w{1})\s" # do not capture the description 
    if re.search(pattern, line): 
     tab_find = re.findall(pattern, line, re.DOTALL|re.UNICODE) 
     if len(tab_find) > 6: 
      return tab_find 

我的第二次尝试是拆分文本并追加预期结果:

def ugly_parsing(line): 
    result = [None] * 9 # init list 
    tab_r = list(filter(None, re.split(r"\s", line))) # ignore '' 
    keys = [0, 1, -1, -2, -3, -4, -5, -6] 
    for i in keys: 
     result[i] = tab_r[i] 
    result[2] = " ".join(tab_r[2:-6]) 
    return result 

忽略描述是好的,但是当描述包含单个字母时,我的正则表达式不起作用。

+3

为什么不在一个以上的空间分割,即'r'\ s {2,}''?或者他们是制表符? – jonrsharpe

+0

请确定你需要什么输出。目前还不清楚(*等)*。 –

+0

@jonrsharpe,不错的选择! –

回答

2

只需将该行转换为正则表达式,并带有所有必需的数字和字符,并给出描述中所剩的任何内容。您可以使用非贪婪匹配来执行此操作:(.+?)

p = re.compile(r"^(\d+)\s+(\d+)\s+(.+?)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)$") 
for line in text.splitlines(): 
    m = p.match(line) 
    if m: 
     print m.groups() 

输出是

('10', '79', 'QUANT. DE ITENS A FORNECER', 'O', 'N', '9', '0', '67', '75') 
('11', '24', 'DATA ENTREGA/EMBARQUE DO ITEM', 'O', 'N', '6', '0', '76', '81') 

不知道是否这使得它更具可读性,但你也可以构造一个大的正则表达式从更小的部分,例如"^" + r"(\d+)\s+" * 2 + "(.+?)" + r"\s+(\w+)" * 6 + "$""^" + "\s+".join([r"(\d+)"] * 2 + ["(.+?)"] + [r"(\w+)"] * 6) + "$"

或者,根据或你的输入,你可以用其他的东西比单个空格,如两个或更多的空间\s{2,}(如意见提出)或制表符分开,但是这可能会产生的情况下,存在的问题说明也包含这些内容。使用固定数量的“描述”内容可能会更可靠。

+0

非常感谢!我的输入是一个包含许多这样的文本块的文件。我将遍历所有行以能够添加检查。 –

1

给定一个文件,像这样:

$ cat /tmp/test.txt 
10 79 QUANT. DE ITENS A FORNECER  O N  9 0 67 75 
      E' a quantidade de itens que o fornecedor consegue suprir 
      o cliente para uma determinada data. As casa decimais estao 
      definidas no campo 022 (unid. casas decimais).    

11 24 DATA ENTREGA/EMBARQUE DO ITEM O N  6 0 76 81 
      Data de entrega/embarque do item. Nos casos em que este cam- 
      po nao contiver a data, seu conteudo devera ser ajustado en- 
      tre as partes. 

如果你想捕捉的描述,您可以使用mmap用正则表达式和块捕获文件块。

例子:

import re 
import mmap 
block_pattern=re.compile(r'^(\d+\s+\d+\s+.*?)(?=(?:^\s*$)|\Z)', flags=re.S | re.M) 
data_pattern=re.compile(r'^(\d+)\s+(\d+)\s+(.*?)\s+(\w)\s+(\w)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$') 
with open(fn) as f: 
    txt=mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) 
    for block in block_pattern.finditer(txt): 
     block_lines=block.group(0).partition('\n') 
     m=data_pattern.search(block_lines[0]) 
     if m: 
      block_data=[m.groups(), block_lines[2]] 
      print block_data 

打印:

[('10', '79', 'QUANT. DE ITENS A FORNECER', 'O', 'N', '9', '0', '67', '75'), "   \x0fE' a quantidade de itens que o fornecedor consegue suprir\n   \x0fo cliente para uma determinada data. As casa decimais estao \n   \x0fdefinidas no campo 022 (unid. casas decimais).    \n"] 
[('11', '24', 'DATA ENTREGA/EMBARQUE DO ITEM', 'O', 'N', '6', '0', '76', '81'), '   \x0fData de entrega/embarque do item. Nos casos em que este cam-\n   \x0fpo nao contiver a data, seu conteudo devera ser ajustado en-\n   \x0ftre as partes. \n'] 

正如评论指出,this regex是非常接近你想要什么。

+0

非常感谢。由于我通过文件循环的方式,应该对mmap.mmap的使用进行改进。你认为有可能捕获文件的所有块如下所述? –

0

感谢大家。

脚本的目标是txt文件[链接] [1]

[1]分析:http://www.anfavea.com.br/rnd/006.TXT RND定义文件为蟒结构:

recorddefs = [{'ITP': [['1', '1', 'IDENT. REGISTRATION TYPE', 'M', 'A', '3', '0', '1', '3'], 
        ['2', '33', 'IDENTIFICATION OF THE PROCESS', 'M', 'N', '3', '0', '4', '6'], 
          ...]}, 
      'RP1': [['1', '1', 'IDENT. REGISTRATION TYPE', 'M', 'A', '3', '0', '1', '3'], 
        ['2', '2', 'COD. DESTINATION FACTORY', 'M', 'A', '3', '0', '4', '6'], 
...]}, 
      'RP2': [['1', '1', 'IDENT. REGISTRATION TYPE', 'M', 'A', '3', '0', '1', '3'], 
        ['2', '24', 'DATA DELIVERY/SHIPMENT OF THE ITEM', 'M', 'N', '6', '0', '4', '9'], 
        ['3', '25', 'QT DELIVERY/SHIPMENT OF THE ITEM', 'M', 'N', '9', '0', '10', '18'], 
...,]}] 

每个块由识别一个代码(3位数字),其中包含所有属于它的元素的描述(block == segment)。

现在我的(只是片断)代码如下所示:

def parse_file(filename): 
    with contextlib.suppress(StopIteration): 
     with open(filename) as fin: 
      while True: 
       line = next(fin) 
       if "LAYOUT DE REGISTRO" in line: 
        yield parse_segment_block(fin) 


def parse_segment_block(fin_iter): 
    r = defaultdict(list) 
    k = None 
    while True: 
     line = next(fin_iter) 
     if re.search(r"\s(\w{3})\s", line) and not k: 
      k = re.search(r"\s(\w{3})\s", line).group(1) 
     tab_parser = parse_line(line) 
     if tab_parser: 
      r[k].append(tab_parser) 
     if "Rede Nacional de Dados" in line: 
      return r 


def parse_line(line): 
    line = line.strip() 
    p = re.compile(r"^(\d+)\s+(\d+)\s+(.+?)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)$") 
    m = p.match(line.strip()) 
    if m: 
     result = list(m.groups()) 
     result[2] = translate(result[2]) # google translate call 
     return result 

考虑到上述回应。根据@黎明的回应,是否有可能拥有全球搜索模式?

+0

这是一个新的/后续问题?如果是这样,你应该将它作为另一个问题发布(可能参考了这个问题),但不能作为答案。 –

+0

我的错。我没有发表评论。答案只是为了说明这一点。 –

+0

顺便说一句,为什么不使用'for'循环而不是'while True','next'并且抑制'StopIteration'? –