我想从 e
中枚举文本元素(显示为单个字符的 Unicode 代码点组,如 ´
+ é
= IEnumerable<char>
) .现在我有以下内容:
// This code is untested! I assume it works because it's fairly simple and I checked the specification though.
public static IEnumerable<string> AsTextElements(this IEnumerable<char> input)
{
StringBuilder currentElement = new StringBuilder();
char highSurrogate = (char)0;
foreach (var c in input)
{
// Assuming input contains valid UTF-16:
if (char.IsHighSurrogate(c))
{
highSurrogate = c;
continue;
}
int codepoint;
if (char.IsLowSurrogate(c))
{ codepoint = char.ConvertToUtf32(highSurrogate, c); }
else
{ codepoint = c; }
var codepointString = char.ConvertFromUtf32(codepoint);
var category = CharUnicodeInfo.GetUnicodeCategory(codepointString, 0);
switch (category)
{
// Do these catch all combining characters?
case UnicodeCategory.EnclosingMark:
case UnicodeCategory.NonSpacingMark:
case UnicodeCategory.SpacingCombiningMark:
if (currentElement == null)
{ currentElement = new StringBuilder(codepointString); }
else
{ currentElement.Append(codepointString); }
break;
default:
if (currentElement.Length != 0)
{
yield return currentElement.ToString();
currentElement.Clear();
}
currentElement.Append(codepointString);
break;
}
}
yield return currentElement.ToString();
}
让我恼火的是所有 codepointString
string
s 是在这里创建的,尽管每个代码点最多需要 32 位。 我找不到直接从 int
获取 Unicode 类别的方法或两个 char
s.
添加 char
(s) 至 currentElement
StringBuilder
不过很容易实现。
我知道“优化前的措施”建议,这个问题主要是因为如果没有堆分配就不可能,这对我来说似乎很奇怪。
我不必迭代文本元素,除非它们在同一个 string
中可用。到目前为止,但我可能会在未来。
最佳答案
如果文本元素是指“用户感知的字符”,那么 Unicode Standard Annex 29包含一种算法,用于查找“扩展字形簇”之间的边界,与归一化产生的代码点相比,它可能更符合“用户感知的字符”。
(我之前的答案不正确,所以我删除了它;它建议使用规范化形式C,但在很多情况下它不足以找到文本元素。)
关于c# - 有没有更好的方法来枚举 IEnumerable<char> 中的文本元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26049903/