我有一个需要提供标准化字符串的例程.但是,进入的数据不一定是干净的,如果字符串包含无效的代码点,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(); }
(编辑:)我正在考虑将文本转换为UTF-32,以便我可以快速迭代它,并查看每个双字是否对应一个有效的代码点.有没有这样做的功能?如果没有,是否有无效范围列表在那里浮动?
解决方法
看来,唯一的办法就是像你这样做的“手动”.这是一个与您的结果相同的版本,但是速度要快一点(在char.MaxValue中的所有字符串的大约4倍),而不需要不安全的代码.我也简化和评论了我的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 }