Regex Golf: ตรวจสอบโซลูชันของ Sudoku


65

เขียน regex ที่ตรงกับโซลูชันของซูโดกุที่ถูกต้องและไม่ตรงกับโซลูชันของซูโดกุที่ไม่ถูกต้อง การป้อนข้อมูลที่เป็นคลี่รุ่นของซูโดกุคือไม่มีตัวคั่นบรรทัด เช่นกระดานต่อไปนี้:

7 2 5 8 9 3 4 6 1
8 4 1 6 5 7 3 9 2
3 9 6 1 4 2 7 5 8
4 7 3 5 1 6 8 2 9
1 6 8 4 2 9 5 3 7
9 5 2 3 7 8 1 4 6
2 3 4 7 6 1 9 8 5
6 8 7 9 3 5 2 1 4
5 1 9 2 8 4 6 7 3

จะได้รับเป็น:

725893461841657392396142758473516829168429537952378146234761985687935214519284673

กฎอาจเป็นความรู้ทั่วไปในตอนนี้ แต่ในกรณีที่ ... บอร์ดซูโดกุใช้ได้ถ้าหาก:

  • แต่ละแถวมีตัวเลขตั้งแต่1ถึง9หนึ่งครั้ง
  • แต่ละคอลัมน์มีตัวเลขตั้งแต่1ถึง9หนึ่งครั้ง
  • แต่ละรายการย่อยเก้า 3x3 รายการมีตัวเลขตั้งแต่1ถึง9หนึ่งครั้ง

กฎระเบียบ

คำตอบของคุณควรประกอบด้วย regex เพียงหนึ่งเดียวโดยไม่มีรหัสเพิ่มเติมใด ๆ (ยกเว้นเป็นทางเลือกรายการของตัวดัดแปลง regex ที่จำเป็นสำหรับการแก้ปัญหาของคุณ) คุณต้องไม่ใช้คุณสมบัติของรสชาติ regex ของภาษาที่อนุญาตให้คุณเรียกใช้โค้ดในภาษาโฮสติ้ง (เช่นeตัวดัดแปลงของ Perl )

คุณสามารถใช้รสชาติของ regex ใด ๆ ที่มีอยู่ก่อนความท้าทายนี้ แต่โปรดระบุรสชาติ

อย่าสันนิษฐานว่า regex ถูกยึดโดยปริยาย เช่นถ้าคุณกำลังใช้งูหลามสมมติว่า regex ของคุณจะใช้กับและไม่ได้มีre.search re.matchregex ของคุณไม่จำเป็นต้องตรงกับสตริงทั้งหมด เพียงแค่ต้องจับคู่สตริงย่อยอย่างน้อยหนึ่งรายการ (ซึ่งอาจว่างเปล่า) สำหรับโซลูชันที่ถูกต้องและไม่พบการจับคู่สำหรับโซลูชันที่ไม่ถูกต้อง

คุณอาจสันนิษฐานว่าข้อมูลที่ป้อนจะเป็นสตริงที่มีค่าเป็นบวก 81 หลักเสมอ

นี่คือสนามกอล์ฟ regex ดังนั้น regex ที่สั้นที่สุดเป็นไบต์จะเป็นผู้ชนะ หากภาษาของคุณต้องการตัวคั่น (โดยปกติ/.../) เพื่อแสดงถึงนิพจน์ทั่วไปอย่านับตัวคั่นด้วยตนเอง หากโซลูชันของคุณต้องการตัวดัดแปลงให้เพิ่มหนึ่งไบต์ต่อตัวดัดแปลง

กรณีทดสอบ

บอร์ดที่ถูกต้อง:

123456789456789123789123456231564897564897231897231564312645978645978312978312645
725893461841657392396142758473516829168429537952378146234761985687935214519284673
395412678824376591671589243156928437249735186738641925983164752412857369567293814
679543182158926473432817659567381294914265738283479561345792816896154327721638945
867539142324167859159482736275398614936241587481756923592873461743615298618924375
954217683861453729372968145516832497249675318783149256437581962695324871128796534
271459386435168927986273541518734269769821435342596178194387652657942813823615794
237541896186927345495386721743269158569178432812435679378652914924813567651794283
168279435459863271273415986821354769734692518596781342615947823387526194942138657
863459712415273869279168354526387941947615238138942576781596423354821697692734185
768593142423176859951428736184765923572389614639214587816942375295837461347651298
243561789819327456657489132374192865926845317581673294162758943735914628498236571
243156789519847326687392145361475892724918653895263471152684937436729518978531264
498236571735914628162758943581673294926845317374192865657489132819327456243561789
978531264436729518152684937895263471724918653361475892687392145519847326243156789
341572689257698143986413275862341957495726831173985426519234768734869512628157394

