C# unicode字符代码的uint和字符转换
有人能解释一下这段代码到底是怎么回事吗C# unicode字符代码的uint和字符转换,c#,.net,unicode,C#,.net,Unicode,有人能解释一下这段代码到底是怎么回事吗 var letter= 'J'; char c = (char)(0x000000ff & (uint)letter); 我知道这是字符的unicode表示形式,但我不完全理解: (0x000000ff & (uint)letter 0x000000ff和向(uint)投出字母的目的是什么?是否有一种简单的方法可以实现相同的结果 谢谢 更新 好的,看起来大多数人认为这是一个糟糕的例子,我不想包含整个类,但我想我也可以这样做,这样你就可以
var letter= 'J';
char c = (char)(0x000000ff & (uint)letter);
我知道这是字符的unicode表示形式,但我不完全理解:
(0x000000ff & (uint)letter
0x000000ff和向(uint)投出字母的目的是什么?是否有一种简单的方法可以实现相同的结果
谢谢
更新
好的,看起来大多数人认为这是一个糟糕的例子,我不想包含整个类,但我想我也可以这样做,这样你就可以看到上下文了。发件人:
此代码所做的不是转换为Unicode。如果有什么不同的话,那就是另一种方式:
0x000000ff&
部分基本上丢弃unicode字母的第二个字节,并将其转换为只有一个字节长的字母。或者更准确地说:它只保留最重要的字节,而丢弃所有其他字节-这对于char
也是一样的,因为它的大小为两个字节
我仍然认为这是没有意义的,因为它会导致误报:实际上使用两个字节的Unicode字母只会丢失其中一个字节,从而变成另一个字母
我会简单地去掉这段代码,在你使用c
的任何地方使用name[I]
0x000000ff的目的是什么?将字母转换为(uint)是什么
要从[0..255]范围获取代码为的字符:char
在内存中占用2个字节
e、 g:
您正在解析HTTP头,对吗?这意味着您不应该使用(任何)unicode编码 HTTP头必须是7位ASCII(与请求数据不同)1。这意味着您应该使用ASCII编码而不是默认编码。因此,在解析请求字节时,必须使用
Encoding.ASCII.GetString
而不是Encoding.Default.GetString
。希望您没有使用StreamReader
——这是个坏主意,原因很多,包括(可能)头和请求内容之间的编码不匹配
编辑:
至于在微软源代码中的使用——是的,确实如此。不要试图抄袭那些东西——这是一种黑客行为。请记住,您没有微软工程师拥有的测试套件和质量保证,因此即使它确实有效,您最好不要复制此类黑客
我假设它是这样处理的,因为对原则上应该是“ASCII字符串”或仅仅是byte[]
的东西使用string
——因为.NET只支持unicode字符串,这被认为是较小的缺点(事实上,这就是为什么代码明确检查字符串
不包含任何unicode字符的原因——它清楚地知道头必须是ASCII字符——如果字符串包含任何非ASCII字符,它将显式失败。这只是编写供其他人构建的高性能框架时的常见折衷
脚注:
var-letter=“J”
应该是var-letter=“J”
@xanatos谢谢你的更正,这是一个打字错误。我不会说第二个-unicode每个字符的字节数可以比两个多,也可以比两个少。它只需要最低的字节,不管其他字节是什么样子(或者有多少字节)@Luaan:C#中的字符类型大小为两个字节,因此不可能超过两个字节。是的,但这是在char
级别上-这意味着这些字符实际上将被表示为一个代理对-这更糟-不仅你不会去掉一半的unicode字母,而且你会在事实上,添加没有任何意义的伪ASCII字符。我知道您并不是想说使用这样的字符是个好主意,但它甚至比在输出中更改一些字母更复杂。char
将只有两个字节,但unicode字母可以有多个char
s。HTTP头可以e ISO-8859-1(默认情况下,超文本传输协议(HTTP)消息中的消息头字段参数不能携带ISO-8859-1字符集之外的字符),但要点是相同的:1byte
变为1char
,值的映射为1:1。@xanatos-Hah,我想知道这是否一直存在(即使是原始的HTTP 1.1 RFC 2616也谈到了“US-ASCII”,这可能意味着ISO-8859-1)。显然,它还允许5987中的UTF-8。在任何情况下,大量客户机都采用ASCII,因此坚持使用7位ASCII仍然是一个好主意(也就是说,每8位零,而不是真正的7位。那将是愚蠢的)。就像不指定字符集一样,它意味着iso-8859-1,而大多数客户端认为它意味着客户端应该猜测编码:D@Luaan但是,如果使用ISO-8859-1
,它的优点是,值为0-255的字节与值为0-255的char
之间的转换为1:1,因此始终是这样安全。然后你可以用另一个编码器重新解码,而不会丢失信息。@Luaan你是一个伟大的治疗者!:-)非常感谢您简洁的回答。@xanatos是的,这绝对是一个很好的观点。这意味着不会有任何数据在途中丢失。当然,它只适用于.NET对其字符串使用的变体-例如,使用UTF-8意味着通过剥离额外的字节,您将丢失127以上的字符(嗯,会将字符弄乱)在ISO-8859-1和UTF-16中,
private static string CheckBadChars(string name, bool isHeaderValue)
{
if (name == null || name.Length == 0)
{
// emtpy name is invlaid
if (!isHeaderValue)
{
throw name == null ?
new ArgumentNullException("name") :
new ArgumentException(SR.GetString(SR.WebHeaderEmptyStringCall, "name"), "name");
}
// empty value is OK
return string.Empty;
}
if (isHeaderValue)
{
// VALUE check
// Trim spaces from both ends
name = name.Trim(HttpTrimCharacters);
// First, check for correctly formed multi-line value
// Second, check for absenece of CTL characters
int crlf = 0;
for (int i = 0; i < name.Length; ++i)
{
char c = (char)(0x000000ff & (uint)name[i]);
switch (crlf)
{
case 0:
if (c == '\r')
{
crlf = 1;
}
else if (c == '\n')
{
// Technically this is bad HTTP. But it would be a breaking change to throw here.
// Is there an exploit?
crlf = 2;
}
else if (c == 127 || (c < ' ' && c != '\t'))
{
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidControlChars), "value");
}
break;
case 1:
if (c == '\n')
{
crlf = 2;
break;
}
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidCRLFChars), "value");
case 2:
if (c == ' ' || c == '\t')
{
crlf = 0;
break;
}
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidCRLFChars), "value");
}
}
if (crlf != 0)
{
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidCRLFChars), "value");
}
}
else
{
// NAME check
// First, check for absence of separators and spaces
if (name.IndexOfAny(InvalidParamChars) != -1)
{
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidHeaderChars), "name");
}
// Second, check for non CTL ASCII-7 characters (32-126)
if (ContainsNonAsciiChars(name))
{
throw new ArgumentException(SR.GetString(SR.WebHeaderInvalidNonAsciiChars), "name");
}
}
return name;
}
char c = (char)(0x000000ff & (uint)name[i]);
var letter= (char)4200; // ၩ
char c = (char)(0x000000ff & (uint)letter); // h
// or
// char c = (char)(0x00ff & (ushort)letter);
// ushort (2-byte unsigned integer) is enough: uint is 4-byte unsigned integer