如何从字符串中删除无效的代码点?

Sea*_*n U 10 c# unicode

我有一个需要提供规范化字符串的例程.但是,进入的数据不一定是干净的,如果字符串包含无效的代码点,String.Normalize()会引发ArgumentException.

我想做的只是用一个一次性字符替换那些代码点,例如'?'.但要做到这一点,我需要一种有效的方法来搜索字符串,以便首先找到它们.有什么好办法呢?

以下代码有效,但它基本上使用try/catch作为粗略的if语句,因此性能很糟糕.我只是分享它来说明我正在寻找的行为:

private static string ReplaceInvalidCodePoints(string aString, string replacement)
{
    var builder = new StringBuilder(aString.Length);
    var enumerator = StringInfo.GetTextElementEnumerator(aString);

    while (enumerator.MoveNext())
    {
        string nextElement;
        try { nextElement = enumerator.GetTextElement().Normalize(); }
        catch (ArgumentException) { nextElement = replacement; }
        builder.Append(nextElement);
    }

    return builder.ToString();
}
Run Code Online (Sandbox Code Playgroud)

(编辑:)我正在考虑将文本转换为UTF-32,以便我可以快速迭代它,看看每个dword是否对应一个有效的代码点.有没有这样做的功能?如果没有,是否有一个无效范围列表在那里漂浮?

por*_*ges 8

似乎唯一的方法是"手动",就像你已经完成的那样.下面是给出了相同的结果你的一个版本,但是是快一点(约4倍于所有的字符串chars最多char.MaxValue,少改善达U+10FFFF)和不需要unsafe的代码.我还简化并评论了我的IsCharacter方法来解释每个选择:

static string ReplaceNonCharacters(string aString, char replacement)
{
    var sb = new StringBuilder(aString.Length);
    for (var i = 0; i < aString.Length; i++)
    {
        if (char.IsSurrogatePair(aString, i))
        {
            int c = char.ConvertToUtf32(aString, i);
            i++;
            if (IsCharacter(c))
                sb.Append(char.ConvertFromUtf32(c));
            else
                sb.Append(replacement);
        }
        else
        {
            char c = aString[i];
            if (IsCharacter(c))
                sb.Append(c);
            else
                sb.Append(replacement);
        }
    }
    return sb.ToString();
}

static bool IsCharacter(int point)
{
    return point < 0xFDD0 || // everything below here is fine
        point > 0xFDEF &&    // exclude the 0xFFD0...0xFDEF non-characters
        (point & 0xfffE) != 0xFFFE; // exclude all other non-characters
}
Run Code Online (Sandbox Code Playgroud)