是否可以用另一个正则表达式检测一个有效的正则表达式?如果是这样,请给出下面的示例代码。


当前回答

不太可能的。

用try. catch或你的语言提供的任何方法来评估它。

其他回答

/
^                                             # 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 / < >这一部分/…/

理论上不可能将所有有效的正则表达式语法与一个正则表达式匹配。

如果正则表达式引擎支持递归,比如PCRE,这是可能的,但它不能再被真正地称为正则表达式了。

实际上,“递归正则表达式”不是正则表达式。但这是一个经常被接受的正则表达式引擎的扩展…具有讽刺意味的是,这个扩展的正则表达式并不匹配扩展的正则表达式。

“在理论上,理论和实践是一样的。但实际上并非如此。”几乎所有了解正则表达式的人都知道正则表达式不支持递归。但是PCRE和大多数其他实现支持的不仅仅是基本的正则表达式。

在grep命令中使用这个shell脚本,它向我显示了一些错误。grep:{}的无效内容。我正在制作一个脚本,可以grep代码库找到所有包含正则表达式的文件

这个模式利用了一个名为递归正则表达式的扩展。正则表达式的POSIX风格不支持这一点。您可以尝试使用-P开关来启用PCRE正则表达式风格。

Regex本身“不是正则语言,因此不能用正则表达式来解析……”

这对于经典正则表达式是正确的。一些现代实现允许递归,这使得它成为一种上下文自由语言,尽管对于这个任务来说有点冗长。

我看到你匹配[]()/\。和其他特殊的正则表达式字符。哪里允许非特殊字符?它似乎可以匹配^(?:[\.]+)$,但不能匹配^abcdefg$。这是一个有效的正则表达式。

[^?+*{}()[\]\\|]将匹配任何单个字符,而不是任何其他结构的一部分。这包括文字(a - z)和某些特殊字符(^,$,.)。

不,如果你严格地说正则表达式,而不包括一些实际上是上下文无关语法的正则表达式实现。

正则表达式有一个限制,即不可能编写匹配所有且仅匹配正则表达式的正则表达式。不能匹配已配对的括号等实现。正则表达式使用许多这样的结构,让我们以[]为例。只要有[就必须有匹配],这对于正则表达式"\[.*\]"来说很简单。

正则表达式不可能实现的原因是它们可以被嵌套。如何编写匹配嵌套括号的正则表达式?答案是没有一个无限长的正则表达式就不能。你可以通过蛮力匹配任意数量的嵌套括号,但你永远不能匹配任意长的嵌套括号集。

此功能通常称为计数,因为您正在计数嵌套的深度。正则表达式根据定义不具备计数的能力。


最后我写了一篇关于正则表达式限制的文章。

虽然完全可以使用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; }
}

不太可能的。

用try. catch或你的语言提供的任何方法来评估它。

不,如果你使用标准正则表达式。

原因是您不能满足常规语言的抽运引理。抽吸引理指出,属于语言“L”的字符串是正则的,如果存在一个数字“N”,使得将字符串分为三个子字符串x, y, z,使得|x|>=1 && |xy|<=N,你可以重复y多次,而整个字符串仍然属于L。

抽运引理的一个结果是,你不能有A ^Nb^Mc^N这样的正则字符串,也就是说,两个相同长度的子字符串被另一个字符串隔开。无论你以何种方式将这些字符串分割成x、y和z,你都不能在不获得“a”和“c”数量不同的字符串的情况下“抽取”y,从而保留原始语言。例如,正则表达式中的圆括号就是这种情况。