Строки обычно перечисляются символом. Но, particuarly при работе с Unicode и неанглийскими языками, иногда я должен перечислить строку графемой. Таким образом, объединение меток и диакритических знаков должно быть сохранено с основным символом, который они изменяют. Что лучший способ состоит в том, чтобы сделать это в .NET?
Вариант использования: Считайте отличные фонетические звуки в серии слов IPA.
TextElementeNumerator очень полезно и эффективно:
private static List<SoundCount> CountSounds(IEnumerable<string> words)
{
Dictionary<string, SoundCount> soundCounts = new Dictionary<string, SoundCount>();
foreach (var word in words)
{
TextElementEnumerator graphemeEnumerator = StringInfo.GetTextElementEnumerator(word);
while (graphemeEnumerator.MoveNext())
{
string grapheme = graphemeEnumerator.GetTextElement();
SoundCount count;
if (!soundCounts.TryGetValue(grapheme, out count))
{
count = new SoundCount() { Sound = grapheme };
soundCounts.Add(grapheme, count);
}
count.Count++;
}
}
return new List<SoundCount>(soundCounts.Values);
}
Вы также можете сделать это, используя регулярное выражение: (из документации, текстовый элементом обрабатывает несколько случаев, что выражение ниже не имеет, особенно дополнительных символов, но те довольно редко, и в любом случае не нужна для моего приложения.)
private static List<SoundCount> CountSoundsRegex(IEnumerable<string> words)
{
var soundCounts = new Dictionary<string, SoundCount>();
var graphemeExpression = new Regex(@"\P{M}\p{M}*");
foreach (var word in words)
{
Match graphemeMatch = graphemeExpression.Match(word);
while (graphemeMatch.Success)
{
string grapheme = graphemeMatch.Value;
SoundCount count;
if (!soundCounts.TryGetValue(grapheme, out count))
{
count = new SoundCount() { Sound = grapheme };
soundCounts.Add(grapheme, count);
}
count.Count++;
graphemeMatch = graphemeMatch.NextMatch();
}
}
return new List<SoundCount>(soundCounts.Values);
}
Производительность: В моем тестировании я обнаружил, что TextElementeNumerator был примерно в 4 раза быстрее, чем правильное выражение.
К сожалению, нет никакого способа «настроить», как текстовый элемент перечисляет, так что класс не будет использовать в реалистичном сценарии.
Одним из решений - настроить наше регулярное выражение:
[\P{M}\P{Lm}] # Match a character that is NOT a character intended to be combined with another character or a special character that is used like a letter
(?: # Start a group for the combining characters:
(?: # Start a group for tied characters:
[\u035C\u0361] # Match an under- or over- tie bar...
\P{M}\p{M}* # ...followed by another grapheme (in the simplified sense)
) # (End the tied characters group)
|\p{M} # OR a character intended to be combined with another character
|\p{Lm} # OR a special character that is used like a letter
)* # Match the combining characters group zero or more times.
Мы, вероятно, также могли бы также создать наш собственный iEnumerator
Я не уверен, что именно то, что вы ищете, но не ваш вопрос, связанный с нормализацией Unicode?
, когда строка нормализована в форму Unicode C (что является формой по умолчанию), диакритики и Символы, которые они изменяют, объединяются, поэтому, если вы перечисляете символы, которые вы получите базу и символы модификатора вместе.
Когда он нормализуется для формы D, база и символы модификатора разделены и возвращаются отдельно в перечислении.
См. Строка . Спортировать метод
для деталей