Regex yang hanya cocok dengan dirinya sendiri

339

Ada beberapa tantangan keren yang melibatkan regex ( Self-matching regex , Regex validate regex )

Ini mungkin tidak mungkin, tetapi adakah regex yang HANYA cocok dengan dirinya sendiri?

CATATAN, pembatas harus disertakan:

misalnya /thing/harus cocok /thing/dan tidak thing. Satu-satunya kecocokan yang mungkin untuk ekspresi Anda haruslah ekspresi itu sendiri. Banyak bahasa memungkinkan implementasi string menggantikan ekspresi reguler. Misalnya di Go

package main

import "fmt"
import "regexp"

func main() {

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

tetapi demi tantangan, biarkan ekspresi dibatasi (simbol awal, ekspresi, simbol akhir ex: /fancypantpattern/atau @[^2048]@), jika Anda ingin memperdebatkan tanda kutip sebagai pembatas Anda, maka jadilah itu. Saya pikir mengingat kesulitan yang tampak dari masalah ini, itu tidak akan membuat banyak perbedaan.

Untuk membantu Anda:

Peretasan cepat saya buat untuk rubular.com (halaman web untuk mengedit 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;

Walaupun ini secara teknis 'kode golf' saya akan sangat terkesan jika ada yang bisa menemukan jawaban / membuktikan itu tidak mungkin.

Tautan sekarang diperbaiki. Maaf untuk semua

Jawaban yang menang sejauh ini: jimmy23013 dengan 40 karakter

Dylan Madisetti
sumber
3
Tentunya setiap ekspresi reguler yang hanya menyertakan literal akan berfungsi: //, / a /, / xyz /, dll. Mungkin baik untuk mengharuskan regex harus menyertakan operasi non-literal.
kotak roti
9
literal tidak akan berfungsi karena Anda diharuskan mencocokkan backslash misalnya / aaa / akan cocok aaatetapi tidak / aaa /
Dylan Madisetti
2
@DylanMadisetti Apakah kita harus menggunakan //pembatas, atau dapatkah kita memilih pembatas lainnya (PCRE mendukung hampir semua karakter, dan khususnya Anda dapat menggunakan kurung / kurung / kurung yang cocok sebagai pembatas).
Martin Ender
3
Saya pikir ini masalah matematika / komputasi yang cukup bagus dan buktinya mungkin tidak mudah ... Banyak teorema penting dimulai hanya dengan pertanyaan sederhana untuk dimainkan, jadi mungkin dalam 5 tahun akan ada artikel wikipedia "Masalah Madisetti";)
Paweł Tokarz
3
Ya persis. Dalam beberapa bahasa (pikirkan grep dalam bash) pembatas pada dasarnya adalah string kosong. Jadi dengan asumsi bahwa regexp membutuhkan pembatas sudah salah sejak awal. Memang, karena grep adalah salah satu implementasi awal regexp, definisi kanonik regexp tidak memiliki pembatas. Manifestasi yang keliru dari asumsi ini adalah PHP yang membutuhkan dua pembatas: "/dan/"
slebetman

Jawaban:

590

Rasa PCRE, 261 289 210 184 127 109 71 53 51 44 40 byte

Ya itu mungkin!

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

Coba di sini. (Tetapi /ditampilkan sebagai pembatas pada Regex101.)

Harap jangan melakukan pengeditan (pembaruan) yang tidak perlu pada halaman Regex101. Jika pengeditan Anda tidak benar-benar melibatkan peningkatan, mencoba atau menguji regex ini, Anda dapat memotongnya atau membuat yang baru dari beranda mereka .

Versi ini berfungsi lebih baik pada Regex101 (44 byte):

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

Coba di sini.

Ini jauh lebih sederhana daripada versi aslinya dan berfungsi lebih seperti quine tradisional. Mencoba mendefinisikan string tanpa menggunakannya, dan menggunakannya di tempat yang berbeda. Jadi itu dapat ditempatkan sangat dekat dengan salah satu ujung regex, untuk mengurangi jumlah karakter yang membutuhkan lebih banyak karakter untuk menentukan pola yang cocok dan diulang lebih banyak kali.

Penjelasan:

  • \Q^\/()(?R){2}\/\z|\1\Qcocok dengan string ^\/()(?R){2}\/\z|\1\Q. Ini menggunakan kekhasan yang \Q...\Etidak harus ditutup, dan pembatas yang tidak terhindar bekerja \Q. Ini membuat beberapa versi sebelumnya hanya berfungsi pada Regex101 dan tidak secara lokal. Tapi untungnya versi terbaru berfungsi, dan saya bermain golf beberapa byte lagi menggunakan ini.
  • \1sebelum \Qmencocokkan grup yang ditangkap 1. Karena grup 1 tidak ada dalam opsi ini, itu hanya dapat cocok dengan panggilan rekursif. Dalam panggilan rekursif cocok dengan string kosong.
  • (?R){2}memanggil seluruh regex secara rekursif dua kali, yang cocok ^\/()(?R){2}\/\z|\1\Quntuk setiap kali.
  • () tidak melakukan apa pun selain menangkap string kosong ke grup 1, yang memungkinkan opsi lain dalam panggilan rekursif.
  • ^\/()(?R){2}\/\zcocok (?R){2}dengan pembatas ditambahkan, dari awal hingga akhir. The \/sebelum panggilan rekursif juga memastikan pilihan ini sendiri tidak cocok dalam panggilan rekursif, karena tidak akan berada di awal string.

51 byte dengan ditutup \Q...\E:

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

Coba di sini.

Versi asli, 188 byte

Terima kasih kepada Martin Büttner untuk bermain golf sekitar 100 byte!

/^(?=.{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}$/

Coba di sini.

Atau 210 byte tanpa \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

Coba di sini.

Versi yang diperluas:

/^(?=.{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

Ekstensi menyukai (?=dan \1telah membuat apa yang disebut ekspresi "reguler" tidak lagi teratur, yang juga memungkinkan quines. Backreference tidak teratur, tetapi lookahead adalah.

Penjelasan:

  • Saya menggunakan \2\di tempat \untuk melarikan diri karakter khusus. Jika \2cocok dengan string kosong, \2\x(di mana xkarakter khusus) cocok dengan xdirinya sendiri. Jika \2cocok \2\, \2\xcocok dengan yang lolos. \2dalam dua pertandingan grup 1 dapat berbeda di regex. Pertama kali \2harus cocok dengan string kosong, dan yang kedua kalinya \2\.
  • \Q\2\)){2}.{11}$\E\/\z(baris 1) cocok dengan 15 karakter dari akhir. Dan .{11}$(baris 7) cocok dengan 11 karakter dari akhir (atau sebelum baris baru). Jadi pola tepat sebelum pola kedua harus cocok dengan 4 atau 3 karakter pertama dalam pola pertama, jadi \2\.\2\|\2\)\2\)harus cocok ...\2\)atau ...\2\. Tidak boleh ada trailing newline karena karakter terakhir seharusnya ). Dan teks yang cocok tidak mengandung yang lain )sebelum yang paling kanan, jadi semua karakter lain harus dalam \2. \2didefinisikan sebagai (.2.|), jadi itu hanya bisa \2\.
  • Baris pertama membuat seluruh ekspresi cocok dengan 188 karakter karena semuanya memiliki panjang tetap. Dua kali grup 1 cocok dengan 45 * 2 karakter plus 29 kali \2. Dan hal-hal setelah grup 1 cocok dengan 11 karakter. Jadi total panjang dua kali \2harus tepat 3 karakter. Mengetahui \2untuk yang kedua kali adalah 3 karakter, itu harus kosong untuk pertama kalinya.
  • Semuanya kecuali lookahead dan \2literal dalam grup 1. Dengan dua kali \2dikenal, dan beberapa karakter terakhir yang diketahui dari baris pertama, regex ini sama persis dengan satu string.
  • Martin Büttner datang dengan ide menggunakan lookahead untuk menangkap grup 2 dan membuatnya tumpang tindih dengan bagian quine. Ini menghapus karakter yang tidak lolos dengan cara normal antara dua kali grup 1, dan membantu menghindari pola yang cocok dengan mereka dalam versi asli saya, dan banyak menyederhanakan regex.

