LINQ on String using the IEnumerable<char> Interface


Introduction

This post is about using LINQ across (or more to the point within the) String Objects. Rather than, the more common, using Strings in LINQ expressions, this blog post focus on using the string object’s representation as a Char array (which is the way I think of the representation – a hangover from being a long term C/C++ programmer) in LINQ expressions. For the pedants, and to be exactly precise, it is the IEnumerable<char> interface of the String Object which enable the use of LINQ on the contents of a String Object.

I suspect that some C# developers may not have spotted that there are opportunities which the IEnumerable<char>  interface of a string offers.

The following are three methods are examples of using the IEnumerable<char> representation of a string to do some fairly common string manipulations.

Code Examples

Camel Case

This is quick proper case (or camel case) routine. The rule here was simple if there are less than four tokens in the input string, make the first character of each token upper case. There is “bit” of “fancy dancing” to get the desired result. For each of the tokens, select the upper case of the first character plus the balance of the string with a trailing space, then roll up the strings into a aggregate, then make a char array of the aggregate, make a new string , and finally trim off the trailing space. Not really heavily leveraging the IEnumerable<char> representation of the string, but shows what can be done.

private string ProperCase(string InfoLine)
{
    char[] delimiters = { ' ' };
    string[] tokens = InfoLine.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
    if (tokens.Length < 4)
    {
        return new string(
            tokens.Select(A => Char.ToUpper(A[0]) + A.Substring(1) + " ")
            .Aggregate((A, B) => A + B).ToArray()).Trim();
    }
    else
    {
        return InfoLine;
    }
}

A Quick QName

This one is used to make a synthetic QName (reference to Wikipedia QName and W3C XML QName definition) which does make use of working at with the IEnumerable<char> representation of the String Class. It’s intention is to throw away all but the standard characters (could/should use char.IsLetter, but this version does what all that I wanted at the time).

private string MakeQName(string Name)
{
    // simple compress spaces out
    return new String(Name.Where(A => !Char.IsPunctuation(A) && !Char.IsSeparator(A)).ToArray());
}

Extracting Number and Text From a String

This is another example of the use of the IEnumerable<char> aspect of the string class. This case does the following:

  • Pulls a long, or double, value from a string.
  • Then the process pulls a unit of quantity from the string as well (the residual text in the string).

This example builds the resulting string up character by character in a StringBuilder object (another way to make the transition from a character by character representation of a string back into string).

private void PullNumberAndUnit(string CompoundValue, out string SizeString, out SizeUnits sizeUnits)
{
    StringBuilder buf = new StringBuilder();
    String strSize;
    long lSize = 0L;
    string strUnit;
    if (CompoundValue.IndexOf(".") == -1)
    {
        CompoundValue.Where(A => Char.IsDigit(A)).ToList().ForEach(A => buf.Append(A));
        strSize = buf.ToString().Trim();
        if (long.TryParse(strSize, out lSize))
        {
            SizeString = lSize.ToString();
        }
        else
        {
            SizeString = String.Empty;
        }
    }
    else
    {
        CompoundValue.Where(A => Char.IsDigit(A) || A == '.').ToList().ForEach(A => buf.Append(A));
        strSize = buf.ToString().Trim();
        double dVal = 0.0;
        if (double.TryParse(strSize, out dVal))
        {
            SizeString = dVal.ToString();
        }
        else
        {
            SizeString = String.Empty;
        }
    }
    buf.Clear();
    CompoundValue.Where(A => !Char.IsDigit(A)).ToList().ForEach(A => buf.Append(A));
    strUnit = buf.ToString().Trim();
    if (this.DecodeUnits.ContainsKey(strUnit))
    {
        sizeUnits = DecodeUnits[strUnit];
    }
    else
    {
        sizeUnits = SizeUnits.Unknown;
    }
}

Conclusions

I hope that the above examples provide some inspiration, or a quick solution to a knotty problem.

Have fun with LINQ and string. There are bound to be a multitude of other ways the representation (or for the pedants reading this interpretation) of a string as a character array can be “gainfully employed” by C# developers. These are just some of samples, of the application of this technique, that way I’ve found (thus far – next development task could have some more waiting to be found).

Some of my previous LINQ Posts

 

 

 







, , , , , ,

  1. #1 by Shimmy on October 30, 2011 - 7:23 am

    Your “ProperCase” is already implemented in .NET (System.Globalization.TextInfo.ToTitleCase method), check it out: http://msdn.microsoft.com/en-us/library/system.globalization.textinfo.totitlecase.aspx.

    • #2 by aussiecraig on October 30, 2011 - 10:19 am

      Many thanks for the information. I was unaware of that .Net Framework function. It would appear to be what I was looking for.

      A comments for Microsoft:
      1) The method name does not make finding this method easy. ToTitleCase leaves the questions of “What is Title Case?”. An answer to that can only be found by looking at the documentation.
      2) Does the search function on MSDN support a wild cards in strings like “To” + * + “Case”? That is something I will have to go and explore.

  2. #3 by kaitlin on November 18, 2010 - 9:10 am

    sweet

  3. #5 by Hipolito M. Wiseman on October 29, 2010 - 2:03 pm

    Interesting article, and the website seems nice all-around also, I been to a few pages before commenting, I usually don’t comment unless I find there is something worth-it on the site. Great site, and thank you for the quality.

  1. Yield Return: Uses, Abuses and “Rules of Thumb” « Craig's Eclectic Blog

Leave a comment