title: How can I perform a culture-sensitive "starts-with" operation from the middle of a string?
body: <p>I have a requirement which is relatively obscure, but it feels like it <em>should</em> be possible using the BCL.</p>
  
  <p>For context, I'm parsing a date/time string in <a href="http://noda-time.googlecode.com">Noda Time</a>. I maintain a logical cursor for my position within the input string. So while the complete string may be "3 January 2013" the logical cursor may be at the 'J'.</p>
  
  <p>Now, I need to parse the month name, comparing it against all the known month names for the culture:</p>
  
  <ul>
  <li>Culture-sensitively</li>
  <li>Case-insensitively</li>
  <li>Just from the point of the cursor (not later; I want to see if the cursor is "looking at" the candidate month name)</li>
  <li>Quickly</li>
  <li>... and I need to know afterwards how many characters were used</li>
  </ul>
  
  <p>The <a href="https://code.google.com/p/noda-time/source/browse/src/NodaTime/Text/ValueCursor.cs?r=40f44c857d94f450372d768a8cef835c3ed1ed4f#60">current code</a> to do this generally works, using <a href="http://msdn.microsoft.com/en-gb/library/f04h1e5y.aspx"><code>CompareInfo.Compare</code></a>. It's effectively like this (just for the matching part - there's more code in the real thing, but it's not relevant to the match):</p>
  
  <pre><code>internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
  {
      return compareInfo.Compare(text, position, candidate.Length,
                                 candidate, 0, candidate.Length, 
                                 CompareOptions.IgnoreCase) == 0;
  }
  </code></pre>
  
  <p>However, that relies on the candidate and the region we compare being the same length. Fine most of the time, but <em>not</em> fine in some special cases. Suppose we have something like:</p>
  
  <pre><code>// U+00E9 is a single code point for e-acute
  var text = "x b\u00e9d y";
  int position = 2;
  // e followed by U+0301 still means e-acute, but from two code points
  var candidate = "be\u0301d";
  </code></pre>
  
  <p>Now my comparison will fail. I could use <a href="http://msdn.microsoft.com/en-gb/library/8hksxky5.aspx"><code>IsPrefix</code></a>:</p>
  
  <pre><code>if (compareInfo.IsPrefix(text.Substring(position), candidate,
                           CompareOptions.IgnoreCase))
  </code></pre>
  
  <p>but:</p>
  
  <ul>
  <li>That requires me to create a substring, which I'd really rather avoid. (I'm viewing Noda Time as effectively a system library; parsing performance may well be important to some clients.)</li>
  <li>It doesn't tell me how far to advance the cursor afterwards</li>
  </ul>
  
  <p>In reality, I strongly suspect this won't come up very often... but I'd really <em>like</em> to do the right thing here. I'd also really like to be able to do it without becoming a Unicode expert or implementing it myself :)</p>
  
  <p>(Raised as <a href="https://code.google.com/p/noda-time/issues/detail?id=210">bug 210</a> in Noda Time, in case anyone wants to follow any eventual conclusion.)</p>
  
  <p>I like the idea of normalization. I need to check that in detail for a) correctness and b) performance. Assuming I <em>can</em> make it work correctly, I'm still not sure how whether it would be worth changing over all - it's the sort of thing which will probably <em>never</em> actually come up in real life, but could hurt the performance of all my users :(</p>
  
  <p>I've also checked the BCL - which doesn't appear to handle this properly either. Sample code:</p>
  
  <pre><code>using System;
  using System.Globalization;
  
  class Test
  {
      static void Main()
      {
          var culture = (CultureInfo) CultureInfo.InvariantCulture.Clone();
          var months = culture.DateTimeFormat.AbbreviatedMonthNames;
          months[10] = "be\u0301d";
          culture.DateTimeFormat.AbbreviatedMonthNames = months;
  
          var text = "25 b\u00e9d 2013";
          var pattern = "dd MMM yyyy";
          DateTime result;
          if (DateTime.TryParseExact(text, pattern, culture,
                                     DateTimeStyles.None, out result))
          {
              Console.WriteLine("Parsed! Result={0}", result);
          }
          else
          {
              Console.WriteLine("Didn't parse");
          }
      }
  }
  </code></pre>
  
  <p>Changing the custom month name to just "bed" with a text value of "bEd" parses fine.</p>
  
  <p>Okay, a few more data points:</p>
  
  <ul>
  <li><p>The cost of using <code>Substring</code> and <code>IsPrefix</code> is significant but not horrible. On a sample of "Friday April 12 2013  20:28:42" on my development laptop, it changes the number of parse operations I can execute in a second from about 460K to about 400K. I'd rather avoid that slowdown if possible, but it's not <em>too</em> bad.</p></li>
  <li><p>Normalization is less feasible than I thought - because it's not available in Portable Class Libraries. I could potentially use it <em>just</em> for non-PCL builds, allowing the PCL builds to be a little less correct. The performance hit of testing for normalization (<code>string.IsNormalized</code>) takes performance down to about 445K calls per second, which I can live with. I'm still not sure it does everything I need it to - for example, a month name containing "ß" should match "ss" in many cultures, I believe... and normalizing doesn't do that.</p></li>
  </ul>