บอร์ดไม่ถูกต้อง:

519284673725893461841657392396142758473516829168429537952378146234761985687935214
839541267182437659367158924715692843624973518573864192298316475941285736456729381
679543182158926473432817659567381294914256738283479561345792816896154327721638945
867539142324167859159482736275398684936241517481756923592873461743615298618924375
754219683861453729372968145516832497249675318983147256437581962695324871128796534
271459386435168927986273541518734269769828435342596178194387652657942813823615794
237541896186927345378652914743269158569178432812435679495386721924813567651794283
168759432459613278273165984821594763734982516596821347615437829387246195942378651
869887283619214453457338664548525781275424668379969727517385163319223917621449519
894158578962859187461322315913849812241742157275462973384219294849882291119423759
123456789456789123564897231231564897789123456897231564312645978645978312978312645
145278369256389147364197258478512693589623471697431582712845936823956714931764825
243561789829317456657489132374192865916845327581673294162758943735924618498236571
243156789529847316687392145361475892714928653895263471152684937436719528978531264
498236571735924618162758943581673294916845327374192865657489132829317456243561789
978531264436719528152684937895263471714928653361475892687392145529847316243156789
342571689257698143986413275861342957495726831173985426519234768734869512628157394
345678192627319458892451673468793521713524986951862347179246835534187269286935714
341572689257698143986413275862341957495726831173985426519234768734869512628517394

