Here's a pretty simple and pretty readable implementation (I call it StringBuilder in the test below):
public static String interleave(String s, int interval, String separator) { StringBuilder sb = new StringBuilder(s); for (int pos = (s.length()-1) / interval; pos > 0; pos--) { sb.insert(pos * interval, separator); } return sb.toString(); }
If you are interested in the effectiveness of a simple StringBuilder implementation, then perhaps this implementation will suit your needs better (I call it Arrays in the test example below):
public static String interleave(String string, int interval, String separator) { char[] src = string.toCharArray(); char[] sep = separator.toCharArray(); int count = (src.length-1)/interval; char[] dst = new char[src.length + count * sep.length]; int srcpos = 0, dstpos = 0; for (int i = 0; i < count; i++) { System.arraycopy(src, srcpos, dst, dstpos, interval); srcpos += interval; dstpos += interval; System.arraycopy(sep, 0, dst, dstpos, sep.length); dstpos += sep.length; } if (dstpos < dst.length) { System.arraycopy(src, srcpos, dst, dstpos, dst.length - dstpos); } return String.valueOf(dst); }
Note. I would probably use such an implementation only in the J2ME environment, but it should be much faster on huge lines. The readability is pretty poor though ...
Of course, there is always a way for RegExp to do things that are surprisingly pretty fast after you climbed in length, when compiling RegExp itself ceases to be a problem (you cannot precompile RegExp because it is generated to fly depending on the interval, thanks Rubens Farias for pointing this out somehow missed him). So here it is (I call this RegExp in the following test case):
public static String interleave(String string, int interval, String separator) { return string.replaceAll("(.{"+interval+"})", "$1"+Matcher.quoteReplacement(separator)); }
Note. . This implementation inserts a delimiter at the end if the string length is a multiple of the spacing (while other implementations are missing). I do not like RegExps because they are not readable and not too fast. Oh, and you can easily forget the "quoteReplacement" part and put yourself in a big problem if the delimiter contains "1 dollar" or even worse if it comes from the user.
Benchmark
At this moment, I did some benchmarking, so the first implementation on a line length of 100,000 takes 0.002643 seconds, the second - 0.000010, the third - 0.000071, but it all depends on the length of the line.
Length StringBuilder Arrays RegExp 10000 0.000012 0.000001 0.000054 100000 0.002643 0.000010 0.000071 1000000 0.315413 0.000026 0.000199
This is by no means a serious benchmarking, but it still shows the trends and complexities of the algorithms used.
Note. . Although these ideas are fun to play with, we are still talking about improvements for the second part when dealing with strings smaller than 1 MB. Therefore, it doesn’t matter where you go if you work only with lines up to 1K in size (this will be 0ms versus 0ms). The most important thing is that it should be readable, understandable and not take too much time to write, because I am sure that you have more important problems to solve if you are not writing a universal library for everyone to use in the most strange cases . Remember - your time is much more valuable than processor time.
Left and Right Interleave
I will take the implementation of arrays for this, since for me it is easiest to change:
public static String interleave(String string, int interval, String separator, boolean fromRight) { char[] src = string.toCharArray(); char[] sep = separator.toCharArray(); int count = (src.length-1)/interval; char[] dst = new char[src.length + count * sep.length]; int srcpos = 0, dstpos = 0; if (fromRight) { srcpos = dstpos = src.length - count * interval; if (srcpos > 0) System.arraycopy(src, 0, dst, 0, srcpos); if (count > 0) { System.arraycopy(sep, 0, dst, dstpos, sep.length); dstpos += sep.length; count--; } } for (int i = 0; i < count; i++) { System.arraycopy(src, srcpos, dst, dstpos, interval); srcpos += interval; dstpos += interval; System.arraycopy(sep, 0, dst, dstpos, sep.length); dstpos += sep.length; } if (dstpos < dst.length) { System.arraycopy(src, srcpos, dst, dstpos, dst.length - dstpos); } return String.valueOf(dst); }