Regex chỉ phù hợp với chính nó


339

Có một số thử thách khá thú vị ngoài kia liên quan đến regex (regex tự khớp , regex xác thực regex )

Điều này cũng có thể là không thể, nhưng có một regex nào CHỈ khớp với chính nó không?

LƯU Ý, các dấu phân cách phải được bao gồm:

ví dụ /thing/phải phù hợp /thing/và không thing. Sự phù hợp duy nhất có thể cho biểu thức của bạn phải là chính biểu thức đó. Nhiều ngôn ngữ cho phép thực hiện một chuỗi ở vị trí của biểu thức chính quy. Ví dụ trong Go

package main

import "fmt"
import "regexp"

func main() {

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

nhưng vì lợi ích của thách thức, hãy để biểu thức được phân định (biểu tượng bắt đầu, biểu thức, biểu tượng kết thúc ex: /fancypantpattern/hoặc @[^2048]@), nếu bạn muốn tranh luận các trích dẫn là dấu phân cách của bạn, vì vậy hãy là nó. Tôi nghĩ với sự khó khăn rõ ràng của vấn đề này, nó sẽ không tạo ra nhiều sự khác biệt.

Để giúp bạn cùng:

Hack nhanh tôi kết hợp với rubular.com (một trang web để chỉnh sửa regy ruby):

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;

Mặc dù đây là về mặt kỹ thuật 'mã golf', tôi sẽ rất ấn tượng nếu bất cứ ai có thể tìm thấy câu trả lời / chứng minh điều đó là không thể.

Liên kết hiện đã được sửa. Xin lỗi tất cả

Chiến thắng câu trả lời cho đến nay: jimmy23013 với 40 ký tự


3
Rõ ràng bất kỳ biểu thức chính quy nào chỉ bao gồm nghĩa đen sẽ hoạt động: //, / a /, / xyz /, v.v. Có thể tốt khi yêu cầu regex phải bao gồm một hoạt động phi chữ.
hộp bánh mì

9
nghĩa đen sẽ không hoạt động vì bạn bắt buộc phải khớp với dấu gạch chéo ngược chẳng hạn / aaa / sẽ khớp aaanhưng không / aaa /
Dylan Madisetti

2
@DylanMadisetti Chúng ta có phải sử dụng //dấu phân cách hay chúng ta có thể chọn các dấu phân cách khác (PCRE hỗ trợ khá nhiều ký tự và đặc biệt là bạn có thể sử dụng dấu ngoặc đơn / dấu ngoặc / dấu ngoặc làm dấu phân cách).
Martin Ender

3
Tôi nghĩ rằng đây là một vấn đề toán học / tính toán khá hay và bằng chứng có thể không dễ dàng ... Nhiều định lý quan trọng bắt đầu chỉ là một câu hỏi đơn giản để chơi, vì vậy có thể trong 5 năm nữa sẽ có bài viết trên wikipedia "Vấn đề Madisetti";)
Paweł Tokarz

3
Đúng chính xác. Trong một số ngôn ngữ (nghĩ grep in bash), dấu phân cách thực chất là một chuỗi rỗng. Vì vậy, giả sử rằng regrec yêu cầu các dấu phân cách đã sai ngay từ đầu. Thật vậy, vì grep là một trong những triển khai sớm nhất của regrec, định nghĩa chính tắc của regrec không có dấu phân cách. Biểu hiện sai nhất của giả định này là PHP yêu cầu hai dấu phân cách: "//"
slebetman

Câu trả lời:


590

Hương vị PCRE, 261 289 210 184 127 109 71 53 51 44 40 byte

Vâng, nó là có thể!

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

Hãy thử nó ở đây. (Nhưng /được hiển thị là dấu phân cách trên Regex101.)

Vui lòng không thực hiện các chỉnh sửa (cập nhật) không cần thiết trên trang Regex101. Nếu chỉnh sửa của bạn không thực sự liên quan đến việc cải thiện, thử hoặc kiểm tra biểu thức chính quy này, bạn có thể rẽ nhánh hoặc tạo bản mới từ trang chủ của họ .

Phiên bản hoạt động chính xác hơn trên Regex101 (44 byte):

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

Hãy thử nó ở đây.

Điều này đơn giản hơn nhiều so với phiên bản gốc và hoạt động giống như một chiếc quine truyền thống. Nó cố gắng xác định một chuỗi mà không sử dụng nó và sử dụng nó ở một nơi khác. Vì vậy, nó có thể được đặt rất gần với một đầu của biểu thức chính quy, để giảm số lượng ký tự cần nhiều ký tự để xác định mẫu phù hợp và lặp lại nhiều lần hơn.

Giải thích:

  • \Q^\/()(?R){2}\/\z|\1\Qphù hợp với chuỗi ^\/()(?R){2}\/\z|\1\Q. Điều này sử dụng một cách giải quyết mà \Q...\Ekhông cần phải đóng, và các dấu phân cách không được giải quyết hoạt động \Q. Điều này làm cho một số phiên bản trước chỉ hoạt động trên Regex101 chứ không phải cục bộ. Nhưng may mắn thay, phiên bản mới nhất đã hoạt động và tôi đã sử dụng thêm một số byte bằng cách này.
  • \1trước khi \Qkhớp với nhóm bị bắt 1. Vì nhóm 1 không tồn tại trong tùy chọn này, nên nó chỉ có thể khớp trong các cuộc gọi đệ quy. Trong các cuộc gọi đệ quy, nó khớp với các chuỗi rỗng.
  • (?R){2}gọi toàn bộ regex đệ quy hai lần, khớp ^\/()(?R){2}\/\z|\1\Qcho mỗi lần.
  • () không làm gì ngoài việc bắt một chuỗi rỗng vào nhóm 1, cho phép tùy chọn khác trong các cuộc gọi đệ quy.
  • ^\/()(?R){2}\/\zphù hợp (?R){2}với dấu phân cách được thêm vào, từ đầu đến cuối. Các \/trước khi cuộc gọi đệ quy cũng chắc chắn rằng tùy chọn này tự nó không phù hợp trong các cuộc gọi đệ quy, bởi vì nó sẽ không được vào đầu của chuỗi.

