Implementing a split (or a pseudo-split) for StringBuffers/Builders
One of the functionalities regrettably absent from the StringBuilder/StringBuffer families is the inbuilt and nice String method split(String regexp) (q.v. java.lang.String.split()), which will produce a tokenised array of Strings based around and consuming the supplied regexp token. The cranky way of doing this with a Stringbuffer is to cast your lightweight StringBuffer to a String, split to an array of Strings, then cast the array of Strings back to a StringBuffer array or List, which to me looks somewhat like defeating the object of the entire exercise in working with StringBuffers. I have a marked preference for working with Lists as opposed to arrays but I do realise that there are those of the other faith who have valid reasons for their heretical idolatry (j/k) so I’ll provide methods for both outcomes.
Given that we have a method for providing a List of token positions from a supplied StringBuffer (q.v. Locating token positions[..]) (and I have a somewhat improved method for doing this which I will anyway supply as an appendage to this post – the refactored method has been renamed getTokenPositions as opposed to the earlier findTokens) the way is clear for us to implement the new split method.
/** Method to split an inbound StringBuffer by (consumed) tokens and produce a List
* @param StringBuffer sbx - the StringBuffer to split
* @param StringBuffer sbTok - a StringBuffer representation of token(s) to use to split
* @return List of StringBuffers split out
*/
public List split(StringBuffer sbx, StringBuffer sbTok)
{
int tokSz = sbTok.length();
List lix = new ArrayList();
List lPos = getTokenPositions(sbx, sbTok );
if( lPos.isEmpty() || lPos == null) // no split? send the original sb back
{
lix.add(sbx);
return lix;
}
int start = 0;
if(lPos.get(0) == 0)
{
start += tokSz;
}
int iSz = lPos.size();
for (int i = 0; i < iSz; i++) {
StringBuffer sbnew = new StringBuffer();
if(i + 1 == iSz)
{
sbnew = new StringBuffer(sbx.subSequence(start, sbx.length()));
}
else
{
sbnew = new StringBuffer(sbx.subSequence(start, lPos.get(i + 1)));
start = lPos.get(i + 1) + tokSz;
}
// System.out.println(sbnew.toString());
lix.add(sbnew);
}
return lix;
}
To produce an Array of StringBuffers, you merely need to change the return method signature
public StringBuffer[] split(StringBuffer sbx, StringBuffer sbTok)
and modify the code where the returns occur (2 places) to read:
return (StringBuffer[]) lix.toArray();
Modified method for providing a List of token positions
I mentioned earlier I had a somewhat improved version of the findTokens method. The code for this (+ the comparator-helper List construction methods) follows:
public List getTokenPositions(StringBuffer sbx, StringBuffer tok )
{
List liTok = charListFromSb(tok);
List liOut = new ArrayList();
int sz = tok.length() - 1;
int finish = sbx.length() - sz;
char firstTok = tok.charAt(0);
char lastTok = tok.charAt(sz);
for (int i = 0; i < finish; i++) {
if ( (sbx.charAt(i) == firstTok) && (sbx.charAt(i + sz) == lastTok) )
{
List comp = charListFromSb(sbx, i, i+ sz);
if (comp.equals(liTok))
{
boolean add = liOut.add(i);
}
}
}
return liOut;
}
public List charListFromSb(StringBuffer sbx)
{
List liOut = new ArrayList();
int iEnd = sbx.length();
for (int i = 0; i < iEnd; i++) {
boolean add = liOut.add(sbx.charAt(i));
}
return liOut;
}
public List<Character> charListFromSb(StringBuffer sbx, int start, int finish)
{
List<Character> liOut = new ArrayList<Character>();
for (int i = start; i <= finish; i++) {
boolean add = liOut.add(sbx.charAt(i));
}
return liOut;
}