gpt4 book ai didi

.net - 通过字素而不是字符枚举字符串

转载 作者:行者123 更新时间:2023-12-04 12:01:40 32 4
gpt4 key购买 nike

字符串通常按字符枚举。但是,特别是在使用 Unicode 和非英语语言时,有时我需要按字素枚举字符串。也就是说,组合标记和变音符号应与它们修改的基本字符保持一致。在 .Net 中执行此操作的最佳方法是什么?

用例:计算一系列 IPA 中不同的语音发音字。

  • 简化定义:字素和声音之间存在一对一的关系。
  • 现实定义:特殊的“类字母”字符也应该包含在基本字符中(例如 pʰ),并且一些声音可能由两个由连接条连接的符号 (k͡p) 表示。
  • 最佳答案

    简化场景

    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);
    }

    您也可以使用正则表达式来做到这一点:(从文档中,TextElementEnumerator 处理了下面的表达式没有处理的一些情况,特别是补充字符,但这些非常罕见,并且在任何情况下我的应用程序都不需要。)
    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 倍。

    现实场景

    不幸的是,没有办法“调整” TextElementEnumerator 的枚举方式,因此该类在现实场景中将毫无用处。

    一种解决方案是调整我们的正则表达式:
    [\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.

    我们也可以使用 CharUnicodeInfo.GetUnicodeCategory 创建我们自己的 IEnumerator 来重新获得我们的性能,但这对我来说似乎太多了,需要额外的代码来维护。 (还有其他人想试一试吗?)正则表达式就是为此而生的。

    关于.net - 通过字素而不是字符枚举字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2056866/

    32 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com