Temukan Pencocokan Bracket Pertama

22

Ini adalah salah satu dari serangkaian tantangan menjelang ulang tahun Brain-Flak. Cari tahu lebih lanjut di sini .

Tantangan

Untuk tantangan ini, sasaran Anda adalah menemukan pasangan kurung yang paling cocok dalam serangkaian kurung yang sepenuhnya cocok ()[]{}<>. Untuk meminjam definisi DJMcMayhem tentang string yang sepenuhnya cocok:

  • Untuk tujuan tantangan ini, "braket" adalah salah satu karakter: ()[]{}<>.

  • Sepasang tanda kurung dianggap "cocok" jika tanda kurung buka dan tutup berada dalam urutan yang benar dan tidak memiliki karakter di dalamnya, seperti

    ()
    []{}
    

    Atau jika setiap subelemen di dalamnya juga cocok.

    [()()()()]
    {<[]>}
    (()())
    

    Subelemen juga dapat disarungkan beberapa lapisan.

    [(){<><>[()]}<>()]
    <[{((()))}]>
    
  • Sebuah string dianggap "Sepenuhnya cocok" jika dan hanya jika masing-masing pasangan braket memiliki braket pembukaan dan penutupan yang benar dalam urutan yang benar.

Memasukkan

Input akan terdiri dari string nonempty tunggal atau array char yang hanya berisi karakter ()[]{}<>, dan dijamin akan sepenuhnya cocok. Anda dapat mengambil input dengan cara apa pun yang sesuai dengan standar i / o kami .

Keluaran

Output dari program atau fungsi Anda akan menjadi indeks braket yang menutup yang pertama. Output harus salah 0atau 1diindeks. Sekali lagi, output mungkin dengan cara apa pun yang sesuai dengan standar i / o kami .

Uji Kasus

Input       0-indexed   1-indexed
()          1           2
(<>)        3           4
<[]{<>}>    7           8
{}{}{}{}    1           2
[[]<>[]]    7           8

Ini adalah , byte terkecil menang!

Pavel
sumber
3
Poin bonus jika Anda menjawab di Brain-Flak ofc :)
Erik the Outgolfer
1
@EriktheOutgolfer Selesai
DJMcMayhem
1
Teknik ini sangat membantu untuk menulis implementasi BF yang tidak efisien.
Buah Esolanging

Jawaban:

2

V , 4 byte

%Dø.

Cobalah online!

Ini, tidak seperti kebanyakan jawaban V, menggunakan pengindeksan 0. Saya sangat bangga dengan jawaban ini, dan seberapa jauh bahasa saya telah muncul. Penjelasan:

%       " Jump to the first bracket match
 D      " Delete everything under and after the cursor
  ø     " Count the number of times the following regex is matched:
   .    "   Any character
DJMcMayhem
sumber
Bukankah ada boilerplate yang Anda butuhkan untuk mencocokkan <>?
Pavel
@Pavel In vim, ya. Tetapi tidak dalam V.
DJMcMayhem
27

Brain-Flak , 685, 155, 151 , 137 byte

(())({<{}({}()<(()()()())>)({}(<>))<>{(({})){({}[()])<>}{}}{}<>
([{}()]{})(({})){{}({}[()])(<()>)}{}(<>)<>{{}<>{}({}<>)}{}(<>[]<>)>()}<>)

Cobalah online!

136 byte kode, ditambah satu byte untuk -a. Satu diindeks.

530 bytes bermain golf! Itu mungkin golf terbesar yang pernah saya lakukan.

14 byte disimpan berkat Riley!

Ini menyalahgunakan formula kurung buka / tutup: jika Anda mengambil nilai ASCII, menambah satu per satu, dan mengambil modulo dari 4, pembuka ( ({[<) akan selalu mendapatkan 0atau 1, sedangkan penutup ( )}]>) akan selalu mendapatkan 2 atau 3.

Penjelasan:

#Push 1
(())

