我想从字符串中删除以\ xF0(带有ASCII代码0xF0的字符)开头的4字节UTF8字符并尝试
sText = Regex.Replace (sText, "\xF0...", "");
这不起作用。使用两个反斜杠也不起作用。
确切的输入是https://de.wikipedia.org/w/index.php?title=Spezial:Exportieren&action=submit&pages=Unicode的内容4字节字符是文本“[[Violinschlüssel]]”之后的一个字符,用十六进制表示法:.. 0x65 0x6c 0x5d 0x5d 0x20 0xf0 0x9d 0x84 0x9e 0x20。预期输出为0x65 0x6c 0x5d 0x5d 0x20 0x20 ..
怎么了?
答案 0 :(得分:5)
这些字符将是.NET中使用UTF-16的代理对。它们中的每一个都是两个 UTF-16代码单元,即两个char
值。
要删除它们,您可以执行(using System.Linq;
):
sText = string.Concat(sText.Where(x => !char.IsSurrogate(x)));
(使用.NET 4.0(Visual Studio 2010)中引入的Concat
重载)。
延迟添加:它可能会提供更好的使用性能:
sText = new string(sText.Where(x => !char.IsSurrogate(x)).ToArray());
即使看起来更糟糕也是如此。 (适用于.NET 3.5(Visual Studio 2008)。)
答案 1 :(得分:2)
您正在尝试搜索byte
值,但C#字符串来自char
值。 “2.4.4.4字符文字”部分的C#语言规范声明:
字符文字表示单个字符,通常由引号中的字符组成,如“a”中所示 ...
十六进制转义序列表示单个Unicode字符,其值由\x
后面的十六进制数字组成。
因此,搜索"\xF0..."
正在搜索将由字节U+F0
表示的字符C3 B0
。
如果你想找到替换所有第一个字节为0xF0的Unicode字符,那么我相信你需要搜索第一个字节(如果是0xFO)的字符值。
字符U+10000
表示为F0 90 80 80
(前面的代码为U+FFFF
,即EF BF BF
)。 F1 .... ..
的第一个代码为U+40000
F1 80 80 80
,其前面的值为U+3FFFF
,即F0 BF BF BF
。
因此,您需要删除U+10000
到U+3FFFF
范围内的字符。这应该可以使用正则表达式,例如
sText = Regex.Replace (sText, "[\\x10000-\\x3FFFF]", "");
问题中引用的相关字符已被提取到下面的代码中。然后代码尝试理解字符在字符串中的保存方式。
static void Main(string[] args)
{
string input = "] (";
Console.Write("Input length {0} : '{1}' : ", input.Length, input);
foreach (char cc in input)
{
Console.Write(" {0,2:X02}", (int)cc);
}
Console.WriteLine();
}
程序的输出如下。这支持@Jeppe在他的回答中给出的代理对解释。
Input length 6 : '] ?? (' : 5D 20 D834 DD1E 20 28