สำหรับกรณีทดสอบเพิ่มเติมคุณสามารถใช้สคริปต์ CJam นี้ซึ่งใช้บอร์ดที่ถูกต้องเป็นอินพุตและสุ่มเพื่อให้บอร์ดใหม่ที่ถูกต้อง (รูปแบบการป้อนข้อมูลที่ไม่เกี่ยวข้องตราบใดที่มีตัวเลขเท่านั้น

ถ้า regex ของคุณเข้ากันได้กับ. NET รสคุณสามารถทดสอบออนไลน์โดยใช้ Retina โซลูชันที่ถูกต้องควรพิมพ์0สำหรับบอร์ดที่ไม่ถูกต้องและจำนวนเต็มบวกสำหรับบอร์ดที่ถูกต้อง หากต้องการเรียกใช้กรณีทดสอบทั้งหมดในครั้งเดียวให้ใช้เทมเพลตนี้และแทรก regex ในบรรทัดที่สอง หากคุณต้องการตัวดัดแปลง regex ให้เติม a `ไปยัง regex และวางตัวอักษรปรับปรุงมาตรฐานไว้ข้างหน้า



1
ถ้าเพียงแค่นี้เป็น [รหัสโบว์ลิ่ง], ฮ่า ๆ
mbomb007

รอสักครู่ ... ถ้าเราจะใช้งูหลามเราสามารถเพียงใช้นิพจน์ปกติและไม่มีอะไรอื่น? แต่ละกระดานใหญ่แค่ไหน? มีขนาดเฉพาะหรือไม่? ถ้าไม่เราควรแยกบอร์ดออกจากกลุ่มใต้valid boardsอย่างไร?
R. Kap

@ R.Kap ไม่ว่าคุณจะใช้รสชาติแบบใดคุณควรส่งเฉพาะ regex (และอาจมีการดัดแปลงบางอย่าง) ใช่ แต่ละอินพุตมีขนาด 81 หลักและหมายถึงกระดานเต็ม (แต่ละบรรทัดในกรณีทดสอบเป็นกระดานแยก)
Martin Ender

ฉันเขียนสคริปต์เพื่อแก้ปัญหาซูโดกุอย่างง่ายใน SQL ฉันแน่ใจว่าสามารถเขียนใหม่สำหรับคำถามนี้ อย่างไรก็ตาม SQL ไม่ค่อยมี REGEX มากนัก นั่นตัดสิทธิ์คำตอบหรือไม่ (สคริปต์อาจมีความยาวไม่เกิน 400 อักขระ)
t-clausen.dk

คำตอบ:


40

Ruby regex, 71 78 73 ไบต์

^(?!.*(?=(.))(.{9}+|(.(?!.{9}*$))+|(?>.(?!.{3}*$)|(.(?!.{27}*$)){7})+)\1)

ฉันไม่รู้จักรูบีจริง ๆ แต่ดูเหมือนว่ามันจะไม่บ่นเกี่ยวกับปริมาณควอเดอร์

ลองที่นี่

.NET regex, 79 78 75 หรือ 77 ไบต์

เพราะมาร์ตินคิดว่าเป็นไปได้ ... แต่ฉันคิดว่าเขาจะรวมการเปลี่ยนแปลงเหล่านี้ด้วย

^(?!(.)+((.{9})+|(?>(.{9})+
|.)+|(?((...)*
)(?>(.{27})+
|.){7}|.)+)(?<=\1))

ต้องขึ้นบรรทัดใหม่ในอินพุตเพื่อให้ทำงาน ฉันไม่แน่ใจว่าฉันได้รับอนุญาตให้ทำเช่นนี้ได้หรือไม่

ลองที่นี่

รุ่น 77 ไบต์มีสติ:

^(?!(.)+((.{9})+|((?!(.{9})*$).)+|(?((...)*$)((?!(.{27})*$).){7}|.)+)(?<=\1))

ขอบคุณ Neil ที่ชี้ให้เห็นข้อผิดพลาดในรุ่นก่อนหน้าของฉันและเล่นกอล์ฟ 1 ไบต์ (สำหรับ(...)*)

ลองที่นี่

PCRE, 77 78 ไบต์

^(?!.*(?=(.))((.{9})+|(.(?!(?3)*$))+|(?(?=.(...)*$)(.(?!(.{27})*$)){7}|.)+)\1)

เพียงเพื่อความสมบูรณ์

ลองที่นี่

อีกรุ่นหนึ่ง, 78 ไบต์เช่นกัน:

^(?!.*(?=(.))((.{9})+|(.(?!(?3)*$))+|(?>.(?!(...)*$)|(.(?!(.{27})*$)){7})+)\1)

ลองที่นี่

คำอธิบาย

^(?!.*                    # Match a string that doesn't contain the pattern,
                          # at any position.
  (?=(.))                 # Capture the next character.
  (
    (.{9})+               # Any 9*n characters. The next character is in
                          # the same column as the captured one.
  |
    (.(?!(.{9})*$))+      # Any n characters not followed by a positions 9*m
                          # to the end. The next character is in the same row
                          # as the captured one.
  |
    (                     # Any n occasions of...
    ?(.(...)*$)           # If it is at a position 3*k+1 to the end:
      (.(?!(.{27})*$)){7} # Then count 7*m characters that are not followed
                          # by a position 27*j to the end,
    |
      .                   # Else count any character.
    )+                    # The next character is in the same block as the
                          # captured one.
  )
  \1                      # Fail if the next character is the captured character.
)

ว้าวทำได้ดีมาก ฉันเพิ่งได้รับถึง 83 ใน. NET และต้องเปลี่ยนไปใช้ PCRE สำหรับ 78 ฉันไม่สงสัยเลยว่าคุณจะต้องจบลงด้วยเช่นกัน :)
Martin Ender

@ MartinBüttnerอ๋อ
Nic Hartley

ฉันคิดว่าการใช้ lookahead เพื่อเอาชนะ @ MartinBüttnerโดย (ในเวลานั้น) 4 ไบต์นั้นเรียบร้อย แต่คุณได้นำมันไปสู่ระดับถัดไป
Neil

ขออภัยไม่สามารถตรวจพบว่าเซลล์ที่ (1, 2) และ (2, 1) เหมือนกันหรือไม่และในทำนองเดียวกันสำหรับเซลล์อื่นทั้งหมดในช่องสี่เหลี่ยมที่มีการทำซ้ำด้านล่างและด้านซ้าย
Neil

1
@ MartinBüttnerฉันเพิ่งรู้ว่าผมสามารถแปลรุ่น PCRE ที่สองของฉันเข้าไปในทับทิม ... ผมคิดว่าคุณสามารถโพสต์คำตอบของคุณตอนนี้ ...
jimmy23013

34

PCRE, 117 119 130 133 147ไบต์

^(?!(.{27})*(...){0,2}(.{9})?.?.?(.).?.?(?=(?2)*$).{6,8}(?3)?\4.{0,17}(?1)*$|.*(.)(.{8}(?3)*|((?!(?3)*$)(|.(?7))))\5)

ควรทำงานใน Python, Java และรสชาติอื่น ๆ ตอนนี้มีการเรียกซ้ำ! และคุณสมบัติ "การเรียกซ้ำ" ใช้แบบไม่เรียกซ้ำสำหรับ "รูทีนย่อย" ซึ่งฉันลืมไปโดยสิ้นเชิงจนกระทั่งฉันต้องใช้การเรียกซ้ำที่แท้จริง


ไอเดียสุดเจ๋ง - หลีกเลี่ยงการทำซ้ำแทนการจับคู่แบบแพ้ ๆ !
Qwertiy

1
.{27}*มันเป็นความอัปยศคุณไม่สามารถเขียน
Neil

Bah ฉันจะเล่นกอล์ฟสารละลาย 133 ไบต์ของคุณลงไปที่ 121 ไบต์เท่านั้นที่จะพบว่าคุณเขียนใหม่ แต่ที่นี่มันอยู่แล้ว:^(?!(.{27})*(.{9})?(...){0,2}.?.?(.).?.?(?=(...)*$)(.{9})?.{6,8}\4.{0,17}(.{27})*$|.*(.)((.{9})+|((?!(.{9})*$).)+)(<=\8))
นีล

@ Neil นั่นคือรสชาติอะไร? PCRE หรือคนอื่น ๆ ที่ฉันรู้จักไม่อนุญาตให้มีการอ้างอิงย้อนกลับในลักษณะที่ปรากฏ
feersum

@Neil (<=\8)ดูไม่เหมือนไวยากรณ์ที่ถูกต้อง (มันหายไป?) นอกจากนี้สิ่งเดียวที่ฉันรู้ว่ารองรับ backreferences ใน lookbehinds คือ. NET
Martin Ender

15

.NET regex, 8339 ไบต์

ใช่ฉันรู้ว่าวิธีแก้ปัญหาของฉันนั้นไร้เดียงสามากตั้งแต่มาร์ตินบอกฉันว่าเขาทำมันในขนาด 130 ไบต์ อันที่จริงแล้ว URL ที่จะลองใช้ออนไลน์นั้นยาวมากจนฉันไม่สามารถหาตัวย่อ URL ที่จะยอมรับได้

(code removed, since it's so long nobody will read it here, 
and it made the post take forever to load. Just use the "Try it online" link.)

ลิงค์ด้านล่างไม่สามารถใช้งานได้ใน IE แต่ทำงานได้ใน Chrome และ Firefox

ลองออนไลน์ - กรณีทดสอบทั้งหมดในคราวเดียวด้วยความช่วยเหลือ!`ในตอนต้นไม่รวมอยู่ในจำนวนไบต์


นี่คือสคริปต์ Python ที่ฉันใช้สร้าง (โค้ดด้านล่าง):

R=range(0,9)
S=range(1,10)

o = ""

# validate rows
T = "(?=.{%s,%s}%s)"
for j in R:
    for i in S:
        o += T % (9*j,9*(j+1)-1, i)

# validate columns
# "(?=(.{%s}|.{%s}|.{%s}|.{%s}|.{%s}|.{%s}|.{%s}|.{%s}|.{%s})%s)"
T = "(?=("+"|".join([".{%s}"]*9)+")%s)"
for j in R:
    for i in S:
        o += T % (j,j+9,j+18,j+27,j+36,j+45,j+54,j+63,j+72, i)

# validate boxes
# (?=.{0,2}1|.{9,11}1|.{18,20}1)(?=.{3,5}1|.{12,14}1|.{21,23}1)
# (?=.{27,29}1|.{36,38}1|.{45,47}1)
T = ".{%s,%s}%s"
for i in S:
    for x in (0,27,54):
        for y in (0,3,6):
            o += "(?="+"|".join(T % (x+y+z,x+y+z+2, i) for z in (0,9,18))+")"

o += ".{81}"

o = o.replace(".{0}","").replace(",80}",",}")
print(o)

1
ฉันรูทเพื่อคุณ
Martijn

4
รู้ว่าอะไรตลก? การลองออนไลน์ลิงก์จะทำให้ IE ขัดข้องเพราะมันยาวเกินไป: P
cat

15
@cat นั่นเป็นสาเหตุที่ทำให้ IE มีวัตถุประสงค์เพื่อให้ผู้ใช้ดาวน์โหลด Firefox (หรือ Chromium)
ผู้บัญชาการไบต์

2
@cat มันไม่ได้ผิดพลาด IE11 บน Windows 8.1 แม้ว่าแม้ว่า Regex จะไม่ได้รับการประมวลผลอย่างถูกต้อง
Nzall

2
@cat มันไม่ผิดพลาด IE 11 ของฉันบน Windows 7 มันแค่ตัดทอน URL
mbomb007

14

.NET regex, 121 ไบต์

^(?!(.{27})*(.{9})?(...){0,2}.?.?(.).?.?(?=(...)*$)(.{9})?.{6,8}\4.{0,17}(.{27})*$|.*(?=(.))((.{9})+|(.(?!(.{9})*$))+)\8)

คำอธิบาย:

^(?!                     Invert match (because we're excluding duplicates)
 (.{27})*                Skip 0, 3 or 6 rows
 (.{9})?                 Optionally skip another row
 (...){0,2}              Skip 0, 3 or 6 columns
 .?.?(.).?.?(?=(...)*$)  Choose any of the next three cells
 (.{9})?                 Optionally skip another row
 .{6,8}\4                Match any of the three cells below
 .{0,17}(.{27})*$        As long as they're from the same square
|                        OR
 .*(?=(.))(              Choose any cell
  (.{9})+                Skip at least one row
 |                       or
  (.                     Skip cells
   (?!(.{9})*$)          Without reaching the end of the row
  )+                     For at least one cell (i.e. the cell chosen above)
 )\8)                    Match the chosen cell to the next cell
)

ดีการรวมกันของแถวและคอลัมน์นั้นค่อนข้างฉลาด นั่นช่วยประหยัด 4 ไบต์ในโซลูชันของฉันเอง :)
Martin Ender

