Başka bir normal ifade ile geçerli bir normal ifade tespit etmek mümkün müdür? Öyleyse lütfen aşağıdaki örnek kodu verin.
Başka bir normal ifade ile geçerli bir normal ifade tespit etmek mümkün müdür? Öyleyse lütfen aşağıdaki örnek kodu verin.
Yanıtlar:
/
^ # 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
/
Bu özyinelemeli bir regex'tir ve birçok regex motoru tarafından desteklenmez. PCRE tabanlı olanlar bunu desteklemelidir.
Boşluk ve yorum olmadan:
/^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*)$/
.NET doğrudan özyinelemeyi desteklemez. (Ve (?1)
ve (?R)
yapılar.) Özyineleme, sayılan dengeli gruplara dönüştürülmelidir:
^ # 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.
sıkıştırılmış:
^(?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>|\?<[^\W\d]\w*>|\?'[^\W\d]\w*')?(?<N>)|\)(?<-N>))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*$(?(N)(?!))
Yorumlardan:
Bu ikame ve çevirileri doğrulayacak mı?
İkamelerin ve çevirilerin regex kısmını doğrular. s/<this part>/.../
Teorik olarak tüm geçerli normal ifade gramerlerini bir normal ifade ile eşleştirmek mümkün değildir.
Normal ifade motorunun PCRE gibi özyinelemeyi desteklemesi mümkündür, ancak bu artık normal ifadeler olarak adlandırılamaz.
Gerçekten de, "özyinelemeli düzenli ifade" normal bir ifade değildir. Ama bu normal ifade motorlarına sıkça kabul edilen bir uzantı ... İronik olarak, bu genişletilmiş normal ifade genişletilmiş normal ifadelerle eşleşmiyor.
"Teorik olarak, teori ve pratik aynıdır. Pratikte öyle değiller." Düzenli ifadeleri bilen neredeyse herkes, düzenli ifadelerin özyinelemeyi desteklemediğini bilir. Ancak PCRE ve diğer birçok uygulama, temel düzenli ifadelerden çok daha fazlasını destekler.
grep komutunda kabuk betiği ile bu, bana bazı hata gösterir .. grep: {} geçersiz içeriği. Düzenli ifadeler içeren tüm dosyaları bulmak için bir kod tabanı grep olabilir bir komut dosyası yapıyorum
Bu model, yinelemeli düzenli ifadeler adı verilen bir uzantıdan yararlanır. Bu normal ifadenin POSIX aroması tarafından desteklenmemektedir. PCRE regex lezzetini etkinleştirmek için -P anahtarıyla deneyebilirsiniz.
Regex'in kendisi "normal bir dil değildir ve bu nedenle düzenli ifadeyle ayrıştırılamaz ..."
Bu klasik düzenli ifadeler için geçerlidir. Bazı modern uygulamalar, bu görev için biraz ayrıntılı olmasına rağmen, onu Bağlamdan Bağımsız bir dile dönüştüren özyinelemeye izin verir.
Nerede eşleştiğini görüyorum
[]()/\
. ve diğer özel normal ifade karakterleri. Özel olmayan karakterlere nerede izin veriyorsunuz? Bu eşleşecek gibi görünüyor^(?:[\.]+)$
, ama değil^abcdefg$
. Bu geçerli bir normal ifade.
[^?+*{}()[\]\\|]
diğer yapıların hiçbiriyle değil, tek bir karakterle eşleşir. (Bu, hem literal içerir a
- z
) ve bazı özel karakterleri ( ^
, $
, .
).
.{,1}
eşleşmedi. Maçlarla değiştirin ^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d*(?:,\d*)?\})[?+]?)?|\|)*)$
. Change \d+
to\d*
[a-b-c]
.
Hayır, kesinlikle düzenli ifadelerden bahsediyor ve aslında bağlamsız gramer olan bazı düzenli ifade uygulamaları dahil etmiyorsanız.
Düzenli ifadelerin bir sınırlaması vardır, bu da tüm regex'lerle eşleşen bir regex yazmayı imkansız hale getirir. Eşleştirilmiş parantez gibi uygulamaları eşleştiremezsiniz. Normal ifadeler bu tür yapıları kullanır, []
örnek olarak alalım. Ne zaman bir regex için yeterince basit [
bir eşleşme olmalıdır .]
"\[.*\]"
Normal ifadeleri imkansız kılan şey, iç içe geçebilmeleridir. İç içe parantezlerle eşleşen bir normal ifadeyi nasıl yazabilirsiniz? Cevap, sonsuz uzun bir regex olmadan yapamazsınız. Kaba kuvvet aracılığıyla istediğiniz sayıda iç içe parantezle eşleştirebilirsiniz, ancak keyfi olarak uzun bir iç içe parantez kümesiyle hiçbir zaman eşleşemezsiniz.
Bu yeteneğe genellikle sayma denir, çünkü yuvalamanın derinliğini sayıyorsunuz. Tanıma göre bir normal ifade, sayma yeteneğine sahip değildir.
Bu konuda " Düzenli İfade Sınırlamaları " yazdım .
İyi soru.
Gerçek düzenli diller keyfi olarak derinden yuvalanmış iyi biçimlendirilmiş parantezlere karar veremez. Alfabeniz içeriyorsa '('
ve ')'
amaç, bunlardan oluşan bir dizenin uygun şekilli parantez olup olmadığına karar vermektir. Bu düzenli ifadeler için gerekli bir gereklilik olduğu için cevap hayırdır.
Ancak, gereksinimi gevşetir ve özyineleme eklerseniz, büyük olasılıkla yapabilirsiniz. Bunun nedeni, özyinelemenin, bu iç içe geçme derinliğini bu yığının üzerine iterek "saymanıza" izin veren bir yığın görevi görebilmesidir.
Russ Cox regex motor uygulaması için harika bir inceleme olan " Düzenli İfade Eşleştirme Basit ve Hızlı Olabilir " yazdı .
Hayır, standart düzenli ifadeler kullanırsanız.
Nedeni, pompalanan lemi düzenli diller için tatmin edememenizdir . Bir numara "N" üç alt dizeleri içine dize bölme sonra böyle, orada varsa pompalama lemma devletler "L" dile ait bir dize düzenli olduğunu x
, y
, z
, öyle ki |x|>=1 && |xy|<=N
sen tekrarlayabilirsiniz, y
istediğiniz kadar çok kez ve tüm dize hala ait olacaktır L
.
Pompalama lemmasının bir sonucu, formda düzenli dizelere a^Nb^Mc^N
, yani başka bir dizeyle ayrılmış aynı uzunlukta iki alt dizeye sahip olamamanızdır. Hiçbir şekilde size böyle dizeleri bölmek x
, y
ve z
sen "pompa", olamaz y
böylece orijinal dili bırakarak "a" ve "c" nin farklı bir sayı ile bir dize alınmadan. Örneğin, düzenli ifadelerdeki parantezlerde durum budur.
MizardX'un yayınladığı gibi yinelemeli bir normal ifadeyi kullanmak mükemmel bir şekilde mümkün olsa da, bu tür şeyler için bir ayrıştırıcı çok daha yararlıdır. Regex'lerin başlangıçta normal dillerle kullanılması amaçlanmıştır, özyinelemeli veya dengeleme gruplarına sahip olmak sadece bir yamadır.
Geçerli normal ifadeleri tanımlayan dil aslında bağlamsız bir gramerdir ve bunu işlemek için uygun bir ayrıştırıcı kullanmalısınız. Basit regex'leri (çoğu yapı olmadan) ayrıştırmak için bir üniversite projesi için bir örnek. JavaCC kullanır. Ve evet, yorumlar İspanyolca'dır, ancak yöntem adları oldukça açıklayıcıdır.
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; }
}
Normal ifade preg_match
geçerli değilse yanlış döndürülecek normal ifadeyi gönderebilirsiniz . @
Hata mesajlarını bastırmak için the komutunu kullanmayı unutmayın :
@preg_match($regexToTest, '');
//
.Asıl olarak pyparsing wiki'den olan ancak şimdi sadece Wayback Machine aracılığıyla kullanılabilen aşağıdaki örnek Paul McGuire, eşleşen dizeleri geri döndürmek amacıyla bazı regex'leri ayrıştırmak için bir dilbilgisi vermektedir . Bu nedenle, '+' ve '*' gibi sınırsız tekrar terimleri içerenleri reddeder. Ancak bu, işleyicileri işleyecek bir ayrıştırıcının nasıl yapılandırılacağı hakkında bir fikir vermelidir.
#
# 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()