2015-09-07 59 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'? –