유효한 정규식을 감지하는 정규식이 있습니까? 유효한 정규식을 감지 할 수

다른 정규식으로 유효한 정규식을 감지 할 수 있습니까? 그렇다면 아래에 예제 코드를 입력하십시오.



답변

/
^                                             # start of string
(                                             # first group start
  (?:
    (?:[^?+*{}()[\]\\|]+                      # literals and ^, $
     | \\.                                    # escaped characters
     | \[ (?: \^?\\. | \^[^\\] | [^\\^] )     # character classes
          (?: [^\]\\]+ | \\. )* \]
     | \( (?:\?[:=!]|\?<[=!]|\?>)? (?1)?? \)  # parenthesis, with recursive content
     | \(\? (?:R|[+-]?\d+) \)                 # recursive matching
     )
    (?: (?:[?+*]|\{\d+(?:,\d*)?\}) [?+]? )?   # quantifiers
  | \|                                        # alternative
  )*                                          # repeat content
)                                             # end first group
$                                             # end of string
/

이것은 재귀 정규식이며 많은 정규식 엔진에서 지원하지 않습니다. PCRE 기반 제품이이를 지원해야합니다.

공백과 주석이없는 경우 :

/^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*)$/

.NET은 재귀를 직접 지원하지 않습니다. ( (?1)(?R)구성) 재귀는 균형 그룹을 세는 것으로 변환되어야합니다.

^                                         # start of string
(?:
  (?: [^?+*{}()[\]\\|]+                   # literals and ^, $
   | \\.                                  # escaped characters
   | \[ (?: \^?\\. | \^[^\\] | [^\\^] )   # character classes
        (?: [^\]\\]+ | \\. )* \]
   | \( (?:\?[:=!]
         | \?<[=!]
         | \?>
         | \?<[^\W\d]\w*>
         | \?'[^\W\d]\w*'
         )?                               # opening of group
     (?<N>)                               #   increment counter
   | \)                                   # closing of group
     (?<-N>)                              #   decrement counter
   )
  (?: (?:[?+*]|\{\d+(?:,\d*)?\}) [?+]? )? # quantifiers
| \|                                      # alternative
)*                                        # repeat content
$                                         # end of string
(?(N)(?!))                                # fail if counter is non-zero.

꽉 찬:

^(?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>|\?<[^\W\d]\w*>|\?'[^\W\d]\w*')?(?<N>)|\)(?<-N>))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*$(?(N)(?!))

의견에서 :

대체 및 번역의 유효성을 검사합니까?

대체 및 번역의 정규식 부분 만 유효성을 검사합니다. s/<this part>/.../

이론적으로 모든 유효한 정규식 문법을 정규식과 일치시키는 것은 불가능합니다.

정규식 엔진이 PCRE와 같은 재귀를 지원하는 경우 가능하지만 더 이상 정규 표현식이라고 할 수는 없습니다.

실제로 “재귀 정규 표현식”은 정규 표현식이 아닙니다. 그러나 이것은 정규 표현식 엔진에 자주 사용되는 확장입니다 … 아이러니하게도이 확장 정규 표현식은 확장 정규 표현식과 일치하지 않습니다.

“이론적으로 이론과 실제는 동일합니다. 실제로는 그렇지 않습니다.” 정규 표현식을 알고있는 거의 모든 사람은 정규 표현식이 재귀를 지원하지 않는다는 것을 알고 있습니다. 그러나 PCRE 및 대부분의 다른 구현은 기본 정규식보다 훨씬 많은 기능을 지원합니다.

grep 명령에서 쉘 스크립트와 함께 이것을 사용하면 오류가 표시됩니다. grep : {}의 유효하지 않은 내용. 정규 표현식이 포함 된 모든 파일을 찾기 위해 코드베이스를 grep 할 수있는 스크립트를 만들고 있습니다

이 패턴은 재귀 정규 표현식이라는 확장을 이용합니다. 이것은 POSIX 버전의 정규식에서 지원되지 않습니다. -P 스위치를 사용하여 PCRE 정규 표현식을 사용할 수 있습니다.

정규 표현식 자체는 “정규 언어가 아니므로 정규식으로 구문 분석 할 수 없습니다 …”

이것은 고전적인 정규식에 해당됩니다. 일부 현대 구현에서는 재귀를 허용 하므로이 작업에는 다소 장황하지만 문맥 자유 언어로 만듭니다.

일치하는 부분이 표시 []()/\됩니다. 다른 특수 정규식 문자. 비 특수 문자를 어디에서 허용합니까? 이것은 일치하는 것처럼 보이지만 ^(?:[\.]+)$그렇지 않습니다 ^abcdefg$. 유효한 정규식입니다.

[^?+*{}()[\]\\|]다른 구문의 일부가 아닌 단일 문자와 일치합니다. (이 두 문자 포함 az), 특정 특수 문자 ( ^, $, .).


답변

있을 것 같지 않게.

try..catch귀하가 사용하는 언어로 또는 무엇이든 평가하십시오 .


답변

아니요, 정규 표현식에 대해 엄격하게 말하고 실제로 컨텍스트 프리 문법 인 일부 정규 표현식 구현을 포함하지 않는 경우.

정규식에는 한 가지 제한 사항이있어 정규식 만 일치하는 정규식을 작성할 수 없습니다. 쌍으로 된 중괄호와 같은 구현을 일치시킬 수 없습니다. 정규 표현식은 그러한 많은 구성을 사용 []합니다. 예를 들어 봅시다 . [일치 할 때마다 ]정규 표현식에 대해 충분히 간단한 일치 항목이 있어야합니다 "\[.*\]".

