Strings are usually enumerated by character. But, particuarly when working with Unicode and non-English languages, sometimes I need to enumerate a string by grapheme. That is, combining marks and diacritics should be kept with the base character they modify. What is the best way to do this in .Net?
Use case: Count the distinct phonetic sounds in a series of IPA words.
- Simplified definition: There is a one-to-one relationship between a grapheme and a sound.
- Realistic definition: Special “letter-like” characters should also be included with the base character (ex. pʰ), and some sounds may be represented by two symbols joined by a tie bar (k͡p).
Simplified scenario
The TextElementEnumerator is very useful and efficient:
You can also do this using a regular expression: (From the documentation, the TextElementEnumerator handles a few cases that the expression below does not, particularly supplementary characters, but those are pretty rare, and in any case not needed for my application.)
Performance: In my testing, I found that the TextElementEnumerator was about 4 times as fast as the regular expression.
Realistic scenario
Unfortunately, there is no way to “tweak” how the TextElementEnumerator enumerates, so that class will be of no use in the realistic scenario.
One solution is to tweak our regular expression:
We could probably also create our own IEnumerator<string> using CharUnicodeInfo.GetUnicodeCategory to regain our performace, but that seems like too much work to me and extra code to maintain. (Anyone else want to have a go?) Regexes are made for this.