2013-06-22 8 views
5

솔직히, 나는 먼저이 질문의 문법에 대한 도움을 요청해야한다고 생각합니다.정규식으로 루프를 만드는 방법은 무엇입니까?

하지만 적절한 제목으로 제목을 편집한다는 것을 이해할 수 있다면 제발.

이와 같이 텍스트를 분리 할 수있는 패턴을 만드는 방법이 있습니까?

{{START}} 
    {{START}} 
     {{START}} 
      {{START}} 
      {{END}} 
     {{END}} 
    {{END}} 
{{END}} 

{{START}}마다 {{END}}과 (과) 일치합니다.

그리고 내가 정규식으로 만 할 수 없다면. PHP를 사용하는 것은 어떨까요?

감사합니다.

+5

Perl과 같은 언어로 번역 할 수있는 트릭이 내 켄을 넘어서는 있지만 정규식의 대부분의 맛은 사용할 수 없습니다. 펌핑 보조 정리에 대해 읽어보고 왜 할 수 없는지 알아보십시오. – siride

+0

귀하의 서식을 입력이라고 가정합니다. 좀 더 설명했다면 아마 다른 대안이 제시 될 수 있습니다. –

+0

당신이 뭔가를 구문 분석하려고하는 것처럼 들리 네요. [뭔가가 HTML처럼 복잡해지면 (저에게 그렇게 보입니다), 정규식으로 처리하는 것은 나쁜 생각입니다.] (http://stackoverflow.com)/question/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454 # 1732454) – michaelb958

답변

4

이것은 일반적인 문법 만 구문 분석 할 수있는 정규 표현식의 기능을 벗어납니다. 당신이 기술하고있는 것은 푸시 다운 오토 마톤이 필요합니다 (일반 언어는 regular automaton으로 정의됩니다).

일반 표현식을 사용하여 개별 요소를 구문 분석 할 수 있지만 "깊이"부분은 메모리 개념으로 언어에 의해 처리되어야합니다 (PHP는 이에 적합합니다).

그렇다면 정규식은 태그를 식별하는 데만 사용되지만 깊이를 추적하고 END 태그가 속한 요소를 결정하는 실제 논리는 프로그램 자체 여야합니다.

+1

PHP는 정규 표현식 이상의 것을 할 수있는 정규식 엔진을 사용합니다. http://pcre.org/pcre.txt - 귀하의 답변은 학업 성적에 불과하므로 실용적인 문제는 아닙니다. 그러나 그 엔진을 사용하여 개요를 설명 할 수도 있습니다. 첫 번째 부분은 PHP/PCRE에는 적용되지 않습니다. – hakre

1

순수한 RegEx로는이 작업을 수행 할 수 없지만 간단한 루프만으로 수행 할 수 있습니다.

JS 예 :

//[.\s\S]* ensures line breaks are matched (dotall not supported in JS) 
var exp = /\{\{START\}\}([.\s\S]*)\{\{END\}\}/; 

var myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}"; 

var matches = []; 
var m = exp.exec(myString); 
while (m != null) { 
    matches.push(m[0]); 
    m = exp.exec(m[1]); 
} 

alert(matches.join("\n\n")); 

PHP는 (나는이 맞다면 내가 PHP를 한 적이 있기 때문에 아무 생각이 영원히 적이있어이)

$pattern = "/\{\{START\}\}([.\s\S]*)\{\{END\}\}/"; 
$myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}"; 

$result = preg_match($pattern, $myString, $matches, PREG_OFFSET_CAPTURE); 
$outMatches = array(); 
while ($result) { 
    array_push($outMatches, $matches[0]); 
    $result = preg_match($pattern, $matches[1], $matches, PREG_OFFSET_CAPTURE); 
} 
print($outMatches); 

출력 :

{{START}} 
test 
{{START}} 
test 2 
{{START}} 
test 3 
{{START}} 
test4 
{{END}} 
{{END}} 
{{END}} 
{{END}} 

{{START}} 
test 2 
{{START}} 
test 3 
{{START}} 
test4 
{{END}} 
{{END}} 
{{END}} 

{{START}} 
test 3 
{{START}} 
test4 
{{END}} 
{{END}} 

{{START}} 
test4 
{{END}} 
+0

OP는 PHP 솔루션을 원했습니다. 다시 시도하십시오. – michaelb958

+0

PHP가 올바르게 추가되었는지 알 수 없습니다. 몇 년 동안 PHP를하지 않았습니다. –

+0

PHP regex에는 재귀가 있습니다. http://pcre.org/를 참조하십시오. – hakre

2

가능합니다!

$data = <<<LOD 
{{START1}} 
    aaaaa 
    {{START2}} 
     bbbbb 
     {{START3}} 
      ccccc 
      {{START4}} 
       ddddd 
      {{END4}} 
     {{END3}} 
    {{END2}} 
{{END1}} 
LOD; 

$pattern = '~(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}}))~'; 
preg_match_all ($pattern, $data, $matches); 

print_r($matches); 

설명 :

부분 : 패턴의이 부분은 {{START#}}와 중첩 된 구조를 설명

({{START\d+}}(?>[^{]++|(?1))*{{END\d+}}){{END#}}

(   # open the first capturing group 
{{START\d+}} 
(?>   # open an atomic group (= backtracks forbidden) 
    [^{]++ # all that is not a { one or more times (possessive) 
    |   # OR 
    (?1)  # refer to the first capturing group itself 
)    # close the atomic group 
{END\d+}}  # 
)    # close the first capturing group 
당신은 재귀 정규 표현식을 사용하여 콘텐츠의 각 레벨을 가질 수있다

이제는이 부분으로 만 모든 레벨을 캡처 할 수 없다는 것이 문제입니다. 문자열의 모든 문자는 패턴에 의해 소비됩니다. 즉, 문자열의 겹쳐진 부분을 일치시킬 수 없습니다.

(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}})) 

이 모든 레벨과 일치합니다 :

문제는 그 결과, 룩어 (?=...) 같은 문자를 소비하지 않는 제로 폭 주장 내부의 모든 부분을 래핑하는 것입니다.

관련 문제