2013-10-03 4 views
7

perlvar을 인용 :

은 ... $/의 값은 문자열이 아닌 정규식입니다. awk은 더 나은 것이되어야합니다. :-)

가변 길이 레코드가있는 파일 구문 분석은 여러 번 발생하는 고전적인 사용 사례입니다. 이러한 기능이 유용 할 수있는 상황을 생각하는 것이 어렵지 않습니다.

는 지금까지 문제가 전체 파일을 메모리로로드 없었고 할 적이 A :

my @records = split /my_regex/, <> ; 

하지만이 기술은 사용 가능한 메모리가 불충분 한 상황에서 사용할 수없는 분명한 이유

. 사실, 많은 시간에 동시에 모든 레코드를 저장할 필요가 없습니다.

어느 날 다시 $/으로 안내합니다.

이 나는 ​​이상한 언어가 $/에 대한 정규식 지원을 프로비저닝되지 않았 음을 찾을 수 있습니다. 이 작업이 의도적으로 수행 되었습니까? 구현하는 것이 단순히 불가능합니까? 멋진 기능이 없다면 모범 사례로 간주 될 수있는 다른 해결 방법이 있습니까?

+1

['Acme :: InputRecordSeparatorIsRegexp'] (https://metacpan.org/pod/Acme::InputRecordSeparatorIsRegexp) – mob

+1

@ mob : awk가 그걸로 도망 갈 수는 없습니까? :) – Zaid

답변

8

시도하는 것조차별로 의미가 없습니다. 너무 자주, 끝까지 읽지 않고 줄 끝까지 도달했는지 알 수 없을 것입니다. 그것은 대화 형 상황에서 매우 나쁠 수 있습니다.

local $/ = qr/\n|\r\n?/; # Handle Windows, Unix and old MacOS line endings. 
while (1) { 
    print "Please enter a command: "; 
    my $cmd = <>; 
    $cmd =~ s{$/\z}{}; 
    process($cmd); 
} 

오른쪽 매우 간단 보이는 : 예를 들어

,의는 다음과 같은 프로그램을 가정 해 봅시다? 실제로 qr/\n|\r\n?/을 지원하는 것이 아마도이 요청에 대한 가장 중요한 이유 일 것입니다. 음, 그 간단한 코드조차도 심각한 결함이 있습니다. 의 내가 맥 OS 라인 엔딩 (CR,^M, \ r에) 나는 그것을 (CR,^M, \ r에) 또는 종료 맥 OS 라인을 준 여부는 알 수 없기 때문에

$ processor 
Please enter a command: foo^M 
[hangs] 

이 프로그램은 응답을 사용한다고 가정 해 봅시다 다른 문자가 입력 될 때까지 Windows 줄 끝 (CRLF,^M^J, \ r \ n).

두 번째 명령을 처리하려면 두 번째 명령을 입력하고 두 번째 명령을 처리하려면 세 번째 명령을 입력해야합니다.

0

Perl6::Slurp는 가능한 workaraound 같다 :

넌 (IRS {=> $ your_irs_here}) 위한 입력 조작 입력 레코드 구분자를 설정할 수있다. 구분 기호는 문자열 또는 정규식으로 지정할 수 있습니다. I 볼 수있는 가장 큰 문제점

+1

docs에서 : "명시 적 입력 레코드 구분 기호에는 스칼라 컨텍스트에서 입력 종료 효과가 없으며 slurp는 'irs'값이" – Zaid

+0

...이든간에 항상 전체 입력 스트림을 읽습니다. 따라서 이것은 간단합니다 전체 파일을 메모리에로드 한 다음 분리하기 – Zaid

4

하나는 일반적으로 정규식 레코드 분리 을 지원하는 파일의 전체 내용을 검사 할 것을 요구한다는 것이다. 어떤 이유로, 당신은 /\n[^X]+\z/의 분리를 규정 한 것을 예를 들어 가정하자

,. 각 줄 바꿈 후에 X 문자가 있는지 확인하려면 전체 파일을 읽어야합니다.

