只匹配自己的正则表达式


338

正则表达式(自匹配正则表达式正则表达式验证正则表达式)面临一些非常酷的挑战

这可能是不可能的,但是是否存在只能匹配自身的正则表达式?

注意,必须包括定界符:

例如/thing/必须匹配/thing/而不是thing。表达式唯一可能的匹配必须是表达式本身。许多语言允许使用字符串代替正则表达式。例如在Go中

package main

import "fmt"
import "regexp"

func main() {

    var foo = regexp.MustCompile("bar")
    fmt.Println(foo.MatchString("foobar"))
}

但是为了挑战,如果您想将引号作为分隔符,则让表达式被定界(开始符号,表达式,结束符号ex:/fancypantpattern/@[^2048]@)。我认为,鉴于此问题的明显困难,它不会带来太大变化。

为了帮助您:

我为rubular.com(用于ruby regex编辑的网页)放在一起的快速技巧:

var test = document.getElementById("test")
,regex = document.getElementById("regex")
,delimiter="/"
,options = document.getElementById("options")
,delay = function(){test.value = delimiter + regex.value + delimiter + options.value}
,update = function(e){
    // without delay value = not updated value
    window.setTimeout(delay,0);
}
regex.onkeydown = update;
options.onkeydown = update;

即使从技术上讲这是“代码高尔夫”,但如果有人能找到答案/证明这是不可能的话,我将印象深刻。

链接现已修复。对不起

迄今为止的获奖答案:40个字符的jimmy23013


3
显然,任何仅包含文字的正则表达式都可以使用://,/ a /,/ xyz /等。最好要求正则表达式必须包含非文字操作。
面包箱2014年

9
文字将不起作用,因为您需要匹配反斜杠,例如/ aaa /将匹配,aaa但/ aaa /不匹配
Dylan Madisetti 2014年

2
@DylanMadisetti我们必须使用//定界符,还是可以选择其他定界符(PCRE支持几乎任何字符,特别是可以使用匹配的括号/大括号/括号作为定界符)。
马丁·恩德

3
我认为这是一个很好的数学/计算问题,证明可能并不容易...许多重要的定理只是作为一个简单的问题而展开的,因此也许在5年后,维基百科将发表文章“ Madisetti问题”;)
帕维尔Tokarz

3
对,就是这样。在某些语言中(例如bash中的grep),分隔符本质上是一个空字符串。因此,首先假设正则表达式需要定界符已经是错误的。实际上,由于grep是regexp的最早实现之一,因此regexp的规范定义没有定界符。此假设的最错误体现是PHP,它需要两个定界符:"//"
slebetman 2014年

Answers:


588

PCRE风味,261 289 210 184 127 109 71 53 51 44 40字节

对的,这是可能的!

<^<()(?R){2}>\z|\1\Q^<()(?R){2}>\z|\1\Q>

在这里尝试。(但是/显示为Regex101的分隔符。)

请不要在Regex101页面上进行不必要的编辑(更新)。如果您的编辑实际上并不涉及改进,尝试或测试此正则表达式,则可以对其进行分叉或从其主页创建新的正则表达式。

该版本在Regex101(44字节)上可以更正确地工作:

/^\/()(?R){2}\/\z|\1\Q^\/()(?R){2}\/\z|\1\Q/

在这里尝试。

这比原始版本要简单得多,并且工作起来更像传统的藜。它尝试不使用字符串就定义一个字符串,并在其他地方使用它。因此,可以将其放置在非常接近正则表达式的一端,以减少需要更多字符来定义匹配模式并重复多次的字符数。

说明:

  • \Q^\/()(?R){2}\/\z|\1\Q匹配字符串^\/()(?R){2}\/\z|\1\Q。这使用了一个\Q...\E不需要关闭的怪癖,而未转义的定界符在中起作用\Q。这使得某些以前的版本只能在Regex101上运行,而不能在本地运行。但是幸运的是最新版本有效,并且我使用此版本获得了更多字节。
  • \1\Q与捕获的组1匹配之前。由于此选项中不存在组1,因此只能在递归调用中进行匹配。在递归调用中,它匹配空字符串。
  • (?R){2}递归调用整个正则表达式两次,^\/()(?R){2}\/\z|\1\Q每次都匹配。
  • () 除了将空字符串捕获到组1中之外,不会执行任何其他操作,这将启用递归调用中的另一个选项。
  • ^\/()(?R){2}\/\z(?R){2}从头到尾与添加的定界符匹配。在\/之前的递归调用还确保这个选项本身并不在递归调用匹配,因为它不会在该字符串的开头。