8

PCRE, 3579 ไบต์

วิธีการแก้ปัญหากำลังดุร้ายน่ากลัวอย่างแน่นอน มองในแง่ลบ

ฉันใช้เวลากับสิ่งนี้มากเกินไปที่จะละทิ้งมันดังนั้นนี่คือเพื่อเห็นแก่ลูกหลาน

ถ้าหากซูโดกุเริ่มใช้อักขระ 9 ชุดที่แตกต่างกันจู่ๆก็ยังใช้งานได้ฉันเดาว่า ...

http://pastebin.com/raw/CwtviGkC

ฉันไม่ทราบวิธีการใช้งาน Retina แต่คุณสามารถวางลงในhttps://regex101.comหรือคล้ายกันก็ได้

รหัส Ruby ใช้ในการสร้าง regex:

# Calculate the block you're in
def block(x)
    x /= 3
    x + x%3 - x%9
end

81.times do |i|
    row, col = i.divmod(9)
    neg = []
    neg += (0...col).map {|e| 9*row + e + 1}
    neg += (0...row).map {|e| 9*e + col + 1}
    neg += (0...i).map {|e| e + 1 if block(e) == block(i)}.compact
    neg = neg.uniq.sort.map {|e| "\\#{e}"}
    if neg.size > 0
        print "(?!#{neg.join '|'})"
    end
    print "(.)"
