// Title: StringSplitter
// Description: Utility that takes a String and returns a String Array of
// broken out "tokens". Works better then the String.Split()
// method.
//
// Copyright: Copyright (c) 2003, All Rights Reserved.
// Company: MyFamily.com
// Author: Bill Yetman
// Version: 1.0
using System;
using System.Collections;
using System.Diagnostics;
namespace Pegasus
{
/// <summary>
/// Use this class to split strings into an array of string
/// objects with each individual word as an array element. This
/// class works different then the Split command off the String object,
/// it properly skips all the white space between the delimeters.
/// </summary>
/// <remarks>
/// This is a utility class straight out of the "Professional Java XML
/// Programming" book. It has turned out to be a very useful class
/// that takes a string and returns an array of String objects with
/// each individual word as an array element. This is a useful class
/// that can be used to break up strings. This class is ment to be
/// used like StringTokenizer, but it can return empty "tokens", and
/// takes only one delimiter which may be either a character or a string.
/// This is an immutable object.
/// <para>
/// For example, the text string "help me [lots of blanks here] fix this", if it
/// split using a blank character as the delimiter will produce a String Array
/// with the following elements: S[0] = "help", S[1] = "me", S[2] = "fix", and
/// S[3] = "this". Notice that the extra blanks do not produce empty string
/// entries between "me" and "fix".
/// </para>
/// </remarks>
public class StringSplitter
{
// Reference to the string that is being split.
private string m_theString;
// If a character is used as a delimeter, this data member holds
// that character.
private char m_theDelim;
// nextToken is the token beginning at m_thePos
private int m_thePos;
// If a string delimeter is used this data member holds that string.
private string m_theDelimStr;
// The length in bytes of the delimeter.
private int m_theDelimLength;
/// <summary>
/// This is the constructor that is called when you want
/// to initialize a string splitter object with a single
/// character as the delimiter.
/// </summary>
/// <param name="split">The string to split.</param>
/// <param name="delimiter">The single character that is the delimiter.</param>
/// <param name="startPos">The position to start splitting at.</param>
public StringSplitter( string split, char delimiter, int startPos )
{
// Forward to the private method that will do the work.
StringSplitterCharConstructor( split, delimiter, startPos );
}
/// <summary>
/// This is a constructor that takes a string to split and
/// a delimiter character then forwards the call to the
/// StringSplitter(String, char, int) constructor with the
/// position to start at set to zero.
/// </summary>
/// <param name="split">The string to split.</param>
/// <param name="delimiter">The single character that is the delimiter.</param>
public StringSplitter( string split, char delimiter )
{
// Forward to the private method that will do the work.
StringSplitterCharConstructor( split, delimiter, 0 );
}
/// <summary>
/// This is the constructor that is called when you want
/// to initialize a string splitter object with a string
/// as the delimiter.
/// </summary>
/// <param name="split">The string to split.</param>
/// <param name="delimiter">The string that is the delimiter.</param>
/// <param name="startPos">The position to start splitting at.</param>
public StringSplitter( string split, string delimiter, int startPos )
{
// Forward to the private method that will do the work.
StringSplitterStringConstructor( split, delimiter, startPos );
}
/// <summary>
/// This is a constructor that takes a string to split and
/// a delimiter string then forwards the call to the
/// StringSplitter(String, String, int) constructor with the
/// position to start at set to zero.
/// </summary>
/// <param name="split">The string to split.</param>
/// <param name="delimiter">The string that is the delimiter.</param>
public StringSplitter( string split, string delimiter )
{
// Forward to the private method that will do the work.
StringSplitterStringConstructor( split, delimiter, 0 );
}
/// <summary>
/// This is the constructor that is called when you want
/// to initialize a string splitter object with a single
/// character as the delimiter.
/// </summary>
/// <param name="split">The string to split.</param>
/// <param name="delimiter">The single character that is the delimiter.</param>
/// <param name="startPos">The position to start splitting at.</param>
private void StringSplitterCharConstructor( string split, char delimiter, int startPos )
{
m_theString = split;
m_theDelim = delimiter;
m_thePos = startPos;
m_theDelimLength = 1;
if( m_thePos >= m_theString.Length )
{
m_thePos = -1;
}
}
/// <summary>
/// This is the constructor that is called when you want
/// to initialize a string splitter object with a string
/// as the delimiter.
/// </summary>
/// <param name="split">The string to split.</param>
/// <param name="delimiter">The string that is the delimiter.</param>
/// <param name="startPos">The position to start splitting at.</param>
private void StringSplitterStringConstructor( string split, string delimiter, int startPos )
{
m_theString = split;
m_theDelimStr = delimiter;
m_thePos = startPos;
m_theDelimLength = delimiter.Length;
if( m_thePos >= m_theString.Length )
{
m_thePos = -1;
}
}
/// <summary>
/// This method will return true if there are more tokens left
/// in the string. If there are no more tokens possible,
/// false is returned.
/// </summary>
/// <returns>
/// A boolean value that indicates if there are any more
/// tokens left to parse in the string.
/// </returns>
public bool HasMoreTokens()
{
return ( m_thePos >= 0 );
}
/// <summary>
/// This method is called to return the next token in the string.
/// If there are no more tokens, null is returned to the caller.
/// </summary>
/// <returns>
/// A String with the next token is returned to the caller.
/// </returns>
public string NextToken()
{
string ret = null;
if( m_thePos >= 0 )
{
int nextPos;
if( m_theDelimStr == null )
{
nextPos = m_theString.IndexOf( m_theDelim, m_thePos );
}
else
{
nextPos = m_theString.IndexOf( m_theDelimStr, m_thePos );
}
if( nextPos >= 0 )
{
int size = nextPos - m_thePos;
ret = m_theString.Substring( m_thePos, size );
m_thePos = nextPos + m_theDelimLength;
}
else
{
ret = m_theString.Substring( m_thePos );
m_thePos = nextPos;
}
}
return ret;
}
/// <summary>
/// This static method is called to split a string that has
/// a character delimiter into an array of String objects.
/// </summary>
/// <param name="split">The string to split.</param>
/// <param name="delimiter">The character delimiter that separates the tokens in the string.</param>
/// <returns>
/// A String array object is returned to the caller with
/// each separate token as an element of the array.
/// </returns>
public static string [] StringSplit( String split, char delimiter )
{
ArrayList list = new ArrayList();
StringSplitter spliter = new StringSplitter( split, delimiter );
while( spliter.HasMoreTokens() )
{
list.Add( spliter.NextToken() );
}
return ArrayListToStringArray( list );
}
/// <summary>
/// This static method is called to split a string that has
/// a string delimiter into an array of String objects.
/// </summary>
/// <param name="split">The string to split.</param>
/// <param name="delimiter">The String delimiter that separates the tokens in the string.</param>
/// <returns>
/// A String array object is returned to the caller with
/// each separate token as an element of the array.
/// </returns>
public static string [] StringSplit( string split, string delimiter )
{
ArrayList list = new ArrayList();
StringSplitter spliter = new StringSplitter( split, delimiter );
while( spliter.HasMoreTokens() )
{
list.Add( spliter.NextToken() );
}
return ArrayListToStringArray( list );
}
/// <summary>
/// This is a static utility method that is called to change a Vector
/// into a string array.
/// </summary>
/// <param name="list">The ArrayList that we want to change to a String array.</param>
/// <returns>
/// An array of String objects is returned to the caller.
/// </returns>
private static string[] ArrayListToStringArray( ArrayList list )
{
int elementCount = NonEmptyCount( list );
String [] strings = new String[ elementCount ];
IEnumerator iter = list.GetEnumerator();
int x = 0;
// Only iterate through the ArrayList if we have a non-zero element count.
if( elementCount > 0 )
{
while( iter.MoveNext() )
{
string current = iter.Current as string;
// We don't move empty array entries into the final string array.
if( current != null && current.Length > 0 )
{
strings[ x ] = current;
x++;
}
}
}
return strings;
}
/// <summary>
/// Called to return the number of non-empty ArrayList entries in the array list
/// passed in.
/// </summary>
/// <param name="V">
/// The array list that we want a non-empty count for.
/// </param>
/// <returns>
/// The number of non-empty strings in the ArrayList.
/// </returns>
private static int NonEmptyCount(
ArrayList V )
{
int result = 0;
IEnumerator pIter = V.GetEnumerator();
while( pIter.MoveNext() )
{
String current = (String)pIter.Current;
if( current.Length > 0 )
result++;
}
return result;
}
}
}