다른 정규식으로 유효한 정규식을 감지 할 수 있습니까? 그렇다면 아래에 예제 코드를 입력하십시오.
다른 정규식으로 유효한 정규식을 감지 할 수 있습니까? 그렇다면 아래에 예제 코드를 입력하십시오.
답변:
/
^ # 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$
. 유효한 정규식입니다.
[^?+*{}()[\]\\|]
다른 구문의 일부가 아닌 단일 문자와 일치합니다. (이 두 문자 포함 a
- z
), 특정 특수 문자 ( ^
, $
, .
).
.{,1}
타의 추종을 불허합니다. ^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d*(?:,\d*)?\})[?+]?)?|\|)*)$
일치로 변경하십시오 . 변화 \d+
에\d*
[a-b-c]
.
아니요, 정규 표현식에 대해 엄격하게 말하고 실제로 컨텍스트 프리 문법 인 일부 정규 표현식 구현을 포함하지 않는 경우.
정규식에는 한 가지 제한 사항이있어 정규식 만 일치하는 정규식을 작성할 수 없습니다. 쌍으로 된 중괄호와 같은 구현을 일치시킬 수 없습니다. 정규 표현식은 그러한 많은 구성을 사용 []
합니다. 예를 들어 봅시다 . [
일치 할 때마다 ]
정규 표현식에 대해 충분히 간단한 일치 항목이 있어야합니다 "\[.*\]"
.
정규식에 불가능한 것은 중첩 될 수 있다는 것입니다. 중첩 된 대괄호와 일치하는 정규식을 어떻게 작성할 수 있습니까? 대답은 무한정 긴 정규 표현식 없이는 할 수 없다는 것입니다. 무차별 대입을 통해 여러 개의 중첩 된 괄호를 일치시킬 수 있지만 임의로 긴 중첩 된 괄호 세트는 일치시킬 수 없습니다.
이 기능은 중첩 깊이를 계산하기 때문에 계산이라고도합니다. 정의에 의한 정규 표현식에는 계산 기능이 없습니다.
이것에 대해 " 정규 표현식 제한 "을 작성 했습니다.
좋은 질문.
진정한 정규 언어는 임의로 깊게 중첩 된 올바른 괄호를 결정할 수 없습니다. 당신의 알파벳이 포함 '('
하고 ')'
목표라면 이것들의 문자열이 일치하는 괄호를 가지고 있는지 결정하는 것입니다. 이것은 정규 표현식에 필요한 요구 사항이므로 대답은 아니오입니다.
그러나 요구 사항을 풀고 재귀를 추가하면 가능합니다. 그 이유는 재귀가이 스택 위로 밀면 현재 중첩 깊이를 "계산"할 수있는 스택의 역할을 할 수 있기 때문입니다.
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, '');
//
.원래 pyparsing wiki에서 왔지만 Wayback Machine을 통해서만 사용할 수 있는 Paul McGuire의 다음 예제 는 일치하는 문자열 세트를 리턴하기 위해 일부 정규 표현식 을 구문 분석하는 문법을 제공합니다 . 따라서 '+'및 '*'와 같은 무한 반복 조건을 포함하는 re를 거부합니다. 그러나 re를 처리하는 파서를 구성하는 방법에 대한 아이디어를 제공해야합니다.
#
# invRegex.py
#
# Copyright 2008, Paul McGuire
#
# pyparsing script to expand a regular expression into all possible matching strings
# Supports:
# - {n} and {m,n} repetition, but not unbounded + or * repetition
# - ? optional elements
# - [] character ranges
# - () grouping
# - | alternation
#
__all__ = ["count","invert"]
from pyparsing import (Literal, oneOf, printables, ParserElement, Combine,
SkipTo, operatorPrecedence, ParseFatalException, Word, nums, opAssoc,
Suppress, ParseResults, srange)
class CharacterRangeEmitter(object):
def __init__(self,chars):
# remove duplicate chars in character range, but preserve original order
seen = set()
self.charset = "".join( seen.add(c) or c for c in chars if c not in seen )
def __str__(self):
return '['+self.charset+']'
def __repr__(self):
return '['+self.charset+']'
def makeGenerator(self):
def genChars():
for s in self.charset:
yield s
return genChars
class OptionalEmitter(object):
def __init__(self,expr):
self.expr = expr
def makeGenerator(self):
def optionalGen():
yield ""
for s in self.expr.makeGenerator()():
yield s
return optionalGen
class DotEmitter(object):
def makeGenerator(self):
def dotGen():
for c in printables:
yield c
return dotGen
class GroupEmitter(object):
def __init__(self,exprs):
self.exprs = ParseResults(exprs)
def makeGenerator(self):
def groupGen():
def recurseList(elist):
if len(elist)==1:
for s in elist[0].makeGenerator()():
yield s
else:
for s in elist[0].makeGenerator()():
for s2 in recurseList(elist[1:]):
yield s + s2
if self.exprs:
for s in recurseList(self.exprs):
yield s
return groupGen
class AlternativeEmitter(object):
def __init__(self,exprs):
self.exprs = exprs
def makeGenerator(self):
def altGen():
for e in self.exprs:
for s in e.makeGenerator()():
yield s
return altGen
class LiteralEmitter(object):
def __init__(self,lit):
self.lit = lit
def __str__(self):
return "Lit:"+self.lit
def __repr__(self):
return "Lit:"+self.lit
def makeGenerator(self):
def litGen():
yield self.lit
return litGen
def handleRange(toks):
return CharacterRangeEmitter(srange(toks[0]))
def handleRepetition(toks):
toks=toks[0]
if toks[1] in "*+":
raise ParseFatalException("",0,"unbounded repetition operators not supported")
if toks[1] == "?":
return OptionalEmitter(toks[0])
if "count" in toks:
return GroupEmitter([toks[0]] * int(toks.count))
if "minCount" in toks:
mincount = int(toks.minCount)
maxcount = int(toks.maxCount)
optcount = maxcount - mincount
if optcount:
opt = OptionalEmitter(toks[0])
for i in range(1,optcount):
opt = OptionalEmitter(GroupEmitter([toks[0],opt]))
return GroupEmitter([toks[0]] * mincount + [opt])
else:
return [toks[0]] * mincount
def handleLiteral(toks):
lit = ""
for t in toks:
if t[0] == "\\":
if t[1] == "t":
lit += '\t'
else:
lit += t[1]
else:
lit += t
return LiteralEmitter(lit)
def handleMacro(toks):
macroChar = toks[0][1]
if macroChar == "d":
return CharacterRangeEmitter("0123456789")
elif macroChar == "w":
return CharacterRangeEmitter(srange("[A-Za-z0-9_]"))
elif macroChar == "s":
return LiteralEmitter(" ")
else:
raise ParseFatalException("",0,"unsupported macro character (" + macroChar + ")")
def handleSequence(toks):
return GroupEmitter(toks[0])
def handleDot():
return CharacterRangeEmitter(printables)
def handleAlternative(toks):
return AlternativeEmitter(toks[0])
_parser = None
def parser():
global _parser
if _parser is None:
ParserElement.setDefaultWhitespaceChars("")
lbrack,rbrack,lbrace,rbrace,lparen,rparen = map(Literal,"[]{}()")
reMacro = Combine("\\" + oneOf(list("dws")))
escapedChar = ~reMacro + Combine("\\" + oneOf(list(printables)))
reLiteralChar = "".join(c for c in printables if c not in r"\[]{}().*?+|") + " \t"
reRange = Combine(lbrack + SkipTo(rbrack,ignore=escapedChar) + rbrack)
reLiteral = ( escapedChar | oneOf(list(reLiteralChar)) )
reDot = Literal(".")
repetition = (
( lbrace + Word(nums).setResultsName("count") + rbrace ) |
( lbrace + Word(nums).setResultsName("minCount")+","+ Word(nums).setResultsName("maxCount") + rbrace ) |
oneOf(list("*+?"))
)
reRange.setParseAction(handleRange)
reLiteral.setParseAction(handleLiteral)
reMacro.setParseAction(handleMacro)
reDot.setParseAction(handleDot)
reTerm = ( reLiteral | reRange | reMacro | reDot )
reExpr = operatorPrecedence( reTerm,
[
(repetition, 1, opAssoc.LEFT, handleRepetition),
(None, 2, opAssoc.LEFT, handleSequence),
(Suppress('|'), 2, opAssoc.LEFT, handleAlternative),
]
)
_parser = reExpr
return _parser
def count(gen):
"""Simple function to count the number of elements returned by a generator."""
i = 0
for s in gen:
i += 1
return i
def invert(regex):
"""Call this routine as a generator to return all the strings that
match the input regular expression.
for s in invert("[A-Z]{3}\d{3}"):
print s
"""
invReGenerator = GroupEmitter(parser().parseString(regex)).makeGenerator()
return invReGenerator()
def main():
tests = r"""
[A-EA]
[A-D]*
[A-D]{3}
X[A-C]{3}Y
X[A-C]{3}\(
X\d
foobar\d\d
foobar{2}
foobar{2,9}
fooba[rz]{2}
(foobar){2}
([01]\d)|(2[0-5])
([01]\d\d)|(2[0-4]\d)|(25[0-5])
[A-C]{1,2}
[A-C]{0,3}
[A-C]\s[A-C]\s[A-C]
[A-C]\s?[A-C][A-C]
[A-C]\s([A-C][A-C])
[A-C]\s([A-C][A-C])?
[A-C]{2}\d{2}
@|TH[12]
@(@|TH[12])?
@(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9]))?
@(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9])|OH(1[0-9]?|2[0-9]?|30?|[4-9]))?
(([ECMP]|HA|AK)[SD]|HS)T
[A-CV]{2}
A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilm]|Uu[bhopqst]|U|V|W|Xe|Yb?|Z[nr]
(a|b)|(x|y)
(a|b) (x|y)
""".split('\n')
for t in tests:
t = t.strip()
if not t: continue
print '-'*50
print t
try:
print count(invert(t))
for s in invert(t):
print s
except ParseFatalException,pfe:
print pfe.msg
print
continue
print
if __name__ == "__main__":
main()