51个字节,已关闭\Q...\E

/\QE\1|^\/(\\)Q(?R){2}z\/\E\1|^\/(\\)Q(?R){2}z\/\z/

在这里尝试。

原始版本,188字节

感谢MartinBüttner打高尔夫球约100个字节!

/^(?=.{173}\Q\2\)){2}.{11}$\E\/\z)((?=(.2.|))\2\/\2\^\2\(\2\?=\2\.\2\{173}\2\\Q\2\\2\2\\\2\)\2\)\2\{2}\2\.\2\{11}\2\$\2\\E\2\\\2\/\2\\z\2\)\2\(\2\(\2\?=\2\(\2\.2\2\.\2\|\2\)\2\)){2}.{11}$/

在这里尝试。

或210个字节,不包含\Q...\E

/^(?=.{194}\\2\\.\)\{2}\.\{12}\$\/D$)((?=(.2.|))\2\/\2\^\2\(\2\?=\2\.\2\{194}\2\\\2\\2\2\\\2\\\2\.\2\\\2\)\2\\\2\{2}\2\\\2\.\2\\\2\{12}\2\\\2\$\2\\\2\/D\2\$\2\)\2\(\2\(\2\?=\2\(\2\.2\2\.\2\|\2\)\2\)){2}.{12}$/D

在这里尝试。

扩展版本:

/^(?=.{173}\Q\2\)){2}.{11}$\E\/\z)        # Match things near the end.
((?=(.2.|))                               # Capture an empty string or \2\ into group 2.
   \2\/\2\^\2\(\2\?=\2\.\2\{173}\2\\Q\2\\2\2\\\2\)\2\)\2\{2}\2\.
   \2\{11}\2\$\2\\E\2\\\2\/\2\\z\2\)      # 1st line escaped.
   \2\(\2\(\2\?=\2\(\2\.2\2\.\2\|\2\)\2\) # 2nd line escaped.
){2}
.{11}$/x

像扩展(?=\1取得了所谓的“正规”的表述不再普通,这也使得基内斯可能。反向引用不是常规的,但提前。

说明:

  • 我用来\2\代替\转义特殊字符。如果\2匹配空字符串,\2\x(其中x是一个特殊字符)匹配其x自身。如果\2匹配\2\,则\2\x匹配转义的那一个。\2组1的两次匹配中的正则表达式可以不同。第一次\2应匹配空字符串,第二次应匹配\2\
  • \Q\2\)){2}.{11}$\E\/\z(第1行)从末尾匹配15个字符。和.{11}$(第7行)从末尾(或尾随换行符之前)匹配11个字符。因此,第二个模式之前的模式必须与第一个模式中的前4个或3个字符\2\.\2\|\2\)\2\)匹配,因此必须匹配...\2\)...\2\。不能有结尾的换行符,因为最后一个字符应该是)。并且匹配的文字)在最右边的文字之前不包含其他文字,因此所有其他字符都必须在中\2\2定义为(.2.|),因此只能为\2\
  • 第一行使整个表达式精确匹配188个字符,因为所有内容的长度都是固定的。组1的两次匹配45 * 2个字符加29次\2。第1组之后的内容匹配11个字符。因此,两次的总长度\2必须恰好是3个字符。\2第二次知道是3个字符长,第一次必须为空。
  • 除了前瞻和以外的所有内容都是第\21组中的文字。\2已知两次,并且从第一行知道了最后几个字符,此正则表达式恰好匹配一个字符串。
  • 马丁·布特纳(MartinBüttner)提出了使用先行捕捉第二组并将其与奎纳部分重叠的想法。这删除了第1组两次之间未以常规方式逃脱的字符,并帮助避免了与我的原始版本中的字符匹配的模式,并大大简化了正则表达式。

