# Balanced triplet brackets

A "triplet bracket" (that I made up for this challenge) is one of the following:

(...+...)
[...:...]
{...|...}
<...-...>


A balanced triplet bracket string (BTBS for short) is either an empty string, two BTBSes concatenated, or one of the above triplet brackets with each ... replaced with a BTBS.

Your task is to write a program or function that checks whether a string that consists of only (+)[:]{|}<-> is balanced. Shortest code wins.

## Examples

Your program should return truthy for the following strings:

(+)(+)(+)
[[[:]:]:(+(+))]{<->|<(+)->[:]}(+)
<<<<<<<<<<<<->->->->->->->->->->->->
{|(+[:<-{|(+[:<->])}>])}
[[[:]:[:]]:[[:]:[:]]]
{[:](+)|<->{|}}[(+)<->:{|}(+)]


Your program should return falsy for the following strings:

:[
<|>
(+(+)
[:][:](+[[:]):]
{|{|{|(+{|{|{|}}}}}+)}[:]{|}
{{||}}
<<->-<->-<->>
[(+):((+)+)+(+(+))]
<<<<<->->->->->->

• Is (|) valid. I don't think so, but I'm not sure Oct 22 '16 at 12:37
• @RomanGräf No, as <|> in the falsy examples. Oct 23 '16 at 7:14

# Japt, 25 bytes

!Ue"%(%+%)|%[:]|\{%|}|<->


Test it online!

e on strings is a recursive-replace function. The second parameter defaults to the empty string, which means this recursively removes matches of the Japt regex "%(%+%)|%[:]|\{%|}|<->" (in regular terms, /$$\+$$|$:]|{\|}|<->/). This returns an empty string for balanced triplet strings and a non-empty string for non-balanced, so the correct return value is the logical NOT of this. ## JavaScript (ES6), 775857 56 bytes f=s=>s==(s=s.replace(/$$\+$$|\[:]|{\|}|<->/,''))?!s:f(s)  ### Test cases f=s=>s==(s=s.replace(/$$\+$$|\[:]|{\|}|<->/,''))?!s:f(s) console.log("Testing truthy values"); console.log(f("(+)(+)(+)")); console.log(f("[[[:]:]:(+(+))]{<->|<(+)->[:]}(+)")); console.log(f("<<<<<<<<<<<<->->->->->->->->->->->->")); console.log(f("{|(+[:<-{|(+[:<->])}>])}")); console.log(f("[[[:]:[:]]:[[:]:[:]]]")); console.log(f("{[:](+)|<->{|}}[(+)<->:{|}(+)]")); console.log("Testing falsy values"); console.log(f(":[")); console.log(f("<|>")); console.log(f("(+(+)")); console.log(f("[:][:](+[[:]):]")); console.log(f("{|{|{|(+{|{|{|}}}}}+)}[:]{|}")); console.log(f("{{||}}")); console.log(f("<<->-<->-<->>")); console.log(f("[(+):((+)+)+(+(+))]")); console.log(f("<<<<<->->->->->->")); • The same idea in Retina is 26 bytes (the first line just makes it a test suite): retina.tryitonline.net/… Oct 22 '16 at 11:17 • And 39 with perl : perl -lpe 's/<->|$$\+$$|{\|}|\[:]//&&redo;_=!_'. – Dada Oct 22 '16 at 11:33 • @Dada That will consider 0 a BTBS. Use this 38 instead: perl -pe 's/<->|$$\+$$|{\|}|\[:]//&&redo;_=/^/' Oct 22 '16 at 11:45 • @TonHospel Didn't thought of that, indeed.. thanks for pointing it out! (feel free to post it if you want by the way, or at least don't hold back because of me) – Dada Oct 22 '16 at 11:48 • That S/s mix was slightly confusing, perhaps f=s=>s==(s=s.replace(...))?!s:f(s)? – Neil Oct 23 '16 at 10:25 # sed, 28 27 bytes : s#(+)\|\[:]\|{|}\|<->## t  sed doesn't have a concept of truthy/falsy, so I'm considering an empty string truthy and a non-empty string falsy. This checks out if we consider the conditional /^/. Thanks to @Neil for golfing off 1 byte! Try it online! • For once, BRE is actually an advantage. Oct 22 '16 at 15:23 • Do you need the $ or does ] suffice?
– Neil
Oct 23 '16 at 10:26
• I don't. Thanks! Oct 23 '16 at 12:45

## Python, 77 bytes

lambda s:eval("s"+".replace('%s','')"*4%('(+)','[:]','{|}','<->')*len(s))==''


Uses Arnauld's replacement idea. Generates and evaluates a long string like

s.replace('(+)','').replace('[:]','').replace('{|}','').replace('<->','').replace('(+)','').replace('[:]','').replace('{|}','').replace('<->','')


to cycle between replacing all the bracket types. Then, checks if the result is the empty string.

# Mathematica, 55 bytes

StringDelete["(+)"|"[:]"|"{|}"|"<->"]~FixedPoint~#==""&


Anonymous function. Takes a string as input and returns True or False as output. Uses the standard method for doing this.

## Grime, 39 bytes

e$$_\+_$$|$_\:_$|\{_\|_\}|\<_\-_\>v*


Try it online! Sadly, the TIO version runs out of memory on most of the test cases.

## Explanation

Nothing too fancy here. _ is shorthand for the entire pattern, and v* is the same as *, but with lower precedence.

e                                       Match entire input against this pattern:
$$_\+_$$                               '(', match of _, '+', match of _, ')'
|                              or
$_\:_$|\{_\|_\}|\<_\-_\>    same for the other bracket types
v*  repeated 0-∞ times


# J, 48 bytes

a:=([:delstring&.>/'(+)';'[:]';'{|}';'<->';])^:_


Similar to the others, this is also based on Arnauld's method.

## Usage

   f =: a:=([:delstring&.>/'(+)';'[:]';'{|}';'<->';])^:_
f '(+)(+)(+)'
1
f '[[[:]:]:(+(+))]{<->|<(+)->[:]}(+)'
1
f '<<<<<<<<<<<<->->->->->->->->->->->->'
1
f '<|>'
0
f '[:][:](+[[:]):]'
0
f '{|{|{|(+{|{|{|}}}}}+)}[:]{|}'
0


## Explanation

a:=([:delstring&.>/'(+)';'[:]';'{|}';'<->';])^:_  Input: string S
(                                        )^:_  Repeat until convergence
]          Get S
'(+)';'[:]';'{|}';'<->';           Append to ['(+)', '[:]', '{|}', '<->']
[:delstring&.>/                                 Reduce right-to-left by deleting
occurrences of each string on the
left from the right
Return the final string as the new S
a:=                                               Test if the final value of S is empty


## Pip, 26 bytes

L#aaR:"(+)[:]{|}<->"<>3x!a


Try it online!

Loops len(a) times, replacing all occurrences of empty triplet brackets ("(+)[:]{|}<->"<>3, where <> is the "group" operator, => ["(+)"; "[:]"; "{|}"; "<->"]) with empty string (x). This many iterations is overkill, but it will always be more than enough to completely reduce all properly formed triplet brackets to nothing. After the loop completes, outputs !a: 0 if a is truthy (still has some characters), 1 if a is falsey (empty).

# Scala, 96 bytes

def&(s:String):Any={val t=s.replaceAll(raw"$$\+$$|\[:]|\{\|}|<->","")
if(t==s)t.size<1 else&(t)}


This is basically the same idea as the other answers, but with some scala boilerplate.

### without stealing ideas from others (188 bytes):

import scala.util.parsing.combinator._
val a = new RegexParsers{def r:Parser[_]="("~r~"+"~r~")"|"["~r~":"~r~"]"|"{"~r~"|"~r~"}"|"<"~r~"-"~r~">"|""
def!(s:String)= !parseAll(r,s).isEmpty}!_