정규식에 불가능한 것은 중첩 될 수 있다는 것입니다. 중첩 된 대괄호와 일치하는 정규식을 어떻게 작성할 수 있습니까? 대답은 무한정 긴 정규 표현식 없이는 할 수 없다는 것입니다. 무차별 대입을 통해 여러 개의 중첩 된 괄호를 일치시킬 수 있지만 임의로 긴 중첩 된 괄호 세트는 일치시킬 수 없습니다.

이 기능은 중첩 깊이를 계산하기 때문에 계산이라고도합니다. 정의에 의한 정규 표현식에는 계산 기능이 없습니다.


이것에 대해 ” 정규 표현식 제한 “을 작성 했습니다.


답변

좋은 질문.

진정한 정규 언어는 임의로 깊게 중첩 된 올바른 괄호를 결정할 수 없습니다. 당신의 알파벳이 포함 '('하고 ')'목표라면 이것들의 문자열이 일치하는 괄호를 가지고 있는지 결정하는 것입니다. 이것은 정규 표현식에 필요한 요구 사항이므로 대답은 아니오입니다.

그러나 요구 사항을 풀고 재귀를 추가하면 가능합니다. 그 이유는 재귀가이 스택 위로 밀면 현재 중첩 깊이를 “계산”할 수있는 스택의 역할을 할 수 있기 때문입니다.

Russ Cox는 정규 표현식 엔진 구현에 대한 훌륭한 논문 인 ” 정규 표현식 일치가 간단하고 빠를 수있다 “라고 썼습니다 .


답변

아니요, 표준 정규식을 사용하는 경우

그 이유는 일반 언어에 대한 펌핑 보조 를 만족시킬 수 없기 때문입니다 . 숫자 “N”은 세 개의 하위 문자열로 문자열을 분할 한 후 같은 것이 존재하면 펌핑 보조 정리 상태 “L”언어에 속하는 문자열은 정규이다 x, y, z, 있도록 |x|>=1 && |xy|<=N당신이 반복 할 수 있습니다, y당신이 원하는만큼 여러 번과를 전체 문자열은 여전히에 속합니다 L.

펌핑 보조 정리의 결과로 a^Nb^Mc^N길이가 같은 두 개의 하위 문자열, 즉 다른 문자열로 구분 된 일반 문자열을 사용할 수 없습니다 . 어떤 식 으로든 x, y및 에서 이러한 문자열을 분리 z하면 y“a”와 “c”가 다른 문자열을 얻지 않으면 “펌프”할 수 없으므로 원래 언어를 그대로 둡니다. 예를 들어 정규 표현식에 괄호가있는 경우입니다.


답변

MizardX가 게시 한 것처럼 재귀 정규 표현식을 사용하는 것이 가능하지만 이러한 종류의 파서는 훨씬 유용합니다. 정규식은 원래 정규 언어와 함께 사용되도록 만들어졌으며 재귀 적이거나 균형 그룹을 갖는 것은 단지 패치입니다.

유효한 정규 표현식을 정의하는 언어는 실제로 컨텍스트 프리 문법이므로 적절한 구문 분석기를 사용하여 처리해야합니다. 다음은 간단한 정규 표현식을 파싱하기위한 대학 프로젝트의 예입니다 (대부분의 구성없이). JavaCC를 사용합니다. 그리고 네, 코멘트는 스페인어로되어 있지만 메소드 이름은 매우 자명합니다.

SKIP :
{
    " "
|   "\r"
|   "\t"
|   "\n"
}
TOKEN :
{
    < DIGITO: ["0" - "9"] >
|   < MAYUSCULA: ["A" - "Z"] >
|   < MINUSCULA: ["a" - "z"] >
|   < LAMBDA: "LAMBDA" >
|   < VACIO: "VACIO" >
}

IRegularExpression Expression() :
{
    IRegularExpression r;
}
{
    r=Alternation() { return r; }
}

// Matchea disyunciones: ER | ER
IRegularExpression Alternation() :
{
    IRegularExpression r1 = null, r2 = null;
}
{
    r1=Concatenation() ( "|" r2=Alternation() )?
    {
        if (r2 == null) {
            return r1;
        } else {
            return createAlternation(r1,r2);
        }
    }
}

// Matchea concatenaciones: ER.ER
IRegularExpression Concatenation() :
{
    IRegularExpression r1 = null, r2 = null;
}
{
    r1=Repetition() ( "." r2=Repetition() { r1 = createConcatenation(r1,r2); } )*
    { return r1; }
}

// Matchea repeticiones: ER*
IRegularExpression Repetition() :
{
    IRegularExpression r;
}
{
    r=Atom() ( "*" { r = createRepetition(r); } )*
    { return r; }
}

// Matchea regex atomicas: (ER), Terminal, Vacio, Lambda
IRegularExpression Atom() :
{
    String t;
    IRegularExpression r;
}
{
    ( "(" r=Expression() ")" {return r;})
    | t=Terminal() { return createTerminal(t); }
    | <LAMBDA> { return createLambda(); }
    | <VACIO> { return createEmpty(); }
}

// Matchea un terminal (digito o minuscula) y devuelve su valor
String Terminal() :
{
    Token t;
}
{
    ( t=<DIGITO> | t=<MINUSCULA> ) { return t.image; }
}


답변

preg_match정규식이 유효하지 않은 경우 false를 반환 하는 정규식을 제출할 수 있습니다 . @오류 메시지를 억제 하기 위해를 사용하는 것을 잊지 마십시오 :

@preg_match($regexToTest, '');
  • 정규식이 인 경우 1을 반환합니다 //.
  • 정규식이 정상이면 0을 반환합니다.
  • 그렇지 않으면 false를 반환합니다.