Regex tanpa rekursi atau referensi, 85 byte

Seseorang mungkin berpendapat bahwa ekspresi dengan rekursi atau referensi-ulang bukanlah ekspresi "reguler" yang sesungguhnya. Tetapi ekspresi dengan hanya lookahead masih bisa hanya cocok dengan bahasa biasa, meskipun mereka mungkin jauh lebih lama jika diungkapkan oleh ekspresi reguler tradisional.

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

Coba di sini.

610 byte tanpa \Q...\E(untuk di-golf):

/^(?=.{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

Coba di sini.

Idenya serupa.

/^(?=.{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

Ekspresi reguler dasar

Jika lookahead tidak diizinkan, yang terbaik yang bisa saya lakukan sekarang adalah:

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

yang cocok

\\(\\\(\\

Jika {m,n}kuantifier tidak diizinkan, tidak mungkin karena tidak ada yang hanya bisa cocok dengan satu string, dapat mencocokkan string lebih lama dari itu sendiri. Tentu saja seseorang masih dapat menemukan sesuatu \qyang hanya cocok /\q/, dan masih mengatakan ekspresi dengan itu secara teratur. Namun ternyata tidak ada yang seperti ini yang didukung oleh implementasi besar.

jimmy23013
sumber
5
Impresif. Saya menghabiskan waktu mencoba untuk mencocokkannya dengan sesuatu yang lain, tidak berhasil.
Primo
76
bagaimana (sih) manusia bisa menghasilkan hal seperti itu?
xem
61
Ini pantas menjadi jawaban dengan suara terbanyak di situs ini.
Cruncher
44
Ini adalah hal yang paling tidak masuk akal, luar biasa yang pernah saya lihat.
Alex A.
22
Seseorang tweeted posting ini jadi saya mendapat 49 upvotes dalam sehari ...
jimmy23013