end

8

รสทับทิม75 74 ไบต์

ขอบคุณ jimmy23013 สำหรับการบันทึก 1 ไบต์

^(?!(.{9}*(.|(.)){,8}|.*(\g<2>.{8})*|.{27}?.{3}?(\g<2>{3}.{6}){,2}.?.?)\3).

ทดสอบที่นี่

ตอนนี้ในที่สุดมันก็พ่ายแพ้ฉันสามารถแบ่งปันทางออกของตัวเอง :) ฉันค้นพบเทคนิค regex ที่น่าสนใจ (อาจจะใหม่หรือไม่?) ในกระบวนการ ( (.|(.)){,8}\3ส่วน) ซึ่งอาจจะไม่สามารถเอาชนะได้ในกรณีที่ไม่สามารถใช้ร่วมกับส่วนอื่น ๆ ของ regex (เช่นเดียวกับคำตอบของ jimmy23013) .

คำอธิบาย

เช่นเดียวกับคำตอบสั้น ๆ อื่น ๆ ฉันใช้ lookahead เชิงลบซึ่งค้นหาคำซ้ำในแถวคอลัมน์หรือบล็อก Building Block พื้นฐานของการแก้ปัญหาคือ:

(.|(.))...\3

โปรดทราบว่า\3จะถูกใช้ซ้ำระหว่างสามทางเลือกที่แตกต่างกัน (ซึ่งทุกกลุ่มใช้3สำหรับการตรวจจับที่ซ้ำกัน)

