Retina , 61 55 byte
^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$
Karena ini hanya satu regex, Retina akan berjalan dalam mode Match dan melaporkan jumlah pertandingan yang ditemukan, yang akan 1
untuk urutan yang valid dan 0
sebaliknya. Ini tidak kompetitif dibandingkan dengan bahasa golf, tapi saya cukup senang dengan itu, melihat saya mulai dengan monster sebesar 260 byte.
Penjelasan
^((.)(?<!\2.+))*
Bit ini menggunakan awalan huruf unik dengan panjang variabel, yaitu cocok dengan potongan terkemuka yang berpotensi tidak lengkap. Lookbehind memastikan bahwa karakter apa pun yang cocok dengan bit ini belum muncul di string sebelumnya.
Sekarang untuk sisa input, kami ingin mencocokkan potongan 7 tanpa mengulangi karakter. Kami dapat mencocokkan potongan seperti ini:
(.)(?!.{0,5}\1)(.)(?!.{0,4}\2)(.)(?!.{0,3}\3)...(.)(?!.?\5).
Yaitu kami mencocokkan karakter yang tidak muncul untuk 6 karakter lainnya, kemudian yang tidak muncul untuk 5 karakter lainnya dan seterusnya. Tetapi ini membutuhkan pengulangan kode yang cukup mengerikan, dan kami harus mencocokkan potongan trailing (berpotensi tidak lengkap) secara terpisah.
Menyeimbangkan kelompok untuk menyelamatkan! Cara yang berbeda untuk mencocokkan
(.)(?!.{0,5}\1)
adalah untuk mendorong 5 pertandingan kosong ke tumpukan tangkapan dan mencoba mengosongkannya:
(){5}(.)(?!(?<-1>.)*\2)
The *
memungkinkan minimal nol pengulangan, seperti {0,5}
, dan karena kami telah mendorong lima menangkap, itu tidak akan dapat pop lebih dari 5 kali baik. Ini lebih lama untuk satu contoh pola ini, tetapi ini jauh lebih dapat digunakan kembali. Karena kita melakukan popping di lookahead negatif , ini tidak mempengaruhi stack yang sebenarnya setelah lookahead selesai. Jadi setelah lookahead, kami masih punya 5 elemen di stack, tidak peduli apa yang terjadi di dalam. Lebih jauh lagi, kita dapat dengan mudah mengeluarkan satu elemen dari stack sebelum setiap lookahead, dan menjalankan kode dalam satu lingkaran, untuk secara otomatis mengurangi lebar lookahead dari 5 ke 0. Jadi sedikit sangat lama di sana sebenarnya dapat disingkat menjadi
(){7}((?<-1>)(.)(?!(?<-1>.)*\1\3))*
(Anda mungkin melihat dua perbedaan: kami mendorong 7 bukannya 5. Satu tangkapan tambahan adalah karena kami meletus sebelum setiap iterasi, bukan setelahnya. Yang lain sebenarnya diperlukan agar kami dapat meloncat dari tumpukan 7 kali (karena kami ingin loop untuk menjalankan 7 kali), kita dapat memperbaikinya dengan kesalahan satu-per-satu di dalam lookahead dengan memastikan \1
bahwa masih ada setidaknya satu elemen yang tersisa di stack.)
Keindahan dari ini adalah ia juga bisa cocok dengan potongan trailing tidak lengkap, karena kami tidak pernah meminta untuk mengulangi 7 kali (itu hanya maksimum yang diperlukan, karena kami tidak bisa pop dari tumpukan lebih sering dari itu). Jadi yang perlu kita lakukan adalah membungkus ini dalam loop lain dan memastikan kita telah mencapai akhir dari string
^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$