Golf meta regex


29

Theo tinh thần của xkcd này

nhập mô tả liên kết ở đây

Viết chương trình chơi golf regex với các cặp danh sách tùy ý. Chương trình ít nhất nên cố gắng rút ngắn regex, một chương trình chỉ xuất ra /^(item1|item2|item3|item4)$/hoặc tương tự là không được phép.

Ghi điểm dựa trên khả năng tạo regex ngắn nhất. Danh sách kiểm tra là danh sách các ứng cử viên tổng thống Mỹ thành công và không thành công, được tìm thấy ở đây (cảm ơn @Peter). Tất nhiên, chương trình phải hoạt động cho tất cả các danh sách rời rạc, vì vậy chỉ cần trả lại câu trả lời cho tổng thống mà người ta không tính.


3
/^item1|atem2|item3|item4$/có lẽ có quyền ưu tiên ngoài ý muốn (chuỗi phải bắt đầu bằng item1, chứa atem2, chứa item3hoặc kết thúc bằng item4).
Konrad Borowski

7
Đây sẽ là một thử thách thú vị hơn nếu nó có một hệ thống tính điểm chủ yếu dựa trên kích thước của các biểu thức được tạo.
Peter Taylor

1
Theo tinh thần của văn bản tiêu đề XKCD, các ứng cử viên tổng thống Mỹ thành công và không thành công . (NB Tôi đã lập danh sách này bằng tay theo dõi Wikipedia , do đó có thể có một số lỗi nhỏ; tôi đã xóa khỏi danh sách những người thua cuộc phù hợp với một người chiến thắng, bởi vì nếu không thì việc phân biệt các danh sách là không thể, nhưng tôi đã cố tình không bị trùng lặp) .
Peter Taylor

4
Tôi tự hỏi liệu Randall Munroe có phải là người viết các thử thách chơi gôn mã tốt hơn chúng ta không ...
Johannes Kuhn

6
Tôi tự hỏi nếu Randall Munroe sẽ ném xuống câu hỏi này.
gian hàng

Câu trả lời:


8

Perl (111 110 122 ký tự)