กลุ่มทางด้านซ้าย (ซึ่งคือกลุ่ม2ที่มีกลุ่ม3) จะใช้สำหรับตำแหน่งใด ๆ ที่สามารถมีครึ่งแรกของตัวเลขที่ซ้ำกัน (ภายในกลุ่มที่ต้องไม่มีตัวเลขที่ซ้ำกัน) จากนั้น...เป็นสิ่งที่ทำให้เราอยู่ในตำแหน่งต่อไปซึ่งอาจมีตัวเลขดังกล่าว (หากจำเป็น) และ\3พยายามค้นหาสำเนาซ้ำในช่วงครึ่งหลังผ่านการอ้างถึงซ้ำ เหตุผลที่ใช้งานได้คือการย้อนรอย เมื่อเครื่องยนต์เข้าคู่กันเป็นครั้งแรก(.|(.))มันจะใช้.ทุกครั้งและไม่จับอะไรเลย ตอนนี้\3ในตอนท้ายล้มเหลว แต่ตอนนี้เครื่องยนต์จะค่อยๆลองใช้(.)แทน.การแข่งขันแบบเดี่ยว ๆ ในที่สุดหากมีการซ้ำกันมันจะหาชุดค่าผสมที่(.)มีการใช้งานครั้งสุดท้ายกับตัวเลขหลักแรกของสำเนาที่ซ้ำกัน (เช่นการจับภาพไม่ได้ถูกเขียนทับในภายหลัง) และจากนั้นใช้บางอย่างเพิ่มเติม.เพื่อเชื่อมช่องว่างกับการอ้างอิงกลับ หากมีสิ่งที่ซ้ำกันการย้อนรอยจะพบได้เสมอ

ลองดูที่ส่วนต่าง ๆ สามส่วนที่ใช้:

.{9}*(.|(.)){,8}

การตรวจสอบนี้จะทำซ้ำในบางแถว ครั้งแรกที่เราข้ามไปยังแถวใด ๆ .{9}*กับ จากนั้นเราจับคู่อักขระได้สูงสุด 8 ตัว (เช่นอะไรก็ตามในแถวนั้นยกเว้นตัวเลขหลักสุดท้าย) โดยใช้การจับคู่ซ้ำที่เป็นตัวเลือกและลองค้นหา\3หลังจากนั้น

.*(\g<2>.{8})*

สิ่งนี้จะค้นหารายการที่ซ้ำกันในบางคอลัมน์ ก่อนอื่นให้สังเกตว่า\g<2>เป็นการเรียกรูทีนย่อยดังนั้นนี่คือ:

.*((.|(.)).{8})*

ที่ทั้งสองกลุ่มเราได้แทรกเพียงแค่จะยังคงเรียกว่าและ23

ที่นี่.*เพียงแค่ข้ามเท่าที่จำเป็น (มันจะเพียงพอที่จะจับคู่ถึง 8 ตัวอักษรที่นี่ แต่ค่าใช้จ่ายไบต์มากขึ้น) จากนั้นกลุ่มด้านนอกจับคู่หนึ่งแถวที่สมบูรณ์ (ซึ่งอาจตัดข้ามสองแถวทางกายภาพ) ต่อครั้งโดยสามารถจับอักขระตัวแรก \3จะมองหาขวาหลังจากนี้ซึ่งทำให้มั่นใจได้แนวตั้งระหว่างการจับภาพและ backreference

ในที่สุดการตรวจสอบบล็อก:

.{27}?.{3}?(\g<2>{3}.{6}){,2}.?.?

อีกครั้ง\g<2>คือการเรียกรูทีนย่อยดังนั้นนี่คือ:

.{27}?.{3}?((.|(.)){3}.{6}){,2}.?.?

ในการตรวจสอบบล็อกโปรดทราบว่าเนื่องจากเราได้ตรวจสอบแถวและคอลัมน์ทั้งหมดแล้วเราจำเป็นต้องตรวจสอบบล็อก 3x3 สี่รายการเท่านั้น เมื่อเรารู้ว่าแถวและคอลัมน์ทั้งหมดรวมทั้งบล็อก 3x3 เหล่านี้ถูกต้อง:

XX.
XX.
...

จากนั้นเราก็รู้ว่าอาจจะมีการซ้ำซ้อนในบล็อกที่เหลืออยู่ไม่ได้ ดังนั้นฉันแค่ตรวจสอบสี่ช่วงตึกเหล่านี้เท่านั้น นอกจากนี้โปรดทราบว่าเราไม่ต้องค้นหารายการที่ซ้ำกันภายในแถวเดียวกันของบล็อก 3x3 ก็เพียงพอแล้วที่จะค้นหาสำเนาของครึ่งแรกในแถวเดียวและค้นหาครึ่งหลังในแถวถัดไป