#While true
({<

    #Pop stack height
    {}

    #Compute (TOS + 1) % 4
    ({}()<(()()()())>)({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]{})

    #Decrement if positive
    (({})){{}({}[()])(<()>)}{}

    #Push 0 onto alternate
    (<>)

    #Toggle back
    <>

    #Pop two zeros from alternate if closer
    {{}<>{}({}<>)}{}

    #Push height of alternate stack
    (<>[]<>)

#Make each time through evaluate to 1
>()

#Endwhile
}

#Push the number of loops onto the offstack
<>)
DJMcMayhem
sumber
8
Demi cinta Tuhan, apa-apaan ini.
Leaky Nun
Pada dasarnya semua orang sekarang menggunakan n-1&2/ n+1&2/ -n&2atau n%7&2untuk membedakan tanda kurung buka dan tutup ...
ETHproduk
@ ETHproductions Saya tidak yakin apakah brain-flak dapat menghitung secara efisien &2, tapi saya akan memeriksanya.
DJMcMayhem
Oh, saya pikir kamu adalah. Anda harus melakukan sesuatu yang mirip untuk membedakan antara 0/ 1dan 2/ 3... meskipun sekarang setelah saya melihatnya, Anda hanya mengurangi jika positif. Trik keren juga :-)
ETHproduksi
1
The (TOS+1)%4bisa lebih pendek: Cobalah secara online!
MegaTom
11

05AB1E , 17 16 10 byte

-1 berkat carusocomputing

-6 terima kasih kepada Adnan untuk wawasannya yang luar biasa bahwa "setelah bertambah, bit terakhir kedua adalah 0 untuk braket pembuka dan 1 untuk braket penutupan"

Ç>2&<.pO0k

Cobalah online!

Ç          # Get input as ASCII values
 >         # Increment
  2&       # And with 2 (0 for open and 2 for close brackets)
    <      # decrement 
     .p    # prefixes
       O   # Sum
        0k # Print the index of the first 0
Riley
sumber
žutampaknya bisa digunakan di sini.
Magic Octopus Mm
žu8ÝÈÏjadi, tidak, tidak terlalu lol. Paling-paling masih 5 byte. Saya berpikir untuk membagi kawat gigi menjadi dua, dan menghapus kawat gigi sampai hanya ada satu pasangan yang tersisa, penghitung kenaikan sebesar 2 untuk setiap pasangan yang dilepas. Saya tidak tahu kalau itu kurang. Mencoba itu atm.
Magic Gurita Guci
Untuk 10 byte: Ç>2&<.pO0k.
Adnan
1
Hanya bermain-main dengan nilai-nilai ASCII. Perhatikan bahwa setelah bertambah, bit terakhir kedua adalah 0untuk braket pembuka dan 1untuk braket penutup.
Adnan
11

Vim, 23 byte

:se mps+=<:>
%DVr<C-a>C1<esc>@"

Cobalah online!

Saya sangat sedih dengan jawaban ini. Solusi ini sangat indah dan pendek, tetapi, secara default, vim tidak mempertimbangkan <dan >cocok, jadi saya perlu 13 byte kode boilerplate. Kalau tidak, ini hanya akan menjadi 10 byte.

Saya akan memposting jawaban V, tetapi itu hanya akan menjadi satu byte lebih pendek, yaitu berubah Vrmenjadi Ò, karena Vrmerupakan vim-idiom yang umum.

Ini adalah 1-diindeks tetapi bisa diubah sepele menjadi 0-diindeks dengan mengubah 1ke a 0.

:se mps+=<:>        " Stupid boilerplate that tells vim to consider `<` and `>` matched
%                   " Jump to the bracket that matches the bracket under the cursor
 D                  " Delete everything from here to the end of the line
  V                 " Visually select this whole line
   r<C-a>           " Replace each character in this selection with `<C-a>`
                    " This conveniently places the cursor on the first char also
         C          " Delete this whole line into register '"', and enter insert mode
          1<esc>    " Enter a '1' and escape to normal mode
                @"  " Run the text in register '"' as if typed. Since the `<C-a>` command
                    " Will increment the number currently under the cursor
DJMcMayhem
sumber
1
Posting jawaban V kalau begitu :)
Erik the Outgolfer
10

Jelly , 11 10 9 byte

O’&2’+\i0

Cobalah online!

Penjelasan

Idenya di sini adalah untuk menemukan "formula ajaib" yang dapat membedakan pembukaan dari kurung tutup. Saya awalnya menggunakan O%7&2(yaitu "mengambil kode ASCII, modulo 7, bitwise-and 2"), tetapi disarankan @ETHproductions O’&2(yang menggantikan modulo 7 dengan penurunan); keduanya mengembalikan 0 untuk satu jenis braket dan 2 untuk yang lain. Mengurangkan 1 ( ) akan menjadikan hasil ini menjadi -1 dan 1.

Sisa kode tersebut adalah +\. +\menghasilkan jumlah kumulatif. Jika satu set tanda kurung cocok dengan benar, itu akan berisi jumlah yang sama dari -1s dan 1s, yaitu jumlah kumulatifnya adalah 0. Maka kita hanya perlu mengembalikan indeks dari 0 pertama dalam daftar yang dihasilkan; kita bisa melakukannya dengan i0.


