# Partition string into chunks

This seems like it should be trivial, but how do I partition a string into length n substrings? I can of course write something like

chunk[s_, n_] := StringJoin[#] & /@ Partition[Characters[s], n]


so that chunk["ABCDEF",2] -> {"AB","CD","EF"} but this appears unnecessarily cumbersome.

-
Welcome to Mathematica.SE! This is a good question, as there doesn't seem to be a direct built-in way (I bumped into this before). Please consider filling out the name field in your profile, so it will show as something easier to remember than 'user1268' – Szabolcs May 17 '12 at 9:19
– Szabolcs May 17 '12 at 10:22
Note StringJoin[#] & is the same as just StringJoin. – amr Oct 3 '12 at 19:59

Try this:

StringCases["ABCDEFGHIJK", LetterCharacter ~~ LetterCharacter]


{"AB", "CD", "EF", "GH", "IJ"}

or for more general cases (i.e. not just for letters, but any characters, and for any partition size):

stringPartition1[s_String, n_Integer] := StringCases[s, StringExpression @@ Table[_, {n}]];


It is more elegant though to use Repeated (thanks rcollyer):

stringPartition2[s_String, n_Integer] := StringCases[s, Repeated[_, {n}]];

stringPartition2["longteststring", 4]


{"long", "test", "stri"}

-
Instead of Table[_,{n}], I'd consider using Repeated[_, {n}], instead. – rcollyer May 17 '12 at 1:34
Thanks @rcollyer, I felt I missed something, but it was too late. Incorporated now. – István Zachar May 17 '12 at 9:50

Here is the regular-expression way:

chunk[s_, n_] :=
StringCases[s, RegularExpression[".{1," <> ToString[n] <> "}"]]

chunk["Hello this is a test string", 2]


{"He", "ll", "o ", "th", "is", " i", "s ", "a ", "te", "st", " s", "tr", "in", "g"}

chunk["Hello this is a test string", 4]


{"Hell", "o th", "is i", "s a ", "test", " str", "ing"}

Note that the last substrings didn't fit the chunk size but were still included.

If you don't want to include them, change the regular expression from ".{1," <> ToString[n] <> "}" to ".{" <> ToString[n] <> "}".

-

Another possibility:

StringTake[#,
Partition[Range@StringLength@#, 2, 2, 1, {}]] &@"abcdefghi"


giving

(*  {"ab", "cd", "ef", "gh", "i"} *)

-

Not completely original, but very compact.

chunk[s_, n_] := StringJoin@@@Partition[Characters[s], n, n, 1, {}]


Update for V10.1

This new function is exactly for that:

StringPartition["ABCDEF",2]


{"AB", "CD", "EF"}

-

This will give better performance (3 times faster in my test, partitioning into length-two strings) than your original code:

chunk[s_, n_] := FromCharacterCode@Partition[ToCharacterCode[s], n]


The reason is that the first few steps of the computation are done with packed arrays.

It will still be slower than the regex-based approaches (István's and Jens's), on my machine by a factor of 2.

The StringTake approach is much slower than all the others in my machine.

### Benchmarks

Function definitions:

(* original *)
chunk1[s_, n_] := StringJoin[#] & /@ Partition[Characters[s], n]

(* István *)
chunk2[s_, n_] := StringCases[s, Repeated[_, {n}]]

(* Jens *)
chunk3[s_, n_] := StringCases[s, RegularExpression[".{1," <> ToString[n] <> "}"]]

(* TomD *)
chunk4 = StringTake[#, Partition[Range@StringLength@#, #2, #2, 1, {}]] &;

(* mine *)
chunk5[s_, n_] := FromCharacterCode@Partition[ToCharacterCode[s], n]

text = ExampleData[{"Text", "Hamlet"}];
testString = StringJoin[ConstantArray[text, 20]];

StringLength[testString] (* 3438740 *)


Timings:

(* original *)
In[10]:= Timing[chunk1[testString, 2];]
Timing[chunk1[testString, 100];]

Out[10]= {5.968, Null}
Out[11]= {1.703, Null}

(* István - fastest *)
In[12]:= Timing[chunk2[testString, 2];]
Timing[chunk2[testString, 100];]

Out[12]={1.25, Null}
Out[13]={0.11, Null}

(* Jens - fastest *)
In[14]:= Timing[chunk3[testString, 2];]
Timing[chunk3[testString, 100];]

Out[14]= {1.313, Null}
Out[15]= {0.125, Null}

(* TomD *)
In[16]:= Timing[chunk4[testString, 2];]
Timing[chunk4[testString, 100];]

(* More than a few minutes. Didn't wait for it to finish ... *)

(* mine *)
In[18]:= Timing[chunk5[testString, 2];]
Timing[chunk5[testString, 100];]

Out[18]= {2.25, Null}
Out[19]= {0.266, Null}


Conclusion: use regex-based methods. The built-in string patterns also use a regex library internally, I believe, but they are easier to construct programmatically because they are represented as expressions.

-
Scrollbar ate your timing results... First I thought it was so lightning fast you did not bother to write it out in numbers :) – István Zachar May 17 '12 at 9:54
Thanks, Szabolcs, and everyone who answered. As ever, more than one way to skin a cat with Mathematica. I'm a bit surprised that there isn't a StringPartition function taking the same arguments as Partition as a built-in, analogous to StringTake vs. Take. – David G May 17 '12 at 13:23
Your code can be further sped up by using DeveloperPartitionMap to apply FromCharacterCode to each term in the list. This does not unpack the list. The speed up is marginal, though, on my machine 1.25793 -> 1.12617 and 0.135588 -> 0.095252. So, still not a contender for the fastest method. – rcollyer May 17 '12 at 16:38
@rcollyer Good point! I never used DeveloperPartitionMap before. (I've seen it in the docs, but I didn't realize its significance: not unpacking.) – Szabolcs May 17 '12 at 16:40
@rcollyer I solved the 'mystery': it was auto-compilation. It avoids unpacking only if the list is above the auto-compilation length. – Szabolcs May 17 '12 at 17:08

I wanted a solution using StringSplit[]

chunk[s_, n_] := StringSplit[s, RegularExpression["(.{" <> ToString@n <> "})"] -> "\$1"]
~ DeleteCases ~ ""

-
Cleaner, IMO: StringSplit[s, x : Repeated[_, {n}] :> x][[;; ;; 2]]. I don't see an advantage over StringCases however. – Mr.Wizard May 4 '14 at 11:05
@Mr.Wizard No advantage. I just wanted a way to use StringSplit[] as said. But I'm too old to remember why I wanted that. – Dr. belisarius May 5 '14 at 3:49