ทีนี้สำหรับโค้ดนั้นเราต้องข้ามไปที่จุดเริ่มต้นของหนึ่งในสี่บล็อกด้วย.{27}?.{3}?(เลือกข้ามสามแถวหรือข้ามสามคอลัมน์ก็ได้) จากนั้นเราพยายามจับคู่แถวของบล็อก 3x3 สองแถวด้วยกลอุบายเดียวกับที่เราใช้สำหรับแถวก่อนหน้านี้:

(.|(.)){3}.{6}

เราอนุญาตให้ แต่ไม่จำเป็นต้องมีการจับภาพใด ๆ ของ 3 เซลล์ในแถวปัจจุบันของบล็อก 3x3 .{6}แล้วข้ามไปยังแถวถัดไปด้วย สุดท้ายเราพยายามค้นหาข้อมูลที่ซ้ำกันใน 3 เซลล์ของแถวที่เราลงท้ายด้วย:

.?.?

และนั่นคือมัน


74: ^(?!(.*((.|(.)).{8})*|.{9}*\g<3>{,8}|.{27}?.{3}?(\g<3>{3}.{6}){,2}.?.?)\4); ^(?!(.*((.|(.)|\4()).{8})*|.{9}*\g<3>{9}|.{27}?.{3}?(\g<3>{3}.{6}){3})\5)73:
jimmy23013

@ jimmy23013 จริง ๆ แล้วฉันใช้\4()เคล็ดลับในรุ่นก่อนหน้าสำหรับบล็อก 3x3 แต่สุดท้ายก็กำจัดมันออกไปเพราะมันยาวกว่า : D
Martin Ender

@ jimmy23013 73 คนไม่ได้ตรวจสอบแถวสุดท้ายแม้ว่า:341572689257698143986413275862341957495726831173985426519234768734869512628517394
Martin Ender

6

Javascript regex, 532 530 481 463 ตัวอักษร

ตรวจสอบแถว:

/^((?=.{0,8}1)(?=.{0,8}2)(?=.{0,8}3)(?=.{0,8}4)(?=.{0,8}5)(?=.{0,8}6)(?=.{0,8}7)(?=.{0,8}8)(?=.{0,8}9).{9})+$/

ตรวจสอบคอลัมน์:

/^((?=(.{9}){0,8}1)(?=(.{9}){0,8}2)(?=(.{9}){0,8}3)(?=(.{9}){0,8}4)(?=(.{9}){0,8}5)(?=(.{9}){0,8}6)(?=(.{9}){0,8}7)(?=(.{9}){0,8}8)(?=(.{9}){0,8}9).){9}/

ตรวจสอบตารางจากถ่านตัวแรก:

/(?=.?.?(.{9}){0,2}1)(?=.?.?(.{9}){0,2}2)(?=.?.?(.{9}){0,2}3)(?=.?.?(.{9}){0,2}4)(?=.?.?(.{9}){0,2}5)(?=.?.?(.{9}){0,2}6)(?=.?.?(.{9}){0,2}7)(?=.?.?(.{9}){0,2}8)(?=.?.?(.{9}){0,2}9)/

ตั้งค่าการแสดงตัวอย่างเป็นจุดเริ่มต้นของตาราง:

/^(((?=)...){3}.{18})+$/

และการแสดงออกทั้งหมด:

/^(?=((?=.{0,8}1)(?=.{0,8}2)(?=.{0,8}3)(?=.{0,8}4)(?=.{0,8}5)(?=.{0,8}6)(?=.{0,8}7)(?=.{0,8}8)(?=.{0,8}9).{9})+$)(?=((?=(.{9}){0,8}1)(?=(.{9}){0,8}2)(?=(.{9}){0,8}3)(?=(.{9}){0,8}4)(?=(.{9}){0,8}5)(?=(.{9}){0,8}6)(?=(.{9}){0,8}7)(?=(.{9}){0,8}8)(?=(.{9}){0,8}9).){9})(((?=.?.?(.{9}){0,2}1)(?=.?.?(.{9}){0,2}2)(?=.?.?(.{9}){0,2}3)(?=.?.?(.{9}){0,2}4)(?=.?.?(.{9}){0,2}5)(?=.?.?(.{9}){0,2}6)(?=.?.?(.{9}){0,2}7)(?=.?.?(.{9}){0,2}8)(?=.?.?(.{9}){0,2}9)...){3}.{18})+$/

จับคู่สตริงทั้งหมด


ทดสอบใน Javascript ES6:

