# Detecting loops in in in strings

Given a string, mark which parts in the string repeat in box brackets, and write how many times it does so before the box.

Example:st st st Hello ThereThere
st(with a space after) repeats 3 times, There repeats 2 times, and l repeats 2 times in Hello, so the output will be:
3[st ]He2[l]o 2[There]
There is no space between [st ] and Hello because the space in the string is being taken up by the repeating part. [st ], 3 times with a Hello after it would be st st st Hello, which is what the string has.

Other examples:
st Hello st st Bye -> st He2[l]o 2[st ]Bye
Bookkeeper -> B2[o]2[k]2[e]per
/\/\/\\\\\\\\/\/\/ -> 3[/\]6[\]3[\/]

Shortestest code wins.

EDIT: To clarify the choice of selections, choose the largest possible repeating section, and try and leave as little non-repeating characters as possible. Do not nest boxed-in sections.

• This is ambiguous. For example, ababababcabcabc -> 4[ab]2[cab]c? 4[ab]c2[abc]? 3[ab]3[abc]? What bout abcdefdefghiabcdefdefghi -> 2[abcdefdefghi]? abc2[def]ghiabc2[def]ghi? 2[abc2[def]ghi]? Jul 26, 2012 at 6:06
• this is not possible ;) just the typical first answer I get whenever I ask a developer something. Jul 26, 2012 at 6:41
• Shouldn't the output to your first example be "3[st ]He2[l]o 2[There]"? (Same for the second.) Jul 26, 2012 at 8:20
• Why gets “st Hello st st Bye” transformed into “st Hello 2[st ]Bye” and not into “st Hello2[ st] Bye”? So the repeating substring why not starts with the first repeated character, the space before “st”? Jul 26, 2012 at 8:54
• The specification is still ambiguous because it lists multiple goals without clearly stating their relative priority, and without indicating what level of naïvety is acceptable. I don't see the point in constructing complicated test cases to elucidate the points: either the question needs to be largely rewritten to give precise acceptance criteria or it needs to be amended to indicate that wide latitude will be given. Jul 28, 2012 at 21:33

## Perl, 36 bytes

#!perl -p
s!(.+)\1+!@{[$&=~/\Q$1/g]}."[$1]"!eg  Try it online! ## PHP 5.6, 68 bytes Same code in PHP. Requires the command line option -F, and relies on deprecated /e modifier. <?=preg_filter('/(.+)\1+/e','substr_count("\0","\1")."[\1]"',$argn);


## scala, 102 chars

print("(?!\\s)(.+)\\1+".r.replaceAllIn(readLine,m=>m.matched.size/m.group(1).size+"["+m.group(1)+"]"))


Output

st st st Hello ThereThere ->    3[st ]He2[l]o 2[There]
st Hello st st Bye        ->    st He2[l]o 2[st ]Bye
Bookkeeper                ->    B2[o]2[k]2[e]per
/\/\/\\\\\\\\/\/\/        ->    3[/\]2[\\\]3[\/]

• +1, nice use of Regex.Match Jul 26, 2012 at 19:22

## C, 224 205 203 199 195 193 chars

The string is given as program parameter. As usual, use double quotes if your string contains spaces, and for empty strings - calling the program without any parameter crashes, but calling with "" works.

Output for test cases is:

st st st Hello ThereThere => 3[st ]He2[l]o 2[There]
Bookkeeper                => B2[o]2[k]2[e]per
/\/\/\\\\\\\\/\/\/        => 3[/\]2[\\\]3[\/]


which looks correct to me regarding "choose the largest possible repeating section".

Code:

l,r,f,i;char*c;main(a,b)char**b;{l=strlen(c=b);for(;putchar(*c);c++)for(a=l;--a;f=0)for(r=a;!f;r+=a){for(i=0;i<a;)f|=r>l||c[i]-c[r+i++];if(f*r>a)c[a]=0,printf("\b%i[%s]",r/a,c),c+=r-1,a=1;}}


# Retina, 4037 24 bytes

(.+)(\1)+
$.($#2*__)[$1]  -13 bytes thanks to @Neil. Try it online or verify all test cases. (NOTE: Slightly different results for some test cases in comparison to the challenge description, but still the same as the accepted answer, so I assumed both are valid.) Explanation: (.+)(\1)+ # Look for the repeated sections (where the repeated string is captured in # group 1, and every time it's repeated in group 2)  Example: in the input "st st st Hello ThereThere" it will find the capture group 1 and 2 as: "st " & ["st ","st "]; "l" & ["l"]; and "There" & ["There"] respectively. $#2          # Get the amount of times group 2 was repeated
*_        # Converted to unary (that amount of '_')
$.( ) # Convert that unary back to a number again by taking the length [$1]  # And append the match of the first capture group between block-quotes

Example: "st st st " will become "3[st ]"; "ll" will becomes "2[l]"; and "ThereThere" will become "2[There]". So "st st st Hello ThereThere" is now the intended result "3[st ]He2[l]o 2[There]" (which is output implicitly).
s|(.+)\1+|(length($&)/length$1)."[$1]"|ge  Try it online! # PowerShell, 82 bytes [regex]::Replace($args,'(.+)\1+',{$a,$g=$args|% gr* "$($a.Length/$g.Length)[\$g]"})