sumber
Menarik bagaimana kami mengambil pendekatan serupa untuk mendeteksi kurung penutup. Sayangnya saya hanya menemukan versi yang lebih rendah:b*2%7>3
2501
Pendekatan yang menarik! Saya mengembangkan jawaban yang lebih panjang (untuk berlatih) yang pada akhirnya saya turunkan untuk hal ini, kecuali cukup menarik, alih-alih pengurangan pertama dalam posting Anda, saya malah menambahnya. :)
HyperNeutrino
9

Retina , 26 24 byte

M!`^.(?<-1>([[({<])*.)*

Cobalah online!

Hasilnya berbasis 1.

Penjelasan

Solusi Retina yang sangat berbeda yang pada dasarnya didasarkan pada regex tunggal (dan sangat mudah dibaca ...). Ini menggunakan teknik baru yang saya temukan kemarin untuk mencocokkan string seimbang menggunakan kelompok balancing .

M!`^.(?<-1>([[({<])*.)*

Temukan ( M) dan kembalikan ( !) semua kecocokan regex ^.(?<-1>([[({<])*.)*. Regex itu melompati karakter pertama dari string dan kemudian menggunakan kelompok penyeimbang untuk melacak kedalaman sarang. Setiap [({<penambahan kedalaman (dilacak oleh grup 1) dan karakter lain mana pun menurunkan kedalaman (pada prinsipnya, .memungkinkan kedalaman untuk dikurangi dengan membuka tanda kurung juga, tetapi karena regex dicocokkan dengan rakus, backtracker tidak akan pernah mencoba yang ). Trik yang aneh adalah bahwa (?<-1>...)kelompok melampirkan 1yang berfungsi karena muncul dari kelompok penyeimbang terjadi di akhir kelompok. Ini menghemat dua byte dari pendekatan standar dalam formulir((open)|(?<-2>close))*. Kecocokan harus berhenti di braket yang menutup yang pertama, karena kami melewatkannya, sehingga tidak diperhitungkan dalam kedalaman tumpukan (dan kedalaman tumpukan tidak bisa negatif).

Panjang pertandingan ini adalah indeks berdasarkan braket yang kami cari.


Cukup hitung jumlah kecocokan kosong dalam string ini. Regex kosong selalu cocok sekali lagi daripada ada karakter di string, jadi ini memberi kita indeks berbasis 1 dari braket yang kita cari.

Martin Ender
sumber
Itu brilian!
Pavel
Pendekatan lebih pendek : hapus bagian kedua dari string daripada mencocokkan bagian pertama. Saya suka bagaimana Anda mengukur panjang string, btw!
Leo
@ Leo Itu benar-benar rapi! Anda dapat mempostingnya sebagai jawaban terpisah :)
Martin Ender
Oke, trik baru untuk string seimbang ini luar biasa: D
Leo
6

Retina , 24 byte

.(([[({<])|(?<-2>.))*$


Cobalah online!

Ini terinspirasi oleh solusi Martin Ender .

Penjelasan

Baris pertama adalah regex yang cocok dengan karakter diikuti oleh string yang seimbang sampai ke akhir string utama (untuk penjelasan rinci tentang bagaimana kelompok penyeimbang digunakan dalam regex ini lihat jawaban Martin). Karena regex mencari kecocokan dari kiri ke kanan, ini akan menemukan subfix tepat terpanjang seimbang, yaitu segalanya setelah braket yang menutup yang pertama, ditambah braket itu sendiri.

Baris berikut kosong, jadi kami mengganti kecocokan dengan string kosong, artinya sekarang kami hanya perlu menghitung karakter yang tersisa untuk mendapatkan hasil (diindeks 0) yang diinginkan.

Baris kosong terakhir menghitung jumlah kecocokan string kosong dalam string, yang merupakan satu lebih dari jumlah karakter dalam string, setara dengan hasil 1-diindeks.

Leo
sumber
Saya menemukan teknik baru untuk mencocokkan string seimbang kemarin yang menghemat dua byte pada kedua jawaban kami: tio.run/##K0otycxL/K@q4Z7wX0/D3kbX0E4jOlqj2iZWU0tPU0uFi@v/… (dan mungkin selusin yang lain yang saya tulis di dalam masa lalu ...)
Martin Ender
5

Perl 5 , 28 byte

Disimpan 6 byte dengan menggunakan hanya .bukan [>})\]], dari Martin Ender ini Retina jawaban .

27 byte kode + -pbendera.

/([<{([](?0)*.)+?/;$_=$+[0]

Cobalah online!

Regex rekursif, penemuan yang indah.
Regex mencari braket pembuka ([<{([] ), diikuti dengan panggilan rekursif ( ?0), diikuti oleh braket penutup ( .). Semua ini tidak rakus ( +?) sehingga cocok sesingkat mungkin dari awal. Indeks akhir pertandingan adalah jawabannya, dan ketika itu terjadi, dapat ditemukan di $+[0].

Dada
sumber
4

JavaScript (ES6), 55 53 52 byte

Disimpan 1 byte berkat @Adnan

f=([c,...s],i=1)=>(i-=-c.charCodeAt()&2)&&1+f(s,++i)

Untuk setiap braket pembuka, mengambil mod kode-nya 4 memberi kita 0 atau 3; untuk kurung penutup, memberi kita 1 atau 2. Oleh karena itu, kita dapat membedakan antara kurung buka dan tutup dengan meniadakan kode-braket braket (yang membalik bit dan mengurangi 1) dan mengambil bit paling tidak signifikan kedua; itu adalah n&2,.

Produksi ETH
sumber
Saya berpikir bahwa alih-alih n-1&2, -n&2juga berfungsi?
Adnan
@ Adnan Hmm, saya pikir Anda benar. Terima kasih!
ETHproduksi
4

C, 75 72 56 55 54 45 byte

a;f(char*s){return(a-=(-*s++&2)-1)?1+f(s):0;}

Lihat itu berfungsi online .

Jika Anda ingin output diindeks 1 daripada diindeks 0, ganti yang terakhir 0dengan 1.

2501
sumber
4

Python 2.7 + Numpy, 85 79 byte

Upaya pertama saya di kode golf:

from numpy import*
lambda s:list(cumsum([(ord(x)+1&2)-1for x in s])).index(0)
acidtobi
sumber
1
Selamat datang di situs ini!
DJMcMayhem
1
Anda tidak harus menyebut lambdas, Anda dapat menghapus g =
Pavel
4

Brain-Flak , 97 byte (96 untuk kode, 1 untuk bendera)

{}<>(())({<(<()>)<>({<({}[()])><>([{}]())<>}{})<>(<{}>())<>{({}[()])<>([{}])<>}{}<>({}{})>()}{})

Jalankan dengan -a bendera.

Cobalah online!

Penjelasan:

#Skip the first open bracket 
{}

#Place a 1 on stack B, representing the nesting depth
<>(())

#Start a loop, until the depth is 0
({<

 #Divide the ASCII code by 2, rounding up
 (<()>)<>({<({}[()])><>([{}]())<>}{})<>

 #Replace TOS B with a 1
 (<{}>())

 #Swap back to stack A
 <>

 #Negate the 1 on stack B n times (n = ASCII value+1/2)
 {({}[()])<>([{}])<>}{}

 #Swap back to stack B
 <>

 #Add the 1/-1 (depending on Open/close bracket) to the nesting depth accumulator
 ({}{})

 #Count loop cycles
 >()

#end loop, print result implicitly by pushing to the stack 
}{}) 

Itu hanya berfungsi, oke.

MegaTom
sumber
3

Retina , 34 byte

^.
!
T`([{}])`<<<>
+T`p`!`<!*>
\G!

Cobalah online!

Hasilnya berbasis 0.

Penjelasan

^.
!

Ganti karakter pertama dengan a !. Ini menyebabkan braket yang kami cari tidak tertandingi.

T`([{}])`<<<>

Ubah tanda kurung, kurung siku dan kurung kurawal ke kurung siku. Karena string dijamin sepenuhnya cocok, kami sama sekali tidak peduli dengan tipe yang sebenarnya, dan ini menghemat beberapa byte pada langkah berikutnya.

+T`p`!`<!*>

Berulang-ulang ( +) ganti setiap karakter di semua kecocokan <!*>dengan !s. Artinya, kami mencocokkan pasangan kurung yang tidak mengandung tanda kurung yang tidak diproses lebih lanjut dan mengubahnya menjadi tanda seru lebih lanjut. Ini akan mengubah seluruh string kecuali braket penutup yang tidak cocok menjadi tanda seru.

\G!

Hitung jumlah tanda seru terdepan, yang sama dengan posisi berbasis 0 dari tanda non-seru pertama (yaitu braket yang tidak cocok). The \Gjangkar setiap pertandingan dengan yang sebelumnya, yang mengapa ini tidak menghitung !s setelah braket kata.

Martin Ender
sumber
Saya melihat Anda telah menjawab di beranda dan tahu itu akan menggunakan semacam regex
Christopher
@ Chris Eh, yang ini hampir tidak menggunakan regex sama sekali (sebagai lawan dari jawaban Retina lainnya yang baru saja saya posting ...).
Martin Ender
Sheesh. Regex banyak?
Christopher
Mengapa tidak ini bekerja?
Bocor Nun
@ LeakyNun Karena (?!(2))adil (?!2). Anda mungkin berarti (?(2)(?!))atau (?2)!). Anda juga lupa untuk lolos ]dan final+ harus *.
Martin Ender
2

PHP, 116 Bytes

for($l=["("=>")","["=>"]","{"=>"}","<"=>">"][$f=$argn[0]];;$d>0?$i++:die("$i"))$d+=$f!=($n=$argn[$i])?$n==$l?-1:0:1;

Versi Online

Jörg Hülsermann
sumber
Tidakkah PHP perlu memulainya <?php?
Pavel
@Phoenix: Ada penerjemah PHP mandiri yang tidak memerlukan tag awal. Itulah yang biasanya digunakan untuk bermain golf.
@ ais523 Dalam hal ini PHP dijalankan dari baris perintah dengan opsi -R
Jörg Hülsermann
2

Python , 76 byte

f=lambda s,r=[],i=0:(i<1or sum(r))and f(s[1:],r+[(ord(s[0])+1&2)-1],i+1)or i

Fungsi rekursif yang menggunakan LSB 2nd ordinal sebagai bendera untuk trik buka vs tutup yang digunakan oleh banyak ditemukan oleh Adnan (dan mungkin yang lain). Ekor hits ketika jumlah kumulatif-1 untuk membuka dan 1menutup mencapai nol. Indeks disimpan dalam variabel karena byte-lebih murah daripada menggunakan len(r), pengindeksan adalah berbasis 1.

Cobalah online!

Jonathan Allan
sumber
2

Ruby, 35 34 byte

p$_[/[<{(\[](\g<0>)*[>})\]]/].size

Berdasarkan jawaban Dada's Perl5 . Output diindeks 1. Membutuhkan interpreter Ruby untuk dipanggil dengan-n opsi ( while getsloop implisit ).

Sunting: Ini juga 35 34 byte, tetapi merupakan titik awal lain yang mungkin untuk mengurangi jawaban ini lebih lanjut.

p$_[/[<{(\[](\g<0>)*[>})\]]/]=~/$/

Sunting2: Menghapus spasi yang tidak perlu setelah p.

Sunting3: Sepasang lagi jawaban 34-byte.

~/[<{(\[](\g<0>)*[>})\]]/;p$&.size
p~/[<{(\[](\g<0>)*[>})\]]/+$&.size
Ray Hamel
sumber
2
Selamat datang di PPCG!
Pavel
1
Sangat dihargai! :)
Ray Hamel
2

Python 3 , 59 55 50 49 byte

f=lambda s,n=1:n and-~f(s[1:],n+1-(-ord(s[1])&2))

Output diindeks 0. Rumus untuk menentukan arah braket pertama kali ditemukan oleh @ETHProductions dan ditingkatkan oleh @Adnan.

Cobalah online!

Dennis
sumber
1

Batch, 172 byte

@set/ps=
@set/ai=d=0
:l
@set/ai+=1,d-=1
@set c="%s:~,1%"
@set "s=%s:~1%
@for %%a in ("<" "(" "[" "{")do @if %%a==%c% set/ad+=2&goto l
@if %d% gtr 0 goto l
@echo %i%

1-diindeks. <>Tentu saja karakter khusus dalam Batch jadi saya tidak hanya harus mengutip seluruh tetapi saya bahkan tidak bisa melakukan trik seperti membuat mereka gotolabel.

Neil
sumber
1

R, 126 Bytes

s=readline();i=0;r=0;for(c in strsplit(s,"")[[1]]){if(grepl("[\\[\\(\\{<]",c))i=i+1 else i=i-1;if(i==0){print(r);break};r=r+1}
Neil
sumber
0

C, 127 byte

Coba Online

c(x){x-40&x-60&x-91&x-123?-1:1;}
f(i,t)char*t;{return i?f(i+c(*t),t+1):t;}
s(char*t){return f(c(*t),t+1)-t;}

Keluaran

2   ()
4   (<>)
8   <[]{<>}>
2   {}{}{}{}
8   [[]<>[]]
Khaled.K
sumber
Setiap komentar, downvoter.
Khaled.K
Saya bukan downvoter, tapi saya pikir itu tidak membantu karena sudah ada pengiriman C yang jauh lebih pendek.
Ørjan Johansen