r = /^(?=((?=.{0,8}1)(?=.{0,8}2)(?=.{0,8}3)(?=.{0,8}4)(?=.{0,8}5)(?=.{0,8}6)(?=.{0,8}7)(?=.{0,8}8)(?=.{0,8}9).{9})+$)(?=((?=(.{9}){0,8}1)(?=(.{9}){0,8}2)(?=(.{9}){0,8}3)(?=(.{9}){0,8}4)(?=(.{9}){0,8}5)(?=(.{9}){0,8}6)(?=(.{9}){0,8}7)(?=(.{9}){0,8}8)(?=(.{9}){0,8}9).){9})(((?=.?.?(.{9}){0,2}1)(?=.?.?(.{9}){0,2}2)(?=.?.?(.{9}){0,2}3)(?=.?.?(.{9}){0,2}4)(?=.?.?(.{9}){0,2}5)(?=.?.?(.{9}){0,2}6)(?=.?.?(.{9}){0,2}7)(?=.?.?(.{9}){0,2}8)(?=.?.?(.{9}){0,2}9)...){3}.{18})+$/
;`123456789456789123789123456231564897564897231897231564312645978645978312978312645
725893461841657392396142758473516829168429537952378146234761985687935214519284673
395412678824376591671589243156928437249735186738641925983164752412857369567293814
679543182158926473432817659567381294914265738283479561345792816896154327721638945
867539142324167859159482736275398614936241587481756923592873461743615298618924375
954217683861453729372968145516832497249675318783149256437581962695324871128796534
271459386435168927986273541518734269769821435342596178194387652657942813823615794
237541896186927345495386721743269158569178432812435679378652914924813567651794283
168279435459863271273415986821354769734692518596781342615947823387526194942138657
863459712415273869279168354526387941947615238138942576781596423354821697692734185
768593142423176859951428736184765923572389614639214587816942375295837461347651298`
.split`
`.every(r.test.bind(r))
&&
`519284673725893461841657392396142758473516829168429537952378146234761985687935214
839541267182437659367158924715692843624973518573864192298316475941285736456729381
679543182158926473432817659567381294914256738283479561345792816896154327721638945
867539142324167859159482736275398684936241517481756923592873461743615298618924375
754219683861453729372968145516832497249675318983147256437581962695324871128796534
271459386435168927986273541518734269769828435342596178194387652657942813823615794
237541896186927345378652914743269158569178432812435679495386721924813567651794283
168759432459613278273165984821594763734982516596821347615437829387246195942378651
869887283619214453457338664548525781275424668379969727517385163319223917621449519
894158578962859187461322315913849812241742157275462973384219294849882291119423759
123456789456789123564897231231564897789123456897231564312645978645978312978312645
145278369256389147364197258478512693589623471697431582712845936823956714931764825`
.split`
`.every(s => !r.test(s))

ฉันคิดว่าคอลัมน์ควรจะง่ายกว่าแถวมากดังนั้นฉันจึงพบว่าคอลัมน์ regex ของคุณยาวกว่าแถวหนึ่งของคุณ
Peter Taylor

@PeterTaylor พวกเขามีโครงสร้างเดียวกัน แต่สำหรับผมมีคอลัมน์ที่จะข้ามไป 9 ตัวอักษรแทน 1 เพื่อให้.ได้รับในวงเล็บเพราะต่อไป(.{9}) {0,8}ทำไมคุณคิดว่าคอลัมน์ควรสั้นลง
Qwertiy

@ PeterTaylor, อ๋อ, คอลัมน์คงจะง่ายกว่านี้ถ้าฉันเดาว่าจะตรวจสอบการปฏิเสธ
Qwertiy

@ SuperJedi224 ทำไมต้องจาวาสคริปต์? ฉันคาดว่า regex นี้จะใช้ได้ทุกที่
Qwertiy

6
@Qwertiy ในขณะที่ regex ของคุณควรทำงานในหลาย ๆ รสชาติมันขึ้นอยู่กับ lookaheads (เช่นไม่มีให้ใน Lua หรือ OCaml เป็นต้น) นอกจากนี้ยังเป็นนิพจน์ทั่วไปพื้นฐานหรือแบบขยายที่ไม่ถูกต้องซึ่งใช้ไวยากรณ์ที่แตกต่างอย่างสิ้นเชิง เป็นการดีที่สุดที่จะเลือกรสชาติสำหรับการเรียกร้องความถูกต้องแม้ว่าวิธีการแก้ปัญหาทำงานได้ในหลาย ๆ
Dennis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.