51 byte đã đóng \Q...\E:

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

Hãy thử nó ở đây.

Phiên bản gốc, 188 byte

Cảm ơn Martin Büttner vì đã chơi golf khoảng 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}$/

Hãy thử nó ở đây.

Hoặc 210 byte mà không có \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

Hãy thử nó ở đây.

Phiên bản mở rộng:

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

Các phần mở rộng thích (?=\1đã làm cho các biểu thức được gọi là "thông thường" không còn thường xuyên, điều này cũng làm cho các quine có thể. Backreference không thường xuyên, nhưng nhìn là được.

Giải trình:

  • Tôi sử dụng \2\thay thế \để thoát khỏi các nhân vật đặc biệt. Nếu \2khớp với chuỗi trống, \2\x(nơi xlà một ký tự đặc biệt) khớp với xchính nó. Nếu \2phù hợp \2\, \2\xphù hợp với một người thoát. \2trong hai trận đấu của nhóm 1 có thể khác nhau về regex. Trong lần đầu tiên \2phải khớp với chuỗi trống và lần thứ hai \2\.
  • \Q\2\)){2}.{11}$\E\/\z(dòng 1) khớp với 15 ký tự từ cuối. Và .{11}$(dòng 7) khớp với 11 ký tự ở cuối (hoặc trước một dòng mới). Vì vậy, mẫu ngay trước mẫu thứ hai phải khớp với 4 hoặc 3 ký tự đầu tiên trong mẫu thứ nhất, do đó \2\.\2\|\2\)\2\)phải khớp ...\2\)hoặc ...\2\. Không thể có một dòng mới vì ký tự cuối cùng phải có ). Và văn bản phù hợp không chứa văn bản khác )trước văn bản ngoài cùng bên phải, vì vậy tất cả các ký tự khác phải nằm trong \2. \2được định nghĩa là (.2.|), vì vậy nó chỉ có thể được \2\.
  • Dòng đầu tiên làm cho toàn bộ biểu thức khớp chính xác với 188 ký tự vì mọi thứ đều có độ dài cố định. Hai lần của nhóm 1 khớp với 45 * 2 ký tự cộng với 29 lần \2. Và những thứ sau nhóm 1 khớp với 11 ký tự. Vì vậy, tổng độ dài của hai lần \2phải chính xác là 3 ký tự. Biết \2lần thứ hai dài 3 ký tự, lần đầu tiên phải trống.
  • Tất cả mọi thứ ngoại trừ giao diện và \2là chữ trong nhóm 1. Với hai lần \2được biết đến và một vài ký tự cuối cùng được biết từ dòng đầu tiên, regex này khớp chính xác với một chuỗi.
  • Martin Büttner nảy ra ý tưởng sử dụng lookahead để chụp nhóm 2 và làm cho nó trùng lặp với phần quine. Điều này đã loại bỏ các ký tự không thoát theo cách thông thường giữa hai lần của nhóm 1 và giúp tránh mô hình khớp với chúng trong phiên bản gốc của tôi và đơn giản hóa regex rất nhiều.

Regex không thu hồi hoặc phản hồi, 85 byte

Ai đó có thể lập luận rằng các biểu thức với sự thu hồi hoặc phản hồi không phải là biểu thức "thông thường" thực sự. Nhưng các biểu thức chỉ có giao diện vẫn có thể chỉ khớp với các ngôn ngữ thông thường, mặc dù chúng có thể dài hơn nhiều nếu được biểu thị bằng các biểu thức thông thường truyền thống.

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

Hãy thử nó ở đây.

610 byte mà không có \Q...\E(để được đánh gôn):

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

Hãy thử nó ở đây.

Ý tưởng là tương tự.

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

Biểu thức chính quy cơ bản

Nếu lookahead không được phép, điều tốt nhất tôi có thể làm bây giờ là:

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

phù hợp với

\\(\\\(\\

Nếu {m,n}định lượng không được phép, điều đó là không thể bởi vì không có gì chỉ có thể khớp với một chuỗi, có thể khớp với một chuỗi dài hơn chính nó. Tất nhiên người ta vẫn có thể phát minh ra thứ gì đó giống như \qchỉ khớp /\q/và vẫn nói biểu thức với thông thường đó. Nhưng rõ ràng không có gì như thế này được hỗ trợ bởi các triển khai lớn.


5
Ấn tượng. Tôi đã dành một thời gian cố gắng để làm cho nó phù hợp với một cái gì đó khác, để không thành công.
primo

76
Làm thế nào (địa ngục) một con người có thể tạo ra một điều như vậy?
xem

61
Đây xứng đáng là câu trả lời được bình chọn cao nhất trên trang web này.
Cruncher

44
Đây là điều ngớ ngẩn nhất, đáng kinh ngạc nhất mà tôi từng thấy.
Alex A.

22
Ai đó đã tweet bài đăng này để tôi nhận được 49 lượt upvote trong một ngày ...
jimmy23013
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.