그래서 내가 생각할 수있는 세 가지 옵션이 있습니다 : 그냥 "페이징"문자열에서 정규 표현식을 구현

  • 기록 분리기를 검색하기 위해 전체 파일을 버퍼링

    • 파일 있도록 레코드 구분 기호로 사용하기위한 표준 정규 표현식의 부분 집합을 구현 부품

    • 읽을 수

    이들 중 어느 것도 구현 관점에서 특히 매력적인 전망은 아니며, 가능한 한 가능하지 않다는 것을 알 수 있습니다. 특히 split을 사용하여 Perl 코더에서 첫 번째 옵션을 사용할 수 있습니다.

  • +1

    사람들이 의미가없는 정규식을 제공 할 수 있다는 사실은 정규식을 지원하지 않는 이유가 아닙니다. – ikegami

    +0

    Re "레코드 분리자를 스캔하기 위해 전체 파일을 버퍼링하는 중"입니다. 이미이 경우가 있습니다 (로컬 $ /;와'$ /'가 포함되지 않은 파일) – ikegami

    3

    펄 정규식 엔진의 (역행) 구현 끝나는 라인으로 사용 근본적으로 호환된다.이 문제의 일부는 다음 문자를 읽을 때 전체 정규식을 재실행하지 않으려한다는 것입니다. 예를 들어, 정규식

    $/ = qr/ A \w*? B | XY/; 
    

    그리고 데이터 스트림 그래서

    f o o A 1 2 X Y B b a r 
    

    을 때 readline 반환해야? 우리가 증분 일치 할 경우 우리는 각 위치에서 전체 정규식을 다시 실행하면, 우리는 우리가이을 (우선 순위) 교대, 즉

    f o o A 1 2 X Y B b a r 
    
         A *FAIL 
         *FAIL 
    
         A\w *FAIL 
         *FAIL 
    
         A\w\w *FAIL 
         *FAIL 
    
         A\w\w\w *FAIL 
          X *FAIL 
    
         A\w\w\w\w *FAIL 
          X Y 
    
    #=> fooA12XY 
    

    을 얻을

    f o o A 1 2 X Y B b a r 
         A\w\w\w\w B 
    
    #=> fooA12XYB 
    

    같은 것을 얻을 수 있습니다 일치하는 복잡한. regex 엔진이 역 추적하지 않는다면 (그러나 테이블 파서 또는 상태 머신으로 실행하는 것이 좋습니다) 전체 정규식을 재실행하거나 증분 일치를 수행하는 경우에는 차이가 없습니다. 그러나 이것이 가능한 정규식 엔진은 Perl 정규 표현식보다 표현력이 적습니다. .*이 원하기 때문에

    또 다른 문제는 ((정규식은 하나 개의 문자 후 이미 만족하기 때문에) 바로 다음 문자를 반환 이러한 "라인"을 읽어해야

    $/ = qr/ .+ /xs; 
    

    끝나는 선 또는 전체 파일 것 가능한 한 많이 일치 시키십시오)? 또는 현재 내부 버퍼의 나머지 부분을 반환해야합니다.

    라인 엔딩에 정규 표현식을 사용하려면 이러한 모호성에 유의해야하며 추가 제한 사항을 적용해야합니다 (예 : 일반 언어 만 허용).

    +0

    입니다. 이것은 awk이 왜 그것을 할 수 있고 Perl이 할 수 없는지에 대한 후속 질문에 대한 답입니다. – Zaid

    +0

    비효율적 인 정규 표현식을 사용할 수 있다는 사실은 그들을 지원하지 않는 매우 설득력있는 이유는 아닙니다. – ikegami

    +0

    '$/= qr /. +/xs;'와는 아무런 문제가 없습니다 (단 말기를 제외하고는). 당신은 정규 표현식 없이도 계속 읽어야합니다. 예 : '$/= "\ r \ n";'또는'$/= $ mime_sep;'를 고려하십시오. – ikegami

    관련 문제