Your challenge is to expand some brackets in a program's input as shown:

  1. Find a string s between two matching brackets [ and ], with a single digit n after the closing bracket.
  2. Remove the brackets.
  3. Replace s with itself repeated n times. (If n is 0, simply remove s.)
  4. Go to step 1 until there are no more matching brackets in the input.

Additional rules and clarifications:

  • You will take input and give output via any allowed means.
  • A trailing newline in the output is allowed.
  • You only need to handle printable ASCII in the input.
  • You may assume that all brackets match, i.e. you will never receive the input []]]] or [[[[].
  • You may assume that each closing bracket ] has a digit after it.

Test cases:

Input                -> Output
[Foo[Bar]3]2         -> FooBarBarBarFooBarBarBar
[one]1[two]2[three]3 -> onetwotwothreethreethree
[three[two[one]1]2]3 -> threetwoonetwoonethreetwoonetwoonethreetwoonetwoone
[!@#[$%^[&*(]2]2]2   -> !@#$%^&*(&*($%^&*(&*(!@#$%^&*(&*($%^&*(&*(
[[foo bar baz]1]1    -> foo bar baz
[only once]12        -> only once2
[only twice]23456789 -> only twiceonly twice3456789
[remove me!]0        -> 
before [in ]2after   -> before in in after

As this is , the shortest answer in each language wins. Good luck!

  • \$\begingroup\$ Sandboxed post. \$\endgroup\$ – MD XF Jan 30 '18 at 2:24
  • 13
    \$\begingroup\$ You should post another challenge to compress a string back down to its shortest format \$\endgroup\$ – Jo King Jan 30 '18 at 9:11
  • \$\begingroup\$ Is it worth stating explicitly that your string s should never contain other brackets? For example, attempting to solve [Foo[Bar]3]2 by expanding the string Foo[Bar 3 times would result in an invalid state Foo[BarFoo[BarFoo[Bar]2 \$\endgroup\$ – BradC Jan 30 '18 at 20:17
  • \$\begingroup\$ @BradC that all depends on how you choose to implement the task. \$\endgroup\$ – MD XF Jan 30 '18 at 21:59
  • \$\begingroup\$ Does that mean that there are two valid answers to [a[b]2c[d]2e]2? You get abbcddeabbcdde by expanding b and d first, but ababcdbcdedbabcdbcdede by expanding a[b and d]2e first. \$\endgroup\$ – BradC Jan 30 '18 at 22:23

19 Answers 19


Gema, 17 characters


Sample run:

bash-4.4$ gema '[#]?=@repeat{?;#}' <<< '[three[two[one]1]2]3'
  • \$\begingroup\$ Wow, talk about finding the right language for the job! \$\endgroup\$ – MD XF Jan 31 '18 at 2:00
  • \$\begingroup\$ Or the right job for the language. Many challenges had to skip because the recursive argument was not flexible enough. \$\endgroup\$ – manatwork Jan 31 '18 at 8:57
  • \$\begingroup\$ Accepting this for now cause I don't see any way it's getting beat, but it'll be unaccepted in the unlikely case that it does. \$\endgroup\$ – MD XF Feb 2 '18 at 3:59

Retina, 24 23 22 bytes


Try it online! This is practically a builtin in Retina 1. Edit: Saved 1 byte thanks to @Kobi. 47 45 bytes in Retina 0.8.2:


Try it online!


Haskell, 101 96 bytes

infix 4%

Try it online! Instead of using regular expression like most of the other answers, this implements a recursive parser.

-5 bytes thanks to BMO!

  • 4
    \$\begingroup\$ A fixity declaration for (%) saves you 1 byte and ['1'..d] saves you another 4, see this. \$\endgroup\$ – ბიმო Jan 30 '18 at 8:12
  • 3
    \$\begingroup\$ @BMO Nice, I didn't expect a fixity declaration would ever be useful for code golfing. I think you should add that to the tips question. \$\endgroup\$ – Laikoni Jan 30 '18 at 8:39

Perl 5, 34 33 29 + 1 (-p) = 30 bytes


Try it online!

Cut it down with some help from @Shaggy and @TonHospel.

  • 3
    \$\begingroup\$ I don't know pearl but redo seems gorgeous! \$\endgroup\$ – officialaimm Jan 30 '18 at 4:02
  • \$\begingroup\$ I think you should be able to save a byte by not escaping the ]. \$\endgroup\$ – Shaggy Jan 30 '18 at 11:05
  • 1
    \$\begingroup\$ I don't know Perl but this seems to work for 30+1 bytes. \$\endgroup\$ – Shaggy Jan 30 '18 at 11:12
  • 2
    \$\begingroup\$ These 29+1 also work: perl -pe 's/.([^[]*?)](.)/$1x$2/e&&redo' and perl -pe 's/.([^][]*)](.)/$1x$2/e&&redo' \$\endgroup\$ – Ton Hospel Jan 30 '18 at 15:07

Japt v2, 21 20 19 bytes

Saved 2 bytes thanks to @Shaggy


Test it online!

e is recursive replace, which makes one replacement at a time until there are no more matches. In this case, matches of the regex /\[([^[]*?)](\d)/g are replaced with with <inner text> repeated <digit> times until there are no more matches.

According to what I have planned (here), this regex should eventually be at least 3 2 bytes shorter:

  • 2
    \$\begingroup\$ As we "may assume that each closing bracket ] has a digit after it" you should be able to replace (\d with (.. \$\endgroup\$ – Shaggy Jan 30 '18 at 8:19
  • \$\begingroup\$ You can also replace \[ with . \$\endgroup\$ – Shaggy Jan 30 '18 at 19:27
  • \$\begingroup\$ @Shaggy Nice, thanks! \$\endgroup\$ – ETHproductions Jan 30 '18 at 23:05

JavaScript, 71 67 66 bytes

I had a 54 byte solution but it got screwed over by the second test case! :(


Test Cases

[[foo bar baz]1]1
[only once]12
[only twice]23456789
[remove me!]0
before [in ]2after`.split`\n`.map(x=>x.padEnd(22)+`:  `+f(x)).join`\n`
<pre id=o></pre>


Python 3, 110 93 92 bytes

import re
f=lambda s:f(re.sub(r'\[([^][]+)\](.)',lambda m:m[1]*int(m[2]),s))if'['in s else s

Try it online!

-17 bytes thanks to pizzapants184 -1 byte thanks to Kevin Cruijssen

  • 1
    \$\begingroup\$ -17 bytes in Python 3 with re.match indexing and substring check using in. \$\endgroup\$ – pizzapants184 Jan 30 '18 at 18:12
  • 1
    \$\begingroup\$ -1 byte by changing (\d) to (.), because we know a block-bracket ] is always followed by a digit. \$\endgroup\$ – Kevin Cruijssen Feb 1 '18 at 12:28

Scala, 173 bytes

l.foreach{x=>def r(c:String):String={val t="""\[([^\[\]]*)\](.)""".r.unanchored;c match{case t(g,h)=>r(c.replaceAllLiterally(s"[$g]$h",g*h.toInt));case _=>c}};println(r(x))}

Try it online!


l.foreach { x =>
  def remove(current: String): String = {
    val test ="""\[([^\[\]]*)\](.)""".r.unanchored
    current match {
      case test(g, h) => remove(current.replaceAllLiterally(s"[$g]$h", g * h.toInt))
      case _ => current


Old solution

Scala, 219 215 213 212 199 bytes

l.foreach{x=>def r(c:String):String={"""\[([^\[\]]*)\](.)""".r.findFirstMatchIn(c).map{x=>val g=x.group(1);val h=x.group(2).toInt;r(c.replaceAllLiterally(s"[$g]$h",g*h))}.getOrElse(c)};println(r(x))}

Try it online!


l.foreach { x =>
  def remove(current: String): String = {
    """\[([^\[\]]*)\](.)""".r.findFirstMatchIn(current).map { x =>
      val g = x.group(1)
      val h = x.group(2).toInt
      remove(current.replaceAllLiterally(s"[$g]$h", g * h))

Where l is the list of strings that we will process.

Thanks Kevin Cruijssen for -1 byte

Went from 212 to 199 by removing an unused parameter, didn't pay attention.

  • 4
    \$\begingroup\$ Welcome to PPCG! Try tio's scala interpreter at tio.run/#scala and see if you can submit a link for the answer, so that others can try it online. :) \$\endgroup\$ – officialaimm Jan 31 '18 at 9:16
  • 2
    \$\begingroup\$ Thank you! I edited the answer to include the link. Hopefully it is ok how the header, code and footer is declared in order to be a proper submission. \$\endgroup\$ – Shikkou Jan 31 '18 at 10:17
  • 1
    \$\begingroup\$ Hi, welcome to PPCG! Great first answer, +1 from me. I think you can save 1 byte by changing (\d) to (.), because we know a block-bracket ] is always followed by a digit. \$\endgroup\$ – Kevin Cruijssen Feb 1 '18 at 12:26

Stacked, 39 38 bytes

Saved 1 byte thanks to Shaggy, golfed the regex!

['\[([^[\]]+)](.)'{.y x:x#~y*}recrepl]

Try it online!

Simply recursively replaces a regex '\[([^[\]]+)](.)' with the repetition rule.

  • \$\begingroup\$ I think you can save a byte by not escaping the last ]. \$\endgroup\$ – Shaggy Jan 30 '18 at 11:15

Python 3, 155 148 101 97 bytes

def f(x):
 return x

Try It Online

Thanks to HyperNeutrino and Mego for -47 bytes and user202729 for -4 bytes.

  • \$\begingroup\$ Make it a one-liner to save a couple bytes: def f(x):a=x.rfind('[');b=x.find(']',a);return f(x[:a]+x[a+1:b]*int(x[b+1])+x[b+2:])if~a else x \$\endgroup\$ – mathmandan Jan 31 '18 at 23:01

JavaScript - 77 75 72 bytes


Edit: updated regex with Shaggy's recommendation


const test = ["[Foo[Bar]3]2", "[one]1[two]2[three]3", "[three[two[one]1]2]3", "[!@#[$%^[&*(]2]2]2", "[[foo bar baz]1]1", "[only once]12", "[only twice]23456789", "[remove me!]0", "before [in ]2after"];

const f=a=>a.replace(/(.*)\[([^[]*?)](.)(.*)/,(a,b,c,d,e)=>f(b+c.repeat(d)+e))

<p id="d">

  • 2
    \$\begingroup\$ Welcome to PPCG! You can get this down to 70 bytes by tweaking your RegEx. \$\endgroup\$ – Shaggy Jan 31 '18 at 10:21
  • \$\begingroup\$ Yes, 72 bytes, obviously, sorry; I was forgetting to count the f=! \$\endgroup\$ – Shaggy Feb 1 '18 at 17:40

QuadR with the argument, 30 28 bytes


Try it online!

\[[^[]+?]. replace "[non-[ stuff]character" with

¯2↓⍵M drop the last two characters of the Match ("]digit")
1↓ drop the first character ("[")
 enclose to be treated as a whole
()⍴reshape to length:
⌽⍵M reverse the Match
 pick the first (the digit)
ϵnlist (flatten)

 repeat until no more changes happen

The equivalent Dyalog APL function is 47 bytes:


Try it online!


Java 8, 250 249 241 239 bytes

s->{for(;s.contains("[");)for(int i=0,j,k;i<s.length();)if(s.charAt(i++)==93){String t="",r=t;for(j=k=s.charAt(i)-48;j-->0;)t+=s.replaceAll(r="(.*)\\[([^\\]]+)\\]"+k+"(.*)","$2");s=k<1?t:s.replaceFirst(r,"$1$3").replace("",t);}return s;}

-2 bytes thanks to @JonathanFrech (code contains two unprintable ASCII characters now, which can be seen in the TIO-link below).

Sigh... Java with regex is so damn limited.. I'll just quote myself from another answer here:

Replacing WWWW with 222W is easy in Java, but with 4W not.. If only Java had a way to use the regex capture-group for something.. Getting the length with "$1".length(), replacing the match itself with "$1".replace(...), converting the match to an integer with new Integer("$1"), or using something similar as Retina (i.e. s.replaceAll("(?=(.)\\1)(\\1)+","$#2$1")) or JavaScript (i.e. s.replaceAll("(.)\\1+",m->m.length()+m.charAt(0))) would be my number 1 thing I'd like to see in Java in the future to benefit codegolfing.. >.> I think this is the 10th+ time I hate Java can't do anything with the capture-group match..
Quote from here.


Try it online.

s->{                           // Method with String as both parameter and return-type
  for(;s.contains("[");)       //  Loop as long as the String contains a block-bracket
    for(int i=0,j,k;i<s.length();)
                               //   Inner loop over the characters of the String
      if(s.charAt(i++)==93){   //    If the current character is a closing block-bracket:
        String t="",r=t;       //     Create two temp-Strings, starting empty
        for(j=k=s.charAt(i)-48;//     Take the digit after the closing bracket
            j-->0;)            //     Loop that many times:
                               //      Append `t` with the word inside the block brackets
        s=k<1?                 //     If the digit was 0:
           t                   //      Replace the input with an empty String as well
          :                    //     Else:
                               //      Replace the word between brackets by `t`,
                               //      and remove the digit
  return s;}                   //  Return the modified input-String as result
  • 1
    \$\begingroup\$ I think you can use a truly ASCII though unprintable character to save two bytes. (Your solution really takes 241 bytes, 239 characters.) \$\endgroup\$ – Jonathan Frech Jan 30 '18 at 18:54
  • \$\begingroup\$ @JonathanFrech Thanks! Was looking for a 1-byte character outside the printable ASCII range. Didn't thought about using an unprintable.. \$\endgroup\$ – Kevin Cruijssen Jan 31 '18 at 7:54

Wolfram Language (Mathematica), 86 bytes


Try it online!


C, 407 368 bytes

Thanks to Jonathan Frech for saving bytes.

golfed (file bracket.c):

i,j,k,l,n;char*f(a,m)char*a;{for(i=0;a[i];++i){a[i]==91&&(j=i+1);if(a[i]==93){k=a[i+1]-48;if(!k){for(l=i+2;l<m;)a[++l-i+j-4]=a[l];a=realloc(a,m-3);return f(a,m-3);}for(l=j;l<i;)a[~-l++]=a[l];for(l=i+2;l<m;)a[++l-4]=a[l];m-=3;n=m+~-k*(i---j--);a=realloc(a,n);for(l=i;l<m;)a[l+++~-k*(i-j)]=a[l];for(m=0;m<k;++m)for(l=j;l<i;)a[l+++m*(i-j)]=a[l];return f(a,n);}}return a;}

ungolfed with program:

#include <stdlib.h>
#include <stdio.h>

// '[' = 133
// ']' = 135
// '0' = 48

i, j, k, l, n;

char* f(a,m) char*a;
  for (i=0; a[i]; ++i) {

    if (a[i]==93) {

      if (!k) {
        for (l=i+2; l<m; )
          a[++l-i+j-4] = a[l];

        a = realloc(a,m-3);
        return f(a,m-3);
      for (l=j;l<i;)
        a[~-l++] = a[l];
      for (l=i+2; l<m; )
        a[++l-4] = a[l];
      m -= 3;
      n = m+~-k*(i---j--);
      a = realloc(a,n);

      for (l=i; l<m; )
        a[l+++~-k*(i-j)] = a[l];
      for (m=0; m<k; ++m)
        for (l=j; l<i;)
          a[l+++m*(i-j)] = a[l];

      return f(a,n);
  return a;

int main()
  char c[]="[Foo[Bar]3]2";
  char *b;

  char cc[]="[remove me!]0";
  char *bb;

  char ccc[]="[only once]12";
  char *bbb;


  for (i=0; i<13; ++i)
    b[i] = c[i];

  for (i=0; i<14; ++i)
    bb[i] = cc[i];

  for (i=0; i<14; ++i)

  printf("%s\n", f(b, 13));
  printf("%s\n", f(bb, 14));
  printf("%s\n", f(bbb, 14));

  return 0;

Compiled with gcc 5.4.1, gcc bracket.c

  • 1
    \$\begingroup\$ 368 bytes. \$\endgroup\$ – Jonathan Frech Jan 31 '18 at 18:16
  • \$\begingroup\$ 387 with the needed include (for realloc). I will do a clean update (with the ungolfed version) later. Thanks \$\endgroup\$ – Tsathoggua Feb 1 '18 at 6:54
  • \$\begingroup\$ If you use GCC, I think the compiler will attempt to guess the definition of both malloc and realloc, including stdlib.h by its own. \$\endgroup\$ – Jonathan Frech Feb 1 '18 at 12:06
  • \$\begingroup\$ I didn't know that. Nice feature for code golfing. Thanks. \$\endgroup\$ – Tsathoggua Feb 2 '18 at 7:12

Red, 147 bytes

f: func[t][a: charset[not"[]"]while[parse t[any a some[remove["["copy h any a"]"copy d a](insert/dup v: copy""h to-integer d)insert v | skip]]][]t]


f: func [t][
    a: charset [not "[]"]                          ; all chars except [ and ]
    while [ parse t [                              ; repeat while parse is returning true
        any a                                      ; 0 or more chars other than [ and ]
        some [                                     ; one or more block:
            remove ["[" copy h any a "]" copy d a] ; remove the entire block, store the
                                                   ; substring between the [] in h,
                                                   ; the digit into d
            (insert/dup v: copy "" h to-integer d) ; makes d copies of h 
            insert v                               ; and inserts them in place 
            | skip ]                               ; skip if no match
    ][]                                            ; empty block for 'while'
    t                                              ; return the modified string

I started learning Red's Parse dialect only yesterday, so I'm sure my code can be improved further. Parse is incomparably more verbose than regex, but is very clear, flexible and readable and can be freely mixed with the rest of the Red language.

Try it online!


Jelly, 30 bytes


Try it online!


œṡ”]µḢUœṡ”[ẋ€1¦Ṫ©Ḣ$FṚ;®    Helper link 1, expand once.
                           Assume input = "ab[cd]2ef".

œṡ      Split at first occurence of
  ”]      character "]".
    µ   Start new monadic chain. Value = "ab[cd","2ef".

Ḣ       ead. "ab[cd"
 U      Upend. "dc[ba"
  œṡ”[  Split at first occurence of "[". | "dc","ba".

ẋ€        Repeat ...
  1¦        the element at index 1...
          by ...
    Ṫ Ḣ$    the ead of the ail of ...
          the input list ("ab[cd","2ef") (that is, 2)

          The command  also pop the head '2'. The remaining
            part of the tail is "ef".
     ©    Meanwhile, store the tail ("ef") to the register.

          Current value: "dcdc","ba"
FṚ        Flatten and everse. | "abcdcd"
  ;®      Concatenate with the value of the register. "abcdcdef"

Çċ”]$¡    Main link.

 ċ”]$     Count number of "]" in the input.
     ¡    Repeatedly apply...
Ç           the last link...
            that many times.

C,381 bytes

Compact version:

while(1){int t=strlen(i);int a,c=-1;char*w;char*s;char*f;while(c++<t){if(i[c]==']'){int k=c-a;w=calloc((k--),1);memcpy(w,&i[a+1],k);s=calloc((t-c-1),1);memcpy(s,&i[c+2],t-c-2);i[a]=0;int r=i[c+1]-48;if(r==0){f=calloc(t,1);sprintf(f,"%s%s",i,s);}else{f=calloc((t+k),1);sprintf(f,"%s%s[%s]%d%s",i,w,w,r-1,s);}free(i);i=f;break;}else if(i[c]=='[')a=c;}free(w);free(s);if(c>=t)break;}

Full version:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void proceed(char* input)
    int t=strlen(input);
    int start,cursor=-1;
    char* word;
    char* suffix;
    char* final;
        int wordlength = cursor-start;
        memcpy(word, &input[start+1], wordlength );
        memcpy( suffix, &input[cursor+2], t-cursor-2 );
        int rep=input[cursor+1]-'0';
      else if(input[cursor]=='[')


int main()
  char* input=calloc(256,sizeof(char));
  printf("in : %s\n",input);
  printf("out: %s\n",input);
  return 0;
  • 3
    \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ – Shaggy Jan 30 '18 at 16:57
  • 1
    \$\begingroup\$ Welcome to the site! Note that C submissions need to be full programs or functions, not just snippets. \$\endgroup\$ – MD XF Jan 30 '18 at 22:12

Python, 80 bytes

import re
s=lambda x:eval(b(r"\](.)",r"')*\1+'",b(r"\[","'+('","%r"%x)))

Try it online!

s("[Foo[Bar]3]2") Converts [Foo[Bar]3]2 to ''+('Foo'+('Bar')*3+'')*2+'', and evaluates.

Fails for input with quotes in brackets (e.g. [']3)

  • \$\begingroup\$ I downvoted this answer as the question requires handling any printable ASCII in the input, and this answer doesn't. Notify me if you fix it, and I'll happily retract my vote. \$\endgroup\$ – caird coinheringaahing Feb 2 '18 at 16:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.