2010-06-17 2 views
0

Perl에서 구문 분석하는 일부 데이터가 있으며 가까운 시일 내에 점점 더 형식이 다른 데이터가 추가 될 것입니다. 내가 뭘하고 싶은지는 문자열과 정규 표현식을 전달할 수있는 사용하기 쉬운 함수를 작성하는 것이고 괄호 안에는 아무것도 반환하지 않을 것이다. 그것은이 (의사)과 같이 작동합니다 :펄 정규식에서 n 개의 괄호가 일치합니다.

sub parse { 
    $data = shift; 
    $regex = shift; 

    $data =~ eval ("m/$regex/") 
    foreach $x ($1...$n) 
    { 
    push (@ra, $x); 
    } 
    return \@ra; 
} 

그럼,이처럼 호출 할 수 있습니다 당신이 볼 수 있듯이

@subs = parse ($data, '^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)'); 

,이 코드에 문제가 몇 가지있다. 평가가 작동하는지, 'foreach'가 제대로 작동하지 않을지, 그리고 얼마나 많은 괄호가 있는지 모른 채 루프 할 횟수를 모르겠습니다.

이것은 분할하기에 너무 복잡하기 때문에 간과 할 수있는 다른 기능이나 가능성이 있다면 알려주십시오.

도움 주셔서 감사합니다.

답변

6

목록 컨텍스트에서 정규식은 괄호로 묶은 모든 일치 목록을 반환합니다.

그래서 당신이해야 할 모든은 다음과 같습니다

my @matches = $string =~ /regex (with) (parens)/; 

그리고 일치한다고 가정 @matches 두 캡처 그룹의 배열이 될 것입니다. 당신이 긴 정규 표현식에있을 때

my @subs = $data =~ /^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)/; 

는 또한, 펄이 닫는 정규식 구분 기호 후가는 x 수정을 가지고 :

그래서 당신의 정규식을 사용하여. x 수정자를 사용하면 가독성을 높이기 위해 공백과 뉴 라인을 정규식에 넣을 수 있습니다.

길이가 0 인 캡처 그룹이 염려되는 경우 @subs = grep {length} @subs을 통해 일치를 전달하여 필터링 할 수 있습니다.

+0

정규식에 괄호가 있는지 여부를 모르는 경우 (기본 전체 일치 문자열 대신) 아무 것도 반환하지 않으려면 추가 세트를 추가하십시오.'$ string = ~/(regex) /' 결과에서이를 버립니다. – ysth

+0

그 grep은 실제로 일치하지 않는 괄호를 걸러 내고, 길이가 0이 아닌 괄호를 걸러 낼 것입니다. (정의되고 "") – ysth

+0

@ysth => 맞습니다. –

0

정규 표현식을 사용하여 복잡한 표현식을 구문 분석하려고합니다. 이는 작업을위한 도구로 충분하지 않습니다. 정규식은 더 높은 문법을 구문 분석 할 수 없다는 것을 상기하십시오. 직관의 경우 중첩 될 수있는 표현식은 정규식으로 파싱 할 수 없습니다.

+0

펄의 regexen이 불규칙 다음은 예입니다. '(?? {blah})'를 사용할 수 있습니다. 그러나 정확하게 권장되는 것은 아닙니다. – muhmuhten

+0

perl의 정규식 엔진은 중첩 된 구문을 쉽게 일치시킬 수있는 재귀도 지원합니다. –

+0

True - 많은 정규식 구현은 일반 언어 집합보다 실제로 구문 분석 할 수 있지만 일관성이 없습니다. 문법을 구문 분석해야하는 경우 적절한 문법 파서를 사용하십시오. –

0

괄호 쌍 안에 텍스트를 찾으려면 Text::Balanced을 사용하고 싶습니다.

하지만 원하는 것은 아니므로 도움이되지 않습니다.

+1

질문의 이름에도 불구하고, OP가 실제로 중첩 된 괄호와 일치하도록 찾고있는 것처럼 보이지 않습니다. 순차적 캡처 그룹이 여러 개있을 수있는 정규식을 사용하는 것 같습니다. –

+0

죄송합니다. 대신 '괄호 그룹'이라고 말 했어야합니다. '괄호'. –

1

그럼,이처럼 호출 할 수 있습니다

@subs = parse($data, 
      '^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)'); 

를 대신 원하는 전화 : 당신이 named captures를 사용할 수 있는지

또한
parse($data, 
    qr/^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)/); 

, 당신의 작업이 간단 할 것 (Perl 5.10 이상).

#!/usr/bin/perl 

use strict; use warnings; 

my %re = (
    id => '(?<id> [0-9]+)', 
    name => '(?<name> \w+)', 
    value => '(?<value> [0-9]+)', 
); 

my @this = (
    '123,one:12', 
    '456,two:21', 
); 

my @that = (
    'one:[12],123', 
    'two:[21],456', 
); 

my $this_re = qr/$re{id} , $re{name} : $re{value}/x; 
my $that_re = qr/$re{name} : \[$re{value}\] , $re{id} /x; 

use YAML; 

for my $d (@this) { 
    print Dump [ parse($d, $this_re) ]; 
} 

for my $d (@that) { 
    print Dump [ parse($d, $that_re) ]; 
} 

sub parse { 
    my ($d, $re) = @_; 
    return unless $d =~ $re; 
    return my @result = @+{qw(id name value)}; 
} 

출력 :

--- 
- 123 
- one 
- 12 
--- 
- 456 
- two 
- 21 
--- 
- 123 
- one 
- 12 
--- 
- 456 
- two 
- 21
+0

감사합니다. 알아두면 좋습니다! –