Регекс, який відповідає лише собі


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;

Хоча технічно це «кодовий гольф», я буду дуже вражений, якщо хтось може знайти відповідь / довести, що це неможливо.

Тепер посилання виправлено. Вибачте всім

Досі виграшна відповідь: jimmy23013 з 40 символами


3
Очевидно, що будь-який регулярний вираз, що включає лише літерали, спрацює: //, / a /, / xyz / тощо. Можливо, було б добре вимагати, щоб регулярний вираз включав нелітеральну операцію.
хлібниця

9
літерали не працюватимуть, тому що вам потрібно відповідати зворотній косої риси, наприклад / aaa / буде відповідати, aaaале не / aaa /
Ділан Мадісетті

2
@DylanMadisetti Чи потрібно використовувати //роздільники, чи ми можемо вибрати інші роздільники (PCRE підтримує будь-який символ, зокрема, ви можете використовувати відповідні дужки / дужки / дужки як роздільники).
Мартін Ендер

3
Я думаю, що це досить приємна математична / обчислювальна проблема, і доведення може бути непростим ... Багато важливих теорем почалося як просто просте питання, тому, можливо, через 5 років з’явиться стаття у Вікіпедії "Проблема Мадісетті";)
Paweł Tokarz

3
Так, саме. У деяких мовах (думаю, греп в басі) роздільник є по суті порожнім рядком. Тож припускаючи, що для регулярного вираження потрібні роздільники, в першу чергу неправильно. Дійсно, оскільки grep є однією з найбільш ранніх втілення regexp, канонічне визначення regexp не має обмежувачів. Найсильнішим проявом цього припущення є PHP, для якого потрібні два роздільники: "/і/"
slebetman

Відповіді:


589

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 байт

Дякуємо Мартіну Бюттнеру за те, що він зіграв близько 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роблять так звані "регулярні" вирази вже не регулярними, що також робить quines можливими. Зворотний зв'язок не є регулярним, але вигляд є.

Пояснення:

  • Я використовую \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 символи, він повинен бути вперше порожнім.
  • Все, окрім lookahead, \2є літералами групи 1. З двох \2відомих разів та останніх кількох символів, відомих з першого рядка, цей регулярний виразок відповідає рівно одному рядку.
  • Мартін Бюттнер придумав ідею використати lookahead для захоплення групи 2 та перекриття її частиною quine. Це видалило символів, які не вийшли нормальним способом між двома часами групи 1, і допомогло уникнути шаблону, щоб він відповідав їм у моїй оригінальній версії, і значно спростив регулярний вираз.

Регекс без рекурсій і зворотних посилань, 85 байт

Хтось може стверджувати, що вирази з рекурсіями або зворотними посиланнями не є справжніми "регулярними" виразами. Але вирази лише з lookahead можуть як і раніше відповідати лише звичайним мовам, хоча вони можуть бути набагато довшими, якщо виражатись традиційними регулярними виразами.

/(?=.*(\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
Вражає. Я витратив деякий час, намагаючись змусити його відповідати чомусь іншому, не маючи успіху.
примо

76
як (пекло) могла людина виробити таке?
xem

61
Це заслуговує на найкращу відповідь на цьому сайті.
Cruncher

44
Це найбезглуздіше, неймовірніше, що я бачив.
Олексій А.

22
Хтось написав цю публікацію, тому я отримав 49 оновлень за день ...
jimmy23013
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.