2013-02-05 2 views
4

누구나이 정규식으로 나를 도와 줄 수 있습니까? 끝에 "생성 된"문자열을 포함하지 않는 행과 일치하는 표현식이 필요합니다. 이 스크립트는 일부 소스 코드에서 제목을 읽는 데 사용됩니다. Perl 정규식 정규식 일치 문자열 제외, 일치하는 문자열이 없음

$string = "* JAN-01-2001 bugsbunny  1234  Created Module"; 
#$string = "* DEC-12-2012 bugsbunny  5678  Modified Module"; 
if($string =~ /^\*\s+(\w\w\w-\d\d-\d\d\d\d)\s+(\w+)\s+(\d+)\s+(?!Created)/){ 
    print "$1\n$2\n$3\n$4\n"; 
} else { 
    print "no match\n"; 
} 

처음 $ 문자열의 정의를 사용하여

, 나는 그것의 끝에서 "만든"단어를 가지고 있기 때문에 실패 할 경기를해야합니다. 두 번째 $ string 정의를 사용할 때 전달해야하며 날짜 ($ 1), 사용자 ($ 2), 변경 번호 ($ 3) 및 설명 ($ 4)을 가져와야합니다.

위의 표현식이 작동하지 않습니다. 어떤 조언을 해주시겠습니까?

답변

4

닫기 :

/^\*\s+(\w{3}-\d{2}-\d{4})\s+(\w+)\s+(\d+)\s+(?!.*Created)/ 

당신은 Created 전에 비 개행 문자의 수를 허용해야합니다, 그러므로 .*.

그렇지 않으면 정규식은 과 일치 할 때 한 문자 씩 백업되므로 다음 텍스트는 이되고 (?!Created)은 일치합니다.

here; 경기가 Created 이전의 한 칸을 어떻게 멈추는 지주의하십시오.

+0

이 또한 필요'*'Created''후.. 실제로 'end'의 OP 정의는 잘못되었습니다. 그는 아마'Created'가 문자열의 마지막 부분에 있어서는 안된다고 원합니다. –

+0

@RohitJain : 아니요. '만든'뒤에 '. *'는 필요하지 않습니다. 미리보기 일치는 문자열 끝에 고정되어 있지 않습니다. 그는 "최종적으로 창조 된"을 포함하지 않고 "창조 된"으로 끝나지 않는다고 썼다. –

+0

@TimPietzcker .. 아! 나는 그것을 어떻게 놓쳤는가? –

1

이 작업을 수행하는 데 사용할 수있는 또 다른 트릭은 역 추적을 비활성화하는 (?>...) 그룹을 사용하는 것입니다. 역 추적을 사용하지 않으면 + 또는 *을 사용하는 표현식이 발견 한 모든 것을 탐욕스럽게 먹고, 패턴이 실패하면 다시 시도하지 않습니다.. 즉, "Created"이전의 공백은 모두 먹었으므로 정규 표현식의 (?!Created) 부분은 항상 정확한 시점에서 발생합니다.

if($string =~ /^(?>\*\s+(\w\w\w-\d\d-\d\d\d\d)\s+(\w+)\s+(\d+)\s+)(?!Created)/){ 
    print "$1\n$2\n$3\n"; 
} else { 
    print "no match\n"; 
} 

또한 정규 표현식을 훨씬 빠르게 만드는 보너스가 추가되었습니다.

이 접근법은 모든 종류의 문제에 대해 작동하지 않습니다. 많은 정규 표현식이 정확하게 일치시키기 위해 역 추적 할 수 있어야하기 때문입니다. 그러나 이것은 위대한 일을 할 것입니다.

0

또 다른 옵션은 split로하고 '생성'에 대한 설명을 테스트 :

use strict; 
use warnings; 

#my $string = "* JAN-01-2001 bugsbunny  1234  Created Module"; 
my $string = "* DEC-12-2012 bugsbunny  5678  Modified Module"; 

my (undef, $date, $user, $change, $desc) = split ' ', $string, 5; 

if ($desc !~ /^Created/) { 
    print "$date\n$user\n$change\n$desc\n"; 
} 
else { 
    print "no match\n"; 
} 

출력 :

DEC-12-2012 
bugsbunny 
5678 
Modified Module 
+0

OP는 소스 코드의 제목에 대한 검색임을 OP가 명시했습니다. 따라서 정규 표현식의 나머지 부분은 소스의 다른 부분이 아니라 표제를 실제로 볼 수있게하는 데 필요했습니다.또한 모든 행을 분할하는 것은 작은 행의 하위 집합을 찾을 때 비효율적 인 해결책이됩니다. 원래와 같은 정규 표현식은'*'로 시작하지 않는 행을 즉시 거부하므로 훨씬 빠릅니다. –

+0

@ dan1111 - 벤치마킹이 6 % 빨라진 것처럼 [정규식 대 스플릿] (http://pastebin.com/CbHNd4wJ)과 같이 정규식 솔루션이 반드시 '분할'보다 * 빠릅니다 *. 내 솔루션이 절대적으로 실패하는 곳은 OP의 문자열 패턴 (귀하의 경우처럼)과 일치하지 * 않습니다. 오 탐지 (false positives)를 만들 수있는 다른 표제가있을 수 있습니다. – Kenosis

+0

나는 훨씬 더 빠를 것이라고 생각한다. –

0
$string = "* JAN-02-2001 bugsbunny  1234  Created Module"; 
$string = "* DEC-12-2012 bugsbunny  5678  Modified Module"; 
if($string =~ /^\*\s+(\w\w\w-\d\d-\d\d\d\d)\s+(\w+)\s+(\d+)\s+([^Created]|Modified)\s+(\w+)/){ 
    print "$1\n$2\n$3\n$4\n"; 
} 
else { 
    print "no match\n"; 
}