use Regexp::Assemble;@ARGV=shift;my$r=new Regexp::Assemble;chomp,add$r "^\Q$_\E\$"while<>;$_=as_string$r;s/\(\?:/(/g;print

Điều này sử dụng mô-đun CPAN được gọi Regexp::Assembleđể tối ưu hóa các biểu thức thông thường. Bởi vì ngôn ngữ nào tốt hơn cho các biểu thức chính quy thì Perl.

Ngoài ra, phiên bản có thể đọc được, chỉ để giải trí (được thực hiện với sự trợ giúp của -MO=Deparse).

use Regexp::Assemble;
my $r = Regexp::Assemble->new;
while (<>) {
    chomp($_);
    $r->add("^\Q$_\E\$");
}
$_ = $r->as_string;
# Replace wasteful (?:, even if it's technically correct.
s/\(\?:/(/g;
print $_;

Đầu ra mẫu (Tôi đã làm CTRL-D sau item4).

$ perl assemble.pl
item1
atem2
item3
item4
^(item[134]|atem2)$

Ngoài ra, như một phần thưởng, tôi đang viết regex cho mỗi từ trong câu hỏi.

^(a((ttemp)?t|llowed\.|rbitrary)?|\/\^item1\|atem2\|item3\|item4\$\/|s(ho(rt,|uld)|imilar)|p((air|lay)s|rogram)|(Writ|mak|Th)e|l(ists\.|east)|o([fr]|utputs)|t(h(at|e)|o)|(jus|no)t|regex|golf|with|is)$

Ngoài ra, danh sách các tổng thống (262 byte).

^(((J(effer|ack|ohn)s|W(ashingt|ils)|Nix)o|Van Bure|Lincol)n|C(l(eveland|inton)|oolidge|arter)|H(a(r(rison|ding)|yes)|oover)|M(cKinley|adison|onroe)|T(a(ylor|ft)|ruman)|R(oosevelt|eagan)|G(arfield|rant)|Bu(chanan|sh)|P(ierce|olk)|Eisenhower|Kennedy|Adams|Obama)$

Điều này xuất hiện để đọc stdin cho một danh sách và buộc danh sách kia trống. Chắc chắn đó không phải là những gì câu hỏi đang yêu cầu?
Peter Taylor

1
@PeterTaylor: Chà, danh sách thứ hai không quan trọng lắm. Trừ khi danh sách thứ hai có các bản sao của danh sách đầu tiên, biểu thức chính quy là hợp lệ. Sẽ rất tốt nếu có một bản rút gọn ngắn hơn, nhưng tôi hơi lười biếng.
Konrad Borowski

IMO ít nhất bạn nên có một cách để lấy nó làm đầu vào, ngay cả khi sau đó bạn loại bỏ nó.
Peter Taylor

@PeterTaylor: Nếu bạn nói như vậy. Chương trình của tôi bây giờ có hai đối số, một trong số đó là danh sách đầu tiên.
Konrad Borowski

4
Điều này thật tuyệt; nhưng nó tạo ra các biểu thức dài không cần thiết vì nó tạo ra loại trừ (cho bất kỳ danh sách nào khác) bằng cách khớp mọi từ đầy đủ có thể . Đó không phải là tinh thần hoàn toàn giống như golf ban đầu.
Nicole

4

Không phải giải pháp của tôi (rõ ràng tôi không phải là peter norvig!) Mà đây là một giải pháp cho câu hỏi (sửa đổi một chút) lịch sự của anh ấy: http://nbviewer.ipython.org/url/norvig.com/ipython/xkcd1313.ipynb

chương trình anh ấy đưa ra như sau (công việc của anh ấy, không phải của tôi):

def findregex(winners, losers):
    "Find a regex that matches all winners but no losers (sets of strings)."
    # Make a pool of candidate components, then pick from them to cover winners.
    # On each iteration, add the best component to 'cover'; finally disjoin them together.
    pool = candidate_components(winners, losers)
    cover = []
    while winners:
        best = max(pool, key=lambda c: 3*len(matches(c, winners)) - len(c))
        cover.append(best)
        pool.remove(best)
        winners = winners - matches(best, winners)
    return '|'.join(cover)

def candidate_components(winners, losers):
    "Return components, c, that match at least one winner, w, but no loser."
    parts = set(mappend(dotify, mappend(subparts, winners)))
    wholes = {'^'+winner+'$' for winner in winners}
    return wholes | {p for p in parts if not matches(p, losers)}

def mappend(function, *sequences):
    """Map the function over the arguments.  Each result should be a sequence. 
    Append all the results together into one big list."""
    results = map(function, *sequences)
    return [item for result in results for item in result]

def subparts(word):
    "Return a set of subparts of word, consecutive characters up to length 4, plus the whole word."
    return set(word[i:i+n] for i in range(len(word)) for n in (1, 2, 3, 4)) 

def dotify(part):
    "Return all ways to replace a subset of chars in part with '.'."
    if part == '':
        return {''}  
    else:
        return {c+rest for rest in dotify(part[1:]) for c in ('.', part[0]) }

def matches(regex, strings):
    "Return a set of all the strings that are matched by regex."
    return {s for s in strings if re.search(regex, s)}

answer = findregex(winners, losers)
answer
# 'a.a|i..n|j|li|a.t|a..i|bu|oo|n.e|ay.|tr|rc|po|ls|oe|e.a'

trong đó người thắng và người thua là danh sách người thắng và người thua tương ứng (hoặc bất kỳ 2 danh sách nào của khóa học) xem bài viết để được giải thích chi tiết.


8
Mặc dù bài viết được liên kết rất thú vị và tôi rất thích đọc nó, nhưng điều này sẽ được đăng tốt hơn như là một nhận xét về câu hỏi thay vì như một câu trả lời vì nó không trả lời câu hỏi đặt ra.
Gareth

1
Bạn nói đúng, nó có thể là một bình luận tốt hơn, tôi đã đăng nó như một câu trả lời đơn giản vì nó trả lời câu hỏi một cách hoàn hảo. Tôi đã không sao chép giải pháp vì tôi nghĩ rằng sẽ không tôn trọng và cố gắng lấy tín dụng cho ai đó làm việc, ngoài việc cung cấp một chương trình chơi golf regex với 2 cặp danh sách, nó còn cung cấp chức năng tập thể dục và mã chi tiết giải thích cùng với song song với vấn đề bao trùm mà tôi chưa xem xét. Nếu bạn vẫn nghĩ nó không liên quan, hãy cho tôi biết, tôi sẽ xóa và đăng dưới dạng nhận xét.
Mike HR

1
Nếu bạn lo lắng về việc lấy tín dụng cho công việc của người khác, hãy gắn cờ và yêu cầu một mod để đưa ra câu trả lời của bạn "Cộng đồng wiki".
Peter Taylor

1
@PeterTaylor tuyệt vời, tôi không biết đó là giao thức, đã xong.
Mike HR

2

Giải pháp của tôi viết bằng Factor :

USING:
    formatting fry
    grouping
    kernel
    math math.combinatorics math.ranges
    pcre
    sequences sets ;
IN: xkcd1313

: name-set ( str -- set )
    "\\s" split members ;

: winners ( -- set )
    "washington adams jefferson jefferson madison madison monroe
monroe adams jackson jackson vanburen harrison polk taylor pierce buchanan
lincoln lincoln grant grant hayes garfield cleveland harrison cleveland     mckinley
 mckinley roosevelt taft wilson wilson harding coolidge hoover roosevelt
roosevelt roosevelt roosevelt truman eisenhower eisenhower kennedy johnson     nixon
nixon carter reagan reagan bush clinton clinton bush bush obama obama" name-set ;

: losers ( -- set )
    "clinton jefferson adams pinckney pinckney clinton king adams
jackson adams clay vanburen vanburen clay cass scott fremont breckinridge
mcclellan seymour greeley tilden hancock blaine cleveland harrison bryan bryan
parker bryan roosevelt hughes cox davis smith hoover landon wilkie dewey dewey
stevenson stevenson nixon goldwater humphrey mcgovern ford carter mondale
dukakis bush dole gore kerry mccain romney" name-set winners diff
    { "fremont" } diff "fillmore" suffix ;

: matches ( seq regex -- seq' )
    '[ _ findall empty? not ] filter ;

: mconcat ( seq quot -- set )
    map concat members ; inline

: dotify ( str -- seq )
    { t f } over length selections [ [ CHAR: . rot ? ] "" 2map-as ] with map ;

: subparts ( str -- seq )
    1 4 [a,b] [ clump ] with mconcat ;

: candidate-components ( winners losers -- seq )
    [
        [ [ "^%s$" sprintf ] map ]
        [ [ subparts ] mconcat [ dotify ] mconcat ] bi append
    ] dip swap [ matches empty? ] with filter ;

: find-cover ( winners candidates -- cover )
    swap [ drop { } ] [
        2dup '[ _ over matches length 3 * swap length - ] supremum-by [
            [ dupd matches diff ] [ rot remove ] bi find-cover
        ] keep prefix
    ] if-empty ;

: find-regex ( winners losers -- regex )
    dupd candidate-components find-cover "|" join ;

: verify ( winners losers regex -- ? )
    swap over [
        dupd matches diff "Error: should match but did not: %s\n"
    ] [
        matches "Error: should not match but did: %s\n"
    ] 2bi* [
        dupd '[ ", " join _ printf ] unless-empty empty?
    ] 2bi@ and ;

: print-stats ( legend winners regex -- )
    dup length rot "|" join length over /
    "separating %s: '%s' (%d chars %.1f ratio)\n" printf ;

: (find-both) ( winners losers legend -- )
    -rot 2dup find-regex [ verify t assert= ] 3keep nip print-stats ;

: find-both ( winners losers -- )
    [ "1 from 2" (find-both) ] [ swap "2 from 1" (find-both) ] 2bi ;



IN: scratchpad winners losers find-both 
separating 1 from 2: 'a.a|a..i|j|li|a.t|i..n|bu|oo|ay.|n.e|ma|oe|po|rc|ls|l.v' (55 chars 4.8 ratio)
separating 2 from 1: 'go|e..y|br|cc|hu|do|k.e|.mo|o.d|s..t|ss|ti|oc|bl|pa|ox|av|st|du|om|cla|k..g' (75 chars 3.3 ratio)

Đó là thuật toán tương tự như của Norvig. Nếu làm tổn thương khả năng đọc là mục tiêu thì có lẽ bạn có thể chơi golf nhiều nhân vật hơn.


1
FYI, bạn đang thiếu một loạt những người thua cuộc trong danh sách chính thức (Burr, Jay, Badnarik, có lẽ những người khác tôi không thấy). Vì vậy, kết quả của bạn là không chính xác; ví dụ, regex đầu tiên không hoạt động, vì nó khớp với Burr và Jay.
elixenide

1

Mã của tôi không phải là kiểu chơi golf và cô đọng, nhưng bạn có thể kiểm tra nó tại https://github.com/amitayd/regapid-golf-coffeescript/ (hoặc cụ thể là thuật toán tại src / regapiGolf.coffee).

Nó dựa trên thuật toán của Peter Norvig, với hai cải tiến:

  1. Tạo các phần để sử dụng với các bộ ký tự (nghĩa là sử dụng [ab] z, [ac] z và [bc] z nếu các phần hợp lệ là az, bz và cz).
  2. Cho phép xây dựng "đường dẫn tối ưu hàng đầu" của bìa, và không chỉ là bìa được tạo từ ứng cử viên tốt nhất ở mỗi lần lặp.

(Và cũng đã ném trong một sự ngẫu nhiên tùy chọn)

Đối với các nhóm người thắng / thua trong bài kiểm tra này, tôi đã tìm thấy một biểu thức chính xác 76 ký tự bằng cách sử dụng nó:

[Jisn]e..|[dcih]..o|[AaG].a|[sro].i|T[ar]|[PHx]o|V|[oy]e|lev|sh$|u.e|rte|nle

Một số chi tiết khác trong bài viết trên blog của tôi về việc chuyển bộ giải sang coffeescript .


2
Bạn có thể vui lòng chứa mã của bạn trong câu trả lời của bạn? Nếu không, chúng tôi không thể xem mã mà không cần nhấp vào liên kết!
wizzwizz4
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.