I don't have a Chinese system, so I cannot test it for you, have you tried HttpUtility.UrlDecode("YourString") or HttpUtility.UrlDecode("YourString",System.Text.Encoding.GetEncoding("GB2312")) or HttpUtility.UrlDecode("YourString",System.Text.Encoding.UTF8) first?
ok, here is something you can try, write the chinese in the form data out to see what the encoding is:Response.Write("****" + Request.Form["YourFormElement"] + "****");
<configuration>
<system.web> <!-- 动态调试编译
设置 compilation debug="true" 以启用 ASPX 调试。否则,将此值设置为
false 将提高此应用程序的运行时性能。
设置 compilation debug="true" 以将调试符号(.pdb 信息)
插入到编译页中。因为这将创建执行起来
较慢的大文件,所以应该只在调试时将该值设置为 true,而在所有其他时候都设置为
false。有关更多信息,请参考有关
调试 ASP.NET 文件的文档。
-->
<compilation defaultLanguage="c#" debug="true"><assemblies><add assembly="CrystalDecisions.CrystalReports.Engine, Version=9.1.3300.0, Culture=neutral, PublicKeyToken=692fbea5521e1304"/><add assembly="CrystalDecisions.ReportSource, Version=9.1.3300.0, Culture=neutral, PublicKeyToken=692fbea5521e1304"/><add assembly="CrystalDecisions.Shared, Version=9.1.3300.0, Culture=neutral, PublicKeyToken=692fbea5521e1304"/><add assembly="CrystalDecisions.Web, Version=9.1.3300.0, Culture=neutral, PublicKeyToken=692fbea5521e1304"/></assemblies></compilation> <!-- 自定义错误信息
设置 customError 模式值可以控制应向
用户显示用户友好错误信息而不是错误详细信息(包括堆栈跟踪信息): “On”始终显示自定义(友好的)信息
“Off”始终显示详细的 ASP.NET 错误信息。
“RemoteOnly”只对不在本地 Web 服务器上运行的
用户显示自定义(友好的)信息。出于安全目的,建议使用此设置,以便
不向远程客户端显示应用程序的详细信息。
-->
<customErrors mode="RemoteOnly" defaultRedirect="error.aspx"/> <!-- 身份验证
此节设置应用程序的身份验证策略。可能的模式是“Windows”、“Forms”、
“Passport”和“None”
-->
<authentication mode="Windows"/> <!-- 应用程序级别跟踪记录
应用程序级别跟踪在应用程序内为每一页启用跟踪日志输出。
设置 trace enabled="true" 以启用应用程序跟踪记录。如果 pageOutput="true",则
跟踪信息将显示在每一页的底部。否则,可以通过从 Web 应用程序
根浏览 "trace.axd" 页来查看
应用程序跟踪日志。
-->
<trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true"/> <!-- 会话状态设置
默认情况下,ASP.NET 使用 cookie 标识哪些请求属于特定的会话。
如果 cookie 不可用,则可以通过将会话标识符添加到 URL 来跟踪会话。
若要禁用 cookie,请设置 sessionState cookieless="true"。
-->
<sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;user id=sa;password=" cookieless="false" timeout="20"/> <!-- 全球化
此节设置应用程序的全球化设置。
-->
<globalization requestEncoding="GB2312" responseEncoding="GB2312" culture="zh-CN" fileEncoding="GB2312"/>
<!--设置上传时间与文件最大大小-->
<httpRuntime executionTimeout="3600" maxRequestLength="1024000"/>
</system.web>
</configuration>
其实是你的操作错误,
我研究了一下,你要注意,“个”的UTF8 编码的ASCII值是:228,184,170
所以你不可以将它付值给一个string 因为170是不可见字符所以如果你要处理一个utf8 文件时应该使用二进制读方式将之付给byte[],如果不是文件比如是socket 接收到的也是一样是byte[]所以我建了示例如下:private string GetOfUTF8(byte[] strObj) {
//开始解码
System.Text.Decoder utf8Decoder = System.Text.Encoding.UTF8.GetDecoder(); int charCount = utf8Decoder.GetCharCount(strObj, 0, strObj.Length);
Char[] chars = new Char[charCount];
int charsDecodedCount = utf8Decoder.GetChars(strObj, 0, strObj.Length, chars, 0); return new string(chars);
}private void button1_Click(object sender, System.EventArgs e) {
string str = "个";
byte[] bytes; //模拟编码
System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding();
bytes = utf8.GetBytes(str); //这里是“个”的utf8 的编码值 str = GetOfUTF8(bytes);
MessageBox.Show(str); str = "娴嬭瘯"; //这是“测试”的UTF8值
bytes = System.Text.Encoding.Default.GetBytes(str);
str = GetOfUTF8(bytes);
MessageBox.Show(str);
}
//开始解码
System.Text.Decoder utf8Decoder = System.Text.Encoding.UTF8.GetDecoder(); int charCount = utf8Decoder.GetCharCount(strObj, 0, strObj.Length);
Char[] chars = new Char[charCount];
int charsDecodedCount = utf8Decoder.GetChars(strObj, 0, strObj.Length, chars, 0); return new string(chars);
}其中 strObj 就是你要解码的UTF8 的ASCII 值数组,比如读一个UTF8编码文件名叫 myf.xmlFileStream fs = new FileStream(@"C:\myf.xml",FileMode.Open, FileAccess.Read);
int byteLength = (int)fs.Length;
byte[] wf = new byte[byteLength];
fs.Read(wf,0,byteLength);
fs.Close();
fs = null;然后 GetOfUTF8(wf) 就可以了,我试过可以的,原来走了弯路是因为老是想将它付给string,晕啊。。
Response.Write(str)
显示结果:测试
str = Encoding.UTF8.GetString(Encoding.GetEncoding("GB2312").GetBytes(str))
Response.Write(str)这样你能解成什么呀?
2 Dim b As Byte() = Encoding.Unicode.GetBytes(s) 'b(0)=42 b(1)=78
3 b = Encoding.Utf8.GetBytes(s) 'b(0)=228 b(1)=184 b(2)=170
4 s = Encoding.Default.GetString(b) 's="涓"
5 b = Encoding.Unicode.GetBytes(s)
'b(0)=147 b(1)=109 b(2)=0 b(3)=0 你看,问题已经出现了
6 b = Encoding.Default.GetBytes(s) 'b(0)=228 b(1)=184 b(2)=0
7 s = Encoding.UTF8.GetString(b) 's=""
8 b = Encoding.Unicode.GetBytes(s) 'b(0)=0 b(1)=0 .Net是使用Unicode编码的字符串的,一般的Unicode指的是Utf16。对上面代码的分析如下:
2."个" 的Utf16编码是: 42 78
3."个" 的Utf 8编码是: 228 184 170
4.把228 184 170经过gb2312到utf16的编码转换,s->“涓”
5.这时变量s里的内容是:147 109 0 0 (四个字节组成,后两个是0。“涓”的Unicode编码是147 109)
6.对s作Utf16到gb2312的转换:147 109 0 0 -> 228 184 0
7.把228 184 0作Utf8到Utf16的编码转换,s->“”
8.这时变量s里的内容是:0 0,也就是说经过一番编码转换后不再为开始时的42 78了总结:
从上面可以看到问题的所在:utf8编码跟utf16编码是一一对应,而utf8(或utf16)跟gb2312却不是,即unicode到gb2312的转换是不可逆的。
搜索了一番MSDN,在.Net里对字符编码操作真辛苦,如果有指针用就好了……
上面不能正确转换是因为那不是纯正的UNICODE TO GB2312或者GB2312 TO UNICODE的转换.例如第四行“把228 184 170经过gb2312到utf16的编码转换”,而228 184 170 根本就不是gb2312编码,是utf8。
byte[] bytes = new byte[str.Length];for (int i=0; i<str.Length; i++){
bytes[i] = (int)str[i];
}
GetOfUTF8(bytes);不过我怀疑在string str = (string)Request.Form["abc"]; 又会出错,因为这个string 转换估计会出错,你试试先。另外,如果不行,你先回答你怎么将“个”字的UTF8码写在表单的 abc 项里的呢??
byte[] bytes = new byte[str.Length];for (int i=0; i<str.Length; i++){
bytes[i] = (byte)str[i];
}
GetOfUTF8(bytes); //这个子程在上面原贴内
C#的字符串是使用UNICODE编码的,所以对任何的string->byte,使用System.Text.Encoding.Unicode.GetBytes这函数可以实现。另外对你的这一段代码有疑问:
for (int i=0; i<str.Length; i++){
bytes[i] = (byte)str[i];
}str[i]是CHAR类型,一个UNICODE字符,双字节,把它强制转换成Byte会有什么后果呢?我用你的代码做了个实验如下:
string str ="娴";
byte[] bytes = new byte[str.Length];
int j;
for (int i=0; i<str.Length; i++)
{
bytes[i] = (byte)str[i]; //bytes[1]=52 (16进制为 34)
j=(int)str[i]; //j=23092 (16进制为5A34)
}
很清楚了吧,字符的第一字节的数据丢失了。这样强制转换一定不正确的。
按 zzhuz(大件)所说,等于没有解法了?请两位再赐教,谢谢
先不理客户端如何提交数据(因为我不熟:),我们就从数据POST到服务器端处理这一步开始。
你设断点,在BEHIND CODE里能正常看到这“个”字吗?如果能,那好,这字符串是UNICODE编码的,现在要做的是把UNICODE编码的字符串写进GB2312的XML文件里。
那很简单嘛~~用Encoding.Default.GetBytes函数实现字符串从UNICODE到GB2312编码的编码转换(返回的是BYTE数组)。
最后以二进制的方式把这字节数组写进你的XML文件里就完事了。
byte[] bytes = new byte[str.Length];for (int i=0; i<str.Length; i++){
bytes[i] = (byte)str[i];
}
GetOfUTF8(bytes); //这个子程在上面原贴内不对,你原来能解的,现在都不行了
大件能如果Encoding.Default.GetBytes是不行的
2,数据-> request.form("abc")
3,问题在 request.form 时就已经不对劲了,它是object 其实是string 装箱,如果我们试着将request.form 内容拆箱成其它类似就会提示无法将string 转成 XXX型,既然它是string 那么箱内的内容也已经不正常了。因为第三个字符170 并且它是单数字节非GB2312(双节)或unicode(双节)可表示字符自然就出问题了(上面我说过了测试二字可以是因为刚好6字节可以转到GB或unicode)可见这种方式是非正当的,你似乎应该考虑一下从post 进来的数据指定为gb 或unicode 入手试试
<form name="form1" action="a.aspx" accept-charset="GB2312">我在<meta>里也设了是GB2312了,不知道为何?
楼主的问题在于不应该把UTF8编码的字符作GB->Unicode的转换“我能Get到的是"个"或者是"测试"等其它的字符串的utf-8编码”,楼主为何不直接把字符作utf8->unicode的转换呢?真奇怪。例如这样:
(收到UTF8编码的字符串s--看上去是一堆乱码)
b=Encoding.Unicode.GetBytes(s) //得到UTF8编码的字节数组
s=Encoding.Utf8.GetString(b) //对字节数组作utf8->unicode的转换。
(现在的s应该不是乱码了,跟着就好办)
<xsl:attribute name="action">../re.aspx?id=<xsl:value-of select="BBS/mainbbs/id" /></xsl:attribute>
<table width="96%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td>
<div align="center">
<textarea name="content" cols="60" rows="8"></textarea>
</div>
</td>
</tr>
<tr>
<td>
<input type="button" name="btnReply" value="回复" onclick="javascript:form1.btnReply.disabled=true;form1.submit();" />
<input type="reset" name="btnReset" value="重写" />
</td>
</tr>
<tr>
<td>
<br />
<font color="red">在这里发贴,表示您接受了本用户论坛的 用户行为准则。</font>
<br />
<font color="red">请您对您的言行负责,并遵守中华人民共和国有关法律、法规,尊重网上道德。</font>
</td>
</tr>
</table>
</form>
这里添的内容可以是符意字符串,比如可以输入"个","测试"等,还要以一段文章,在,re.aspx里,我要Response.Write(Requeset.Form["content"]);得到的是乱码,但是我用IE的编码改为utf-8能正确显示,我现在要把这正确显示的内容写到XML文件或者是数据库表中,所以我必须把Requeset.Form["content"]的内容转成正确的显示才能放到xml或数据库中,否则里面放的是乱吗.请大家再看一下,是否明白。另:我的xsl中其它的声明全是gb2312的如:<?xml version="1.0" encoding="gb2312" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">还有
<meta http-equiv="Content-Type" content="text/html;charset=gb2312" />谢谢大家~~
这里添的内容可以是符意字符串,比如可以输入"个","测试"等,还可以是一段文章,
http://61.145.116.154/WebProject3/page1.aspx.txt
http://61.145.116.154/WebProject3/re.aspx.cs.txt
http://61.145.116.154/WebProject3/re.aspx.txt
http://61.145.116.154/WebProject3/Web.config.txt
在http://61.145.116.154/WebProject3/page1.aspx这页按右键“编码”->“utf-8”
页面的中文都乱码了,先不理它。在textarea里写上“测试”,按确定。
页面转到了re.aspx,显示“娴嬭瘯”,这时再按右键“编码”->“utf-8”,乱码又变回“测试了”----终于可以模拟出你的做法了。这现象的解析:
提交时page1.aspx的textarea的数据是utf-8编码的。而又因为在web.config里有这样一句:requestEncoding="gb2312",所以re.aspx把提交过来的数据(utf8编码)
作了gb->unicode的转换,得到的是“娴嬭瘯”。
又因为在web.config里又有这样一句:responseEncoding="gb2312",所以它把“娴嬭瘯”作unicode->gb的转换(这样数据上又转回到原来的utf-8编码了)再发送到客户端浏览器。如果用户以gb2312方式就能看到“娴嬭瘯”;以utf-8的方式就能看到“测试”。
针对这种情况,如果改成requestEncoding="utf-8"那就没问题了。 以上对web.config里的requestEncoding和responseEncoding的作用是跟据这个例子猜的,也不知道是否真的是这样,还望指教。
希望这个例子对你有帮助。
提交时page1.aspx的textarea的数据是utf-8编码的。 --->我分明提交的是gb2312,因为
<form name="form1" method="post" accept-charset="gb2312">,要不我怎么设置它让提交的时候是gb2312呢,你上面分析的很对,但是我就是想把它设置提交gb2312,为什么却是提交的是utf-8呢?
private void button1_Click(object sender, System.EventArgs e) {
string str = "娴嬭瘯";
byte[] bytes = new byte[str.Length * 2];
string tmp = ""; for (int i=0; i<str.Length; i++){
// 当前字符十六进制值
string hexCode = ((int)str[i]).ToString("x");
//高位在前
string hexCodeHigh = hexCode.Substring(2,2);
//低位
string hexCodeLow = hexCode.Substring(0,2); tmp += hexCodeHigh + hexCodeLow + ","; bytes[i*2] = Convert.ToByte(hexCodeLow,16);
bytes[i*2+1] = Convert.ToByte(hexCodeHigh,16);
} MessageBox.Show("bytes value: \n\n" + tmp);
}// 真正的utf8 值
private void button2_Click(object sender, System.EventArgs e) {
string str1 = "测试";
string tmp = "";
byte[] b = System.Text.Encoding.UTF8.GetBytes(str1); for (int i=0; i<b.Length; i++){
tmp += b[i].ToString("x");
if (i % 2 != 0) tmp += ",";
} MessageBox.Show("bytes value: \n\n" + tmp);
}二次显示的bytes 数组并不一样,所以可以说“娴嬭瘯”并非“测试”二字的utf8 值!此论点可以根据“娴嬭瘯”还必须经过 encoding.utf8.getbytes 再次编码才可以得到它真正的 bytes 数组给:private string GetOfUTF8(byte[] strObj) {
//开始解码
System.Text.Decoder utf8Decoder = System.Text.Encoding.UTF8.GetDecoder(); int charCount = utf8Decoder.GetCharCount(strObj, 0, strObj.Length);
Char[] chars = new Char[charCount];
int charsDecodedCount = utf8Decoder.GetChars(strObj, 0, strObj.Length, chars, 0); return new string(chars);
}进行解码,这就非常奇怪了。。楼上大件所说的问题我基本上并不是很赞同所以都没有直接发表意见,你所说的理论是不能转为unicode 字符,否则会丢失成为\u0000,你要知道,任何ascii 码都可以转为unicdoe,不管“个”的utf8 三个字节所对应的是什么字符都可以用ascii 来表示的,但是在用endcoding 编码成为unicode 才会被强制忽略,因为170 非双字节。研究中
此library 只有一个作用,就是将参数 string myStr 直接取ascii 码方式转换为 byte[] 并返回,这样就避免了猪头.net 的自动转换为unicode 的问题,就是说实现如下功能类似上面的button1_Click 子程功能:public byte[] GBToBytes(string gbCodeStr) {
string str = gbCodeStr;
byte[] bytes = new byte[str.Length * 2];
string tmp = ""; for (int i=0; i<str.Length; i++){
// 当前字符十六进制值
string hexCode = ((int)str[i]).ToString("x"); //高位在前
string hexCodeHigh = hexCode.Substring(2,2); //低位
string hexCodeLow = hexCode.Substring(0,2); tmp += hexCodeHigh + hexCodeLow + ","; bytes[i*2] = Convert.ToByte(hexCodeLow,16);
bytes[i*2+1] = Convert.ToByte(hexCodeHigh,16);
} return bytes;
}然后调用方法为:string newString = GetOfUTF8(GBToBytes(Request.Form["abc"]));这个子程序出发点是正确的,但是在.net 下不行,因为string str = gbCodeStr; 这句付值已经被进行了自动转换也是就是 gb->unicode,所以必须用非.net 语言写一个库给.net 引用来解决这个问题,如果楼主不会就回贴我帮忙写一个肯定可以解决这个问题
以上我说的全没理论依据,都是在相关的实验中总结出来(dot Net配合Delphi做的)。
有同感,从这贴子中学习到不少东西,继续研究中