2017-03-17 1 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 (구문 언어)을 구문 분석하려는 것처럼 보입니다. 형식이 다양 할 수 있기 때문에 이것은 거의 항상 끔찍한 생각입니다. 이것은 [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 modules 및 게시물이 this article 인 경우를 제외하고 허용되는 접근 방식의 쉬운 목록을 산출하지 못했습니다. 최상의 접근 방식을 찾는 것이 실제로 첫 번째 단계입니다.

그러나 다음은 제목과 명확한 설명에 나와있는 질문에 대한 대답입니다. 처리 할 단위가 알 수없는 행에 걸쳐있는 매우 큰 파일을 구문 분석하는 방법입니다.


'버퍼'를 조합하여 확인하십시오. 일치하는 항목을 찾으면 처리하고 지 웁니다.

예를 들어 변수에 한 행을 추가하고 check (정규 표현식을 사용하면 일치하도록 시도)하십시오. 계속 진행하고 프로세스와 일치하고 변수를 지우십시오.

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

@ 동질주의 귀하의 설명과 다른 의견의 진술로 업데이트됩니다. – zdim

관련 문제