不带递归或反向引用的正则表达式,85字节

有人可能会争辩说,具有递归或反向引用的表达式不是真正的“常规”表达式。但是仅具有超前性的表达式仍只能匹配正则语言,尽管如果用传统正则表达式表达的话可能更长。

/(?=.*(\QE\\){2}z\/\z)^\/\(\?\=\.\*\(\\Q.{76}\E\\){2}z\/\z)^\/\(\?\=\.\*\(\\Q.{76}\z/

在这里尝试。

610个字节\Q...\E(不打高尔夫球):

/^(?=.{610}$)(?=.{71}(\(\.\{8\}\)\?\\.[^(]*){57}\)\{2\}\.\{12\}\$\/D$)((.{8})?\/(.{8})?\^(.{8})?\((.{8})?\?=(.{8})?\.(.{8})?\{610(.{8})?\}(.{8})?\$(.{8})?\)(.{8})?\((.{8})?\?=(.{8})?\.(.{8})?\{71(.{8})?\}(.{8})?\((.{8})?\\(.{8})?\((.{8})?\\(.{8})?\.(.{8})?\\(.{8})?\{8(.{8})?\\(.{8})?\}(.{8})?\\(.{8})?\)(.{8})?\\(.{8})?\?(.{8})?\\(.{8})?\\(.{8})?\.(.{8})?\[(.{8})?\^(.{8})?\((.{8})?\](.{8})?\*(.{8})?\)(.{8})?\{57(.{8})?\}(.{8})?\\(.{8})?\)(.{8})?\\(.{8})?\{2(.{8})?\\(.{8})?\}(.{8})?\\(.{8})?\.(.{8})?\\(.{8})?\{12(.{8})?\\(.{8})?\}(.{8})?\\(.{8})?\$(.{8})?\\(.{8})?\/D(.{8})?\$(.{8})?\)(.{8})?\(){2}.{12}$/D

在这里尝试。

这个想法是相似的。

/^(?=.{610}$)(?=.{71}(\(\.\{8\}\)\?\\.[^(]*){57}\)\{2\}\.\{12\}\$\/D$)
((.{8})?\/(.{8})?\^(.{8})?\((.{8})?\?=(.{8})?\.(.{8})?\{610(.{8})?\}(.{8})?\$(.{8})?\)
(.{8})?\((.{8})?\?=(.{8})?\.(.{8})?\{71(.{8})?\}
  (.{8})?\((.{8})?\\(.{8})?\((.{8})?\\(.{8})?\.(.{8})?\\(.{8})?\{8(.{8})?\\(.{8})?\}
    (.{8})?\\(.{8})?\)(.{8})?\\(.{8})?\?(.{8})?\\(.{8})?\\
    (.{8})?\.(.{8})?\[(.{8})?\^(.{8})?\((.{8})?\](.{8})?\*(.{8})?\)(.{8})?\{57(.{8})?\}
  (.{8})?\\(.{8})?\)(.{8})?\\(.{8})?\{2(.{8})?\\(.{8})?\}
  (.{8})?\\(.{8})?\.(.{8})?\\(.{8})?\{12(.{8})?\\(.{8})?\}
  (.{8})?\\(.{8})?\$(.{8})?\\(.{8})?\/D(.{8})?\$(.{8})?\)(.{8})?\(){2}.{12}$/D

基本正则表达式

如果不允许前瞻,那么我现在能做的就是:

/\\(\\\(\\\\){2}/

哪个匹配

\\(\\\(\\

如果{m,n}不允许使用量词,那是不可能的,因为没有什么可以匹配一个字符串,也不能匹配比其更长的字符串。当然,人们仍然可以发明\q只匹配的东西/\q/,并且仍然用该正则表达式来表达。但是显然,主要的实现都不能支持这种情况。


5
令人印象深刻。我花了一段时间尝试使它与其他匹配,但没有成功。
primo 2014年

76
人怎么会(地狱)产生这样的东西?
xem 2014年

61
这应该是该网站上投票率最高的答案。
Cruncher 2014年

44
这是我见过的最荒谬,不可思议的事情。
Alex A.

22
有人发布了此信息,因此我一天获得49票赞成票……
jimmy23013 '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.