2017-03-17 56 views
0

我有一個4GB的文本文件,其長度高度可變,這只是一個示例文件,生產文件將會大得多。我需要讀取該文件並應用多行正則表達式。Perl讀取一個大文件用於多行正則表達式

什麼是閱讀這樣一個大型文件的多行正則表達式的最佳方式是什麼?

如果我逐行閱讀它,我不認爲我的多行正則表達式可以正常工作。當我在3參數形式中使用read函數時,我的正則表達式結果會隨着我在read語句中指定的長度的大小而改變。我相信文件的大小使它太大而無法讀入數組或內存。

這是我的代碼

package main; 
use strict; 
use warnings; 

our $VERSION = 1.01; 
my $buffer; 
my $INFILE; 
my $OUTFILE; 

open $INFILE, '<', ... or die "Bad Input File: $!"; 
open $OUTFILE, '>',... or die "Bad Output File: $!"; 

while (read $INFILE, $buffer, 512 ) { 
    if ($buffer =~ /(?m)(^[^\r\n]*\R+){1}^(B|BREAK|C|CLOSE|D|DO(?! NOT)|E|ELSE|F|FOR|G|GOTO|H|HALT|HANG|I|IF|J|JOB|K|KILL|L|LOCK|M|MERGE|N|O|OPEN|Q|QUIT|R|READ|S|SET|TC|TRE|TRO|TS|U|USE|V|VIEW|W|WRITE|X|XECUTE)(|:).*[^\r\n]/) { 
     print $OUTFILE $&; 
     print $OUTFILE "\n"; 
    } 
} 

close($INFILE); 
close($OUTFILE); 
1; 

下面是一些示例數據:

^%Z("EUD") 
S %L=%LO,%N="E1" 
^%Z("RT") 
This is data that I don't want the regex to find 
^%Z("EXY") 
X ^%Z("EW2"),^%Z("ELONG"):$L(%L)>245 S %N="E1" Q:$L(%L)>255 X ^%ZOSF("EON") S DX=0,DY=%EY,X=%RM+1 X ^%ZOSF("RM"),XY K %EX,%EY,%E1,%E2,DX,DY,%N Q 
^%Z("F12") 
S %A=$P(^DIC(9.8,0),"^",3)+1,%C=$P(^(0),"^",4)+1 X "F %=0:0 Q:'$D(^DIC(9.8,%A,0)) S %A=%A+1" S $P(^DIC(9.8,0),"^",3,4)=%A_"^"_%C,^DIC(9.8,%A,0)=%X_"^R",^DIC(9.8,"B",%X,%A)="" 
^%Z("F2") 
S %=$H>21549+$H-.1,%Y=%\365.25+141,%=%#365.25\1,%D=%+306#(%Y#4=0+365)#153#61#31+1,%M=%-%D\29+1,%DT=%Y_"00"+%M_"00"+%D,%D=%M_"/"_%D_"/"_$E(%Y,2,3) 

上述線是成對的,語法(線1和2一起去,3和4等)。我需要找到特定的對,這是所有的對除上述數據:

^%Z("RT") 
This is data that I don't want the regex to find 
+3

看起來你正在嘗試使用多行正則表達式來解析DSL(doman特定語言)。這幾乎總是一個可怕的想法,因爲格式可能差異很大。這似乎是一個[XY問題](http://xyproblem.info),你已經走下了思考的正確的工具,正確的工具,當它幾乎肯定不是。你應該做的是編輯你的問題,包括一個有代表性的輸入樣本,並描述你的最終目標。 –

+1

因爲它看起來足夠複雜,以便以後擴展和更精確的解析,我會建議使用[Pegex](https://metacpan.org/pod/distribution/Pegex/lib/Pegex.pod)來構建解析器。開始有點陡峭(需要學習Pegex並編寫語法規則),但稍後它可能會付錢... – jm666

+0

提醒,請參閱[當某人回答我的問題時該怎麼辦?](http://堆棧溢出。com/help/someone-answers) – zdim

回答

2

的問題顯然是關於解析DSL,並且似乎在一般的正則表達式是不是該正確的工具。快速搜索沒有產生易於接受的方法列表,除了pages of CPAN modulesthis article之類的帖子。找出最佳方法確實是第一步。

但是,以下是標題和明確描述中所述問題的答案:如何解析非常大的文件,其中要處理的單元遍佈未知數量的行。


繼續組裝一個'緩衝區'並檢查它。一旦你找到一個匹配,處理並清除它。

例如,附加一行到變量並檢查(如果使用正則表達式,嘗試匹配)。繼續前進,一旦匹配過程並清除變量。

my $unit; 
while (<$fh>) { 
    # chomp;  # if suitable 
    $unit .= $_; 

    if (test_unit($unit)) { 
     # process ... 
     $unit = undef; 
    } 
} 

test_unit是代碼的佔位符,用於決定是否應該處理組合單元。如果是這樣的正則表達式可以在循環之前進行定義,my $re = qr/.../;(參見qr in perlop),然後測試在環與if ($unit =~ $re)

在問題的說明指出,要被處理成對出現線,但它是在clarificated後續行不總是配對的評論。因此我們不能處理線對。

+0

成對語法不一致,文件中包含其他數據結構。正則表達式找到我需要的多行對,並通過所有其他的東西,所以我需要避免操縱數據,以防我破壞數據的神祕結構。你能提出一個緩衝區方法的代碼片段嗎? – Intrinsic

+0

@我看到了。然後保持修補線並檢查。這樣,你一次只能在內存中擁有(大概)小塊,並且按照我的理解,你完全按照自己的意願去做。 (除非整個方法可以被別的東西替代,像[@Jim Garrison](http://stackoverflow.com/users/18157/jim-garrison)的評論說的那樣。我不知道,我在迴應標題和問題中的明確聲明。) – zdim

+0

@Intrinsic更新爲您的說明和其他評論中的陳述。 – zdim