regex ง่าย ๆ ที่สั้นที่สุดที่ตรงกับคำไบนารี


20

งาน

กำหนดregex อย่างง่ายเป็นนิพจน์ปกติที่ไม่ว่างประกอบด้วยเพียง

  • ตัวอักษร0และ1,
  • การจัดกลุ่มวงเล็บ(และ),
  • +อย่างใดอย่างหนึ่งหรือมากกว่าปริมาณการทำซ้ำ

ด้วยสตริง0และ1s ที่ไม่ว่างเปล่าโปรแกรมของคุณควรค้นหา regex ที่สั้นที่สุดที่ตรงกับสตริงอินพุตแบบเต็ม (นั่นคือเมื่อจับคู่ regex ธรรมดาให้ทำท่าว่ามันถูก bookended โดย^ และ  $.) หากมี regexes ที่สั้นที่สุดหลายอันให้พิมพ์ใด ๆ หรือทั้งหมด)

ดังนั้นการส่งที่สั้นที่สุด (เป็นไบต์) จะชนะ

กรณีทดสอบ

1 -> 1
00 -> 00 or 0+
010 -> 010
1110 -> 1+0
01010 -> 01010
0101010 -> 0(10)+ or (01)+0
011111 -> 01+
10110110 -> (1+0)+
01100110 -> (0110)+ or (01+0)+
010010010 -> (010)+
111100111 -> 1+001+ or 1+0+1+
00000101010 -> 0+(10)+ or (0+1)+0
1010110001 -> 1(0+1+)+ or (1+0+)+1

3
คุณควรชี้แจงว่าคุณต้องการให้เราเขียนโปรแกรมที่เขียน regex ไม่ใช่เขียน regex เราเอง แต่นี่ดูน่าสนใจ
gcampbell

1
ในการทดสอบของฉัน01100110เป็นกรณีที่น่าสนใจ ... อัลกอริทึมไร้เดียงสาจะเขียน01+0+1+0หรือ(0+1+)+0ที่ไม่เหมาะสม
Neil

คำตอบ:


2

Pyth, 20 ไบต์

hf.x}z:zT1Zy*4"()01+

การดำเนินการนี้ใช้เวลาประมาณ 30 วินาทีดังนั้นจึงจำเป็นต้องเรียกใช้ออฟไลน์

คำอธิบาย:

hf.x}z:zT1Zy*4"()01+
                        Implicit: z is the input string.
              "()01+    "()01+"
            *4          Repeated 4 times
           y            All subsequences in length order
hf                      Output the first one such that
      :zT1              Form all regex matches of z with the candidate string
    }z                  Check if the input is one of the strings
  .x      Z             Discard errors

ฉันไม่แน่ใจอย่างสมบูรณ์ว่าสตริงที่สั้นที่สุดคือการเรียงลำดับของ "() 01+" * 4 แต่ 4 สามารถเพิ่มเป็น 9 ได้โดยไม่ต้องเสียค่าใช้จ่ายไบต์


9

JavaScript (ES6), 488 341 ไบต์

s=>[s.replace(/(.)\1+/g,'$1+'),...[...Array(60)].map((_,i)=>`(${(i+4).toString(2).slice(1)})+`),...[...Array(1536)].map((_,i)=>`${i>>10?(i>>8&1)+(i&2?'+':''):''}(${i&1}${i&4?i>>4&1:i&16?'+':''}${i&8?''+(i>>7&1)+(i&64?i>>5&1:i&32?'+':''):''})+${i&512?(i>>8&1)+(i&2?'+':''):''}`)].filter(r=>s.match(`^${r}$`)).sort((a,b)=>a.length-b.length)[0]

คำอธิบาย: เนื่องจากหก regexes สามารถแสดงคำไบนารีที่เป็นไปได้ทั้งหมดและสองที่ยาวที่สุดคือความยาวเก้าอักขระจึงพอเพียงที่จะตรวจสอบ regexes เหล่านั้นและ regexes ที่สั้นกว่าทั้งหมด หนึ่งในผู้สมัครที่เห็นได้ชัดคือสตริงที่มี "การเข้ารหัสความยาวรัน" (เช่นการทำงานหลักทั้งหมดแทนที่ด้วย+s ที่เหมาะสม) แต่ยัง()ต้องตรวจสอบสตริงที่มีชุดหนึ่งชุดด้วย ฉันสร้าง regexes 1,596 รายการ (รวมถึงรายการที่ซ้ำกันและ regexes ที่ไร้ประโยชน์ แต่พวกเขาจะถูกกำจัดออกไป) และทดสอบ 1597 ทั้งหมดเพื่อดูว่าการแข่งขันใดที่สั้นที่สุด regexes ที่สร้างขึ้นแบ่งออกเป็นสองประเภท: \(\d{2,5}\)\+(60 regexes) และ(\d\+?)?\(\d[\d+]?(\d[\d+]?)?\)(\d\+?)?(1536 regexes เนื่องจากฉันหลีกเลี่ยงการสร้าง regexes ที่มีตัวเลขนำหน้าและหลักท้าย)


@LeakyNun ในตอนแรกฉันคิดว่ามีความยาว 4 regexes แต่นี่ไม่ถูกต้องชัดดังนั้นฉันได้อธิบายคำอธิบายของฉันแล้ว
Neil

2

Pyth - 31 30 29 ไบต์

กำลังดุร้าย! อาจตีกอล์ฟตัววนซ้ำได้เล็กน้อย

 f=+Yf.x:zjY"^$")Z^"10+()"T1Y

Test Suite


1

Ruby, 109 ไบต์

มันเป็นวิธีการบังคับเดรัจฉานที่น่าเบื่อ ใช้งานได้เนื่องจากไม่ต้องใช้ regex นานกว่า 9 ตัวอักษร (ตาม Neil notes) และไม่จำเป็นต้องทำซ้ำแต่ละอักขระมากกว่า 4 ครั้ง (ลองใช้'01()+'.chars*9ทำให้ซีพียูของฉันไม่มีความสุข)

10.times{|i|('01()+'.chars*4).combination(i).map{|s|begin
/^#{s*''}$/=~$*[0]&&[puts(s*''),exit]
rescue
end}}
$ for word in `grep -Po '^\S+' test_cases.txt`; do nice -n20 ruby sre.rb $word; done
1
0+
010
1+0
01010
0(10)+
01+
(1+0)+
(01+0)+
(010)+
1+0+1+
0+(10)+
1(0+1+)+

1

Python 3, 186 ไบต์

ฉันกำลังตรวจสอบว่ามีวิธีการแก้ไขปัญหานี้นอกเหนือจากการบังคับให้เดรัจฉานหรือไม่ แต่นี่คือวิธีการแก้ปัญหากำลังดุร้ายของ Python ในตอนนี้

import re,itertools
def a(b):
 for z in range(10):
  for i in itertools.combinations("01()+"*4,z):
   j=''.join(i)
   try:
    if re.fullmatch(j,b)and len(j)<=len(b):return j
   except:1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.