自分自身にのみ一致する正規表現


339

正規表現に関連するかなりクールな課題がいくつかあります(自己一致正規表現正規表現検証正規表現

これはおそらく不可能かもしれませんが、それ自体にのみ一致する正規表現はありますか?

注:区切り文字を含める必要があります。

例えば/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編集用のWebページ)にまとめたクイックハック:

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 /などが機能します。正規表現に非リテラル演算を含める必要があることを要求するのは良いことです。
ブレッドボックス

9
リテラルを使用すると、たとえば/ AAAのためにバックスラッシュを一致させるために必要としているので、一致する/動作しませんaaaではなく、/ AAA /
ディランMadisetti

2
@DylanMadisetti //区切り文字を使用する必要がありますか、それとも他の区切り文字を選択できますか(PCREはほとんどすべての文字をサポートし、特に、一致した括弧/括弧/括弧を区切り文字として使用できます)。
マーティンエンダー

3
私はこれは非常に素晴らしい数学/計算上の問題であり、その証明は簡単ではないかもしれないと思います...多くの重要な定理は遊ぶための単純な質問として始まったので、おそらく5年後にウィキペディアの記事「マディセッティ問題」があります;)
パウェウトカルツ

3
はい、正確に。一部の言語(bashでgrepを考える)では、区切り文字は本質的に空の文字列です。したがって、正規表現に区切り文字が必要であると仮定すると、そもそもすでに間違っています。実際、grepはregexpの最も初期の実装の1つであるため、正規表現の正規定義には区切り文字がありません。この仮定のwrongest症状は2つの区切り文字を必要とPHPです"//"
slebetman

回答:


590

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}正規表現全体を再帰的に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バイト

約100バイトのゴルフをしてくれたMartinBüttnerに感謝します!

/^(?=.{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\xx特殊文字は)は、xそれ自体に一致します。場合は\2マッチ\2\\2\xエスケープしたものと一致します。\2グループ1の2つの一致では、正規表現が異なる場合があります。1回\2目は空の文字列に一致し、2回目は一致する必要があります\2\
  • \Q\2\)){2}.{11}$\E\/\z(1行目)は、末尾から15文字に一致します。及び.{11}$(ライン7)の端部から11個の文字に一致する(または末尾の改行の前に)。したがって、2番目のパターンの直前のパターンは、最初のパターンの最初の4文字または3文字に\2\.\2\|\2\)\2\)一致する必要があるため、...\2\)またはに一致する必要があり...\2\ます。最後の文字はである必要があるため、末尾の改行は使用できません)。一致したテキストには)、右端のテキストの前に別のテキストが含まれていないため、他のすべての文字はになければなりません\2\2はと定義されている(.2.|)ため、のみ指定できます\2\
  • 最初の行では、すべてが固定長であるため、式全体が188文字と正確に一致します。グループ1の2回は、45 * 2文字と29回に一致し\2ます。そして、グループ1の後のものは11文字に一致します。したがって、2回の合計の長さは\2正確に3文字でなければなりません。知って\2二度目にすると、3文字の長さ、それは最初に空でなければなりません。
  • 先読みを除くすべて\2はグループ1のリテラルです。\2最初の行で2回認識され、最後の数文字が認識されると、この正規表現は1つの文字列に一致します。
  • MartinBüttnerは、lookaheadを使用してグループ2をキャプチャし、クィーンパートとオーバーラップさせるというアイデアを思いつきました。これにより、グループ1の2回の間に通常の方法でエスケープされない文字が削除され、元のバージョンでパターンと一致するパターンを回避し、正規表現を大幅に簡素化しました。

再帰または後方参照のない正規表現、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}量指定子が許可されていない場合、1つの文字列のみに一致するものは何もなく、それ自体より長い文字列に一致する可能性があるため、不可能です。もちろん、\q一致するものだけを作成することもでき/\q/、その正規表現で表現することもできます。しかし、明らかにこのようなものは主要な実装ではサポートされていません。


5
印象的。私はそれを他の何かにマッチさせようとしてしばらくして、成功しなかった。
プリモ14年

76
どのように(地獄)人間はそのようなものを作り出すことができますか?
xem 14年

61
これは、このサイトで最高の投票に値するに値する。
ランチャー14年

44
これは私が今まで見た中で最も馬鹿げた、信じられないほどのことです。
アレックスA.

22
誰かがこの投稿をツイートしたので、1日で49の賛成票を獲得しました
...-jimmy23013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.