感觉奇怪。给浏览器输入一个网址,为什么浏览器能够以正确的编码方式来显示页面?
如果说浏览器先把页面以string 形式下下来。那也只是把二进制码下了下来。怎么把二进制代码转换为人眼能看懂的字符?
应该要先读出chatset后面的编码方式,然后以这个编码方式把整个网页编码显示。那么问题是chatset本身就是要在知道编码方式的前提下才能解析进而获得编码方式。大家来讨论一下。

解决方案 »

  1.   

    response 写回流的 head中都有相关信息呢.
      

  2.   

    http://topic.csdn.net/u/20100108/17/c0505e9c-4d96-4ff2-8ea2-a489554c950d.html
    参考.using System;
    using System.Net;
    using System.Text;
    using System.Text.RegularExpressions;class Program
    {
      // 获取网页的HTML内容,根据网页的charset自动判断Encoding
      static string GetHtml(string url)
      {
        return GetHtml(url, null);
      }  // 获取网页的HTML内容,指定Encoding
      static string GetHtml(string url, Encoding encoding)
      {
        byte[] buf = new WebClient().DownloadData(url);
        if (encoding != null) return encoding.GetString(buf);
        string html = Encoding.UTF8.GetString(buf);
        encoding = GetEncoding(html);
        if (encoding == null || encoding == Encoding.UTF8) return html;
        return encoding.GetString(buf);
      }  // 根据网页的HTML内容提取网页的Encoding
      static Encoding GetEncoding(string html)
      {
        string pattern = @"(?i)\bcharset=(?<charset>[-a-zA-Z_0-9]+)";
        string charset = Regex.Match(html, pattern).Groups["charset"].Value;
        try { return Encoding.GetEncoding(charset); }
        catch (ArgumentException) { return null; }
      }  // 根据网页的HTML内容提取网页的Title
      static string GetTitle(string html)
      {
        string pattern = @"(?si)<title(?:\s+(?:""[^""]*""|'[^']*'|[^""'>])*)?>(?<title>.*?)</title>";
        return Regex.Match(html, pattern).Groups["title"].Value.Trim();
      }  // 打印网页的Encoding和Title
      static void PrintEncodingAndTitle(string url)
      {
        string html = GetHtml(url);
        Console.WriteLine("[{0}] [{1}]", GetEncoding(html), GetTitle(html));
      }  // 程序入口
      static void Main()
      {
        PrintEncodingAndTitle("http://www.msdn.net/");
        PrintEncodingAndTitle("http://www.cnblogs.com/");
        PrintEncodingAndTitle("http://www.cnblogs.com/skyiv/");
        PrintEncodingAndTitle("http://www.csdn.net/");
        PrintEncodingAndTitle("http://news.163.com/");
      }
    }
    /* 程序输出:
    [] [MSDN: Microsoft Developer Network]
    [System.Text.UTF8Encoding] [博客园 - 程序员的网上家园]
    [System.Text.UTF8Encoding] [空间/IV - 博客园]
    [System.Text.UTF8Encoding] [CSDN.NET - 中国最大的IT技术社区,为IT专业技术人员提供最全面的信息传播和服务平台]
    [System.Text.DBCSCodePageEncoding] [新闻中心_网易新闻]
    */
      

  3.   

    ResponseHeader里面的Content-Type: text/html; charset=UTF-8
    和页面的Head里面的meta http-equiv="Content-Type" content="text/html; charset=GB2312
      

  4.   

    6楼同志劳苦但功却不高。回答问题没有答到点子上,你的这些方法一般人都写得出来。注意到没有,你的这些方法都是在“知道”页面的编码方式下才能进行的。比如你的这个:
      // 根据网页的HTML内容提取网页的Encoding
      static Encoding GetEncoding(string html)
      {
        string pattern = @"(?i)\bcharset=(?<charset>[-a-zA-Z_0-9]+)";
        string charset = Regex.Match(html, pattern).Groups["charset"].Value;
        try { return Encoding.GetEncoding(charset); }
        catch (ArgumentException) { return null; }
      }我请问,你用到的html,它是个字符串,既然要从它里面匹配charset出来,就说明事先已经对它进行了编码解析了(注意:同一二进制流,以不同方式编码,显然会得到不同的字符串,即使是乱码也是字符串呀),而浏览器是怎么知道用什么编码方式来编码页面的二进制流的呢。另外,你用了正则,那我想,pattern是什么编码方式的,Regex.Match()这个方法就应该会以什么编码方式对html进行了匹配的,但是你的pattern到底是以什么方式编码的呢。
    有朋友说浏览器通过responseHeader来知道页面的编码方式。那应该是web服务器与浏览器之间有一个默认的对responseHeader的编码规范,比如responseHeader一定要用ANSI编码,这样才可能再没有任何编码提示的情况下正确解析页面。
    浏览器正确解析页面,显示出来,用户能看懂后。我想问,程序员用程序把页面字符串获得后,要从中取得某些字符或者匹配某些内容。又是怎么知道页面字符串是什么编码的?因为既然已经可以用代码来处理了,就说明下载已经完成,不可能再去读responseHeader了。
      

  5.   

    另:http://topic.csdn.net/u/20100108/17/c0505e9c-4d96-4ff2-8ea2-a489554c950d.html 
    说是.net环境里,字符都是以utf16编码的。那就是不管responseHeader里是什么编码,或者chatset是什么,一律编码为utf16? utf16这个编码方式不大了解,可能是一个字符用比其它编码方式都多的“位”来存储,因为只有这样才能“通吃”其它编码方式,而不会乱码。有了解的可以说说。
    假设.net环境下都是这种编码的话。那么说我们写的代码都是这个编码的,从外界读取的字符等都是这个方式编码的,那就统一了,对字符串操作也就自然不用每次都指定编码方式了,呵呵,是不是这样理解的,大鸟出来放话。
      

  6.   


    用代码也可以读取responseHeader.如果responseHeader里提供了编码方式数据,就很容易处理了。
    问题是,很多网站的responseHeader并没有加入编码方式。在这种情况下,就只能针对具体的网站进行具体处理。
      

  7.   

    .NET在内存中的字符编码是UTF-16,但存储是用UTF-8,所以对传入传出的字符还是按UTF-8编码...另外对不是char、string类型存在的字符如byte[]、stream需要你明确指定编码,.NET是不会乱猜测给你编解码的...
      

  8.   

    UTF-16也不是为了“能“通吃”其它编码方式,而不会乱码”,只是为了容纳更多字符集...不同编码方式如果没有确定的编码转换规则必定会乱码,UTF-16也不例外...
      

  9.   

       reader = new StreamReader(stream, System.Text.Encoding.Default);                string buffer = "", line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        buffer += line + "\r\n";
                    }
                    string strEncoding = GetEncoding(buffer);                Encoding encoding;
                    if (strEncoding.ToUpper() == "UTF-8")
                        encoding = Encoding.UTF8;
                    else if (strEncoding.ToUpper() == "UTF-7")
                        encoding = Encoding.UTF7;
                    else if (strEncoding.ToUpper() == "UNICODE")
                        encoding = Encoding.Unicode;
                    else if (strEncoding.ToUpper() == "GB2312")
                        encoding = Encoding.GetEncoding("GB2312");
                    else if (strEncoding.ToUpper() == "BIG5")
                        encoding = Encoding.GetEncoding("BIG5");
                    else
                        encoding = Encoding.Default;                if (encoding != Encoding.Default)
                    {
                        request.Timeout = 6000;
                        request = (HttpWebRequest)WebRequest.Create(strUrl);
                      }
      

  10.   

     #region 获取HTML文件编码
            /// <summary>
            /// 获取HTML文件编码
            /// </summary>
            /// <param name="inputString">HTML文件</param>
            /// <returns></returns>
            public static string GetEncoding(string inputString)
            {
                Regex r = new Regex("charset\\s*=\\s*(?:\"(?<1>[^\"]*)\"|(?<1>\\S+))", RegexOptions.IgnoreCase);
                Match m = r.Match(inputString);
                return m.Groups[1].Value.Replace("\"", "").Replace(">", "").ToUpper();
            }
            #endregion
        }
      

  11.   

    这个问题,有点复杂~除非html中标明了编码,否则浏览器必须根据实际内容来判断。而这种判断,还是会有问题,偶尔会判断失误,举个例子,比如记事本里输入 联通 然后保存,再打开就是乱码。放浏览器里也一样,这是由于gb编码有事会和unicode模板重叠,导致无法区分。下面是我自己写的函数,根据字节流判断编码,主要能区分:UTF8/UNICODE/GB2312的编码。对于unicode,主要是判断数据头(这主要针对标准的unicode编码的文本文件,对于网页数据流,不一定有用)        /// <summary>
            /// 检查参数字节数组内容的编码,主要判断是UTF-8或是GB2312/GBK
            /// Created by: b_wind, 2009-10
            /// </summary>
            /// <param name="raw">包含文本数据的字节数组</param>
            /// <returns>推断出的数据编码</returns>
            public static Encoding DetectEncoding(byte[] raw)
            {
                if (raw.Length >= 3)
                {
                    if (raw[0] == 0xEF && raw[1] == 0xBB && raw[2] == 0xBF)
                        return Encoding.UTF8;
                }
                if (raw.Length >= 2)
                {
                    if (raw[0] == 0xFF && raw[1] == 0xFE)
                        return Encoding.Unicode;
                    else if (raw[0] == 0xFE && raw[1] == 0xFF)
                        return Encoding.BigEndianUnicode;
                }
                int utf8_freq = 0;
                for (int i = 0; i < raw.Length; i++)
                {
                    int c = GetByte1Count(raw[i]);
                    if (c == 0)
                        continue;
                    if (c == 1 && i + 1 <= raw.Length - 1)
                    {
                        if ((raw[i + 1] >> 7) == 1)
                            return Encoding.Default;
                    }
                    if (c + i > raw.Length)
                        break;
                    for (int j = 1; j < c; j++)
                    {
                        if ((raw[i + j] >> 6) != 2)
                        {
                            return Encoding.Default;
                        }
                        else
                        {
                            if (j == c - 1)
                            {
                                utf8_freq++;
                                i += j;
                            }
                        }
                    }
                    if (utf8_freq >= 5)
                        return Encoding.UTF8;
                }
                if (utf8_freq > 2)
                    return Encoding.UTF8;
                else
                    return Encoding.Default;
            }        private static int GetByte1Count(byte b)
            {
                if ((b & 0xFC) == 0xFC)
                    return 6;
                else if ((b & 0xF8) == 0xF8)
                    return 5;
                else if ((b & 0xF0) == 0xF0)
                    return 4;
                else if ((b & 0xE0) == 0xE0)
                    return 3;
                else if ((b & 0xC0) == 0xC0)
                    return 2;
                else if ((b & 0x80) == 0x80)
                    return 1;
                else
                    return 0;
            }
      

  12.   

    楼上有两位已经说了,我们随便找个通讯调试程序就可以看明白了。比如当前这个页面,我的浏览器收到的消息就是这样的:[code]TTP/1.1 200 OK
    Server: CWS/1.0.64
    Date: Sun, 17 Jan 2010 10:33:33 GMT
    Content-Type: text/html; charset=utf-8
    Transfer-Encoding: chunked
    Connection: keep-alive
    Vary: Accept-Encoding
    X-UA-Compatible: IE=EmulateIE7
    X-Powered-By: ASP.NET
    Last-modified: 2010-01-17 18:26:17
    Cache-control: private
    Content-Encoding: gzip
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>编码问题,怎么取得页面的编码方式?进者分,17来讨论</title>
    <link href="http://c.csdn.net/bbs/t/5/t5.css" rel="stylesheet" type="text/css" />
    <link href="http://www.csdn.net/images/favicon.ico" rel="SHORTCUT ICON" />
    <script type="text/javascript">
    var tinfo = {
    pdate: "2010-01-12 21:20:57"
    ,sid: "3036657c-277c-476c-982d-75f154e09050"
    ,tid: "d4563a47-bd15-4ec9-9417-f3a400b5a4cf"
    ,ba: "DotNET"
    ,sa: "ASPDotNET"
    };
    </script>
    <script type="text/javascript" src="/u/t5/t5.js"></script>
    <script type="text/javascript" src="http://counter.csdn.net/a/js/AreaCounter.js"></script>
    </head>
    <body id="bbscsdn_wrap"><div class="tad">
        <iframe id="Topic_Top" marginwidth="0" marginheight="0" frameborder="0" scrolling="no" width="100%" height="0" src="/u/t5/include/ad1.asp" ></iframe>
    </div>
    <div class="nav">
         <a href="#"><img src="http://c.csdn.net/bbs/t/5/i/pic_logo.gif" alt="" class="logo" /></a>
         <ul class="txt">
            <li><a href="http://www.csdn.net/" target="_blank">首页</a>|</li>
    <li><a href="http://hi.csdn.net/" target="_blank">空间</a>|</li>
    <li><a href="http://news.csdn.net/" target="_blank">新闻</a>|</li>
    <li><a href="http://bbs.csdn.net/" target="_blank">论坛</a>|</li>
    <li><a href="http://blog.csdn.net/" target="_blank">博客</a>|</li>
    <li><a href="http://download.csdn.net/" target="_blank">下载</a>|</li>
    <li><a href="http://book.csdn.net/" target="_blank">读书</a>|</li>
    <li><a href="http://wz.csdn.net/" target="_blank">网摘</a>|</li>
    <li><a href="http://live.csdn.net/" target="_blank">视频</a>|</li>
    <li><a href="http://www.dearbook.com.cn/" target="_blank">书店</a>|</li>
    <li><a href="http://www.programmer.com.cn/" target="_blank">程序员</a>|</li>
    <!--<li><a href="http://www.itliyu.com/" target="_blank">求职招聘</a>|</li>-->
    <li><a href="http://prj.csdn.net/" target="_blank">项目交易</a>|</li>
    <li><a href="http://training.csdn.net/" target="_blank">培训</a>|</li>
    <li><a href="http://daohang.csdn.net/" target="_blank">网址</a></li>
    </ul>
    .................[/code]
      

  13.   

    TTP/1.1 200 OK
    Server: CWS/1.0.64
    Date: Sun, 17 Jan 2010 10:33:33 GMT
    Content-Type: text/html; charset=utf-8
    Transfer-Encoding: chunked
    Connection: keep-alive
    Vary: Accept-Encoding
    X-UA-Compatible: IE=EmulateIE7
    X-Powered-By: ASP.NET
    Last-modified: 2010-01-17 18:26:17
    Cache-control: private
    Content-Encoding: gzip
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>编码问题,怎么取得页面的编码方式?进者分,17来讨论</title>
    <link href="http://c.csdn.net/bbs/t/5/t5.css" rel="stylesheet" type="text/css" />
    <link href="http://www.csdn.net/images/favicon.ico" rel="SHORTCUT ICON" />
    <script type="text/javascript">
    var tinfo = {
    pdate: "2010-01-12 21:20:57"
    ,sid: "3036657c-277c-476c-982d-75f154e09050"
    ,tid: "d4563a47-bd15-4ec9-9417-f3a400b5a4cf"
    ,ba: "DotNET"
    ,sa: "ASPDotNET"
    };
    </script>
    <script type="text/javascript" src="/u/t5/t5.js"></script>
    <script type="text/javascript" src="http://counter.csdn.net/a/js/AreaCounter.js"></script>
    </head>
    <body id="bbscsdn_wrap"><div class="tad">
        <iframe id="Topic_Top" marginwidth="0" marginheight="0" frameborder="0" scrolling="no" width="100%" height="0" src="/u/t5/include/ad1.asp" ></iframe>
    </div>
    <div class="nav">
         <a href="#"><img src="http://c.csdn.net/bbs/t/5/i/pic_logo.gif" alt="" class="logo" /></a>
         <ul class="txt">
            <li><a href="http://www.csdn.net/" target="_blank">首页</a>|</li>
    <li><a href="http://hi.csdn.net/" target="_blank">空间</a>|</li>
    <li><a href="http://news.csdn.net/" target="_blank">新闻</a>|</li>
    <li><a href="http://bbs.csdn.net/" target="_blank">论坛</a>|</li>
    <li><a href="http://blog.csdn.net/" target="_blank">博客</a>|</li>
    <li><a href="http://download.csdn.net/" target="_blank">下载</a>|</li>
    <li><a href="http://book.csdn.net/" target="_blank">读书</a>|</li>
    <li><a href="http://wz.csdn.net/" target="_blank">网摘</a>|</li>
    <li><a href="http://live.csdn.net/" target="_blank">视频</a>|</li>
    <li><a href="http://www.dearbook.com.cn/" target="_blank">书店</a>|</li>
    <li><a href="http://www.programmer.com.cn/" target="_blank">程序员</a>|</li>
    <!--<li><a href="http://www.itliyu.com/" target="_blank">求职招聘</a>|</li>-->
    <li><a href="http://prj.csdn.net/" target="_blank">项目交易</a>|</li>
    <li><a href="http://training.csdn.net/" target="_blank">培训</a>|</li>
    <li><a href="http://daohang.csdn.net/" target="_blank">网址</a></li>
    </ul>
    ...............
      

  14.   


    谢谢vrhero同志的回答。你说“.NET在内存中的字符编码是UTF-16,但存储是用UTF-8”
    那么我想推一下理:我们用vs打开一个.cs文件并编辑,这个过程应该是:
    第一步:.net把以文件形式存储在硬盘上的.cs文件载入内存。这一步是把utf-8的编码转化为utf-16;
    第二步:.net把内存中的这个.cs文件在.net环境下显示出来(就是在vs代码编辑器中)。为什么要强调是在".net环境下显示出来"呢?因为既然是utf-16编码的,其它的程序(比如计事本)就无法正确显示,因为它们不具体编码和解码utf-16的功能。而且这里还有个前提是:.net环境要维护一个对应关系:即每个utf-16字符对应的具体的人可以看明白的“字”。
    第三步:我们要编辑改变这个.cs文件的内容。我们要通过键盘输入“字符”,或者更准确的讲是“一串按键动作”。那么我们输入的“字符”应该是先经过“输入法”处理的!我们切掉不同的输入法,按下一串相同的键,得到的字符从二进制角度讲是一样的,但是显示出来的“字符”是不一样的,也就是对同样的“信息”的编码是不同的。我们直接在vs编辑器中对.cs文件进行输入动作,那实际上是vs编辑器从输入法程序中获得“信息”并正确编码。而且要同时完成两个步骤:以utf-16编码方式对传过来的其它编码方式的“信息”往内存进行转存;并以utf-8编码方式往硬盘进行转存。总结:.net以uft-16来工作;以utf-8来保存结果,以备与其它程序兼容。
     不知道以上理解是否正确,希望大家来确认。
      

  15.   


    对于此楼的回答,我的回答是,其实我想问的是:浏览器是怎么从页面请求的回复中读出(解析出)下面这些东西的:
    TTP/1.1 200 OK
    Server: CWS/1.0.64
    Date: Sun, 17 Jan 2010 10:33:33 GMT
    Content-Type: text/html; charset=utf-8
    Transfer-Encoding: chunked
    Connection: keep-alive
    Vary: Accept-Encoding
    X-UA-Compatible: IE=EmulateIE7
    X-Powered-By: ASP.NET
    Last-modified: 2010-01-17 18:26:17
    Cache-control: private
    Content-Encoding: gzip
    特别是:Content-Type: text/html; charset=utf-8这一行。
    当然其它可以设想一下,要获得这些信息其它很容易,前提是又方有个“约定”(服务器和浏览器)。
    什么约定呢?就是比如服务器向浏览器约定:我给你回复的内容,不管长短,前100位都是我们通讯所固定占据的位置。这些固定位置的信息全部以ascii编码,而不管其它内容是怎么编码的。在这100个固定位置里的第50~60位存储的是回复其它的内容(也就是用户真正希望看到的信息)的编码信息。
    有了如上约定当然可以正确解析出任何服务器的回复了。
    不知道我设想的对不对呢?
      

  16.   

    不是这个理由...是因为Windows是采用UTF-8编码的(Windows 2000以后版本),所以被OS处理的字符没有明确声明编码方式都被作为UTF-8编码,和输入法什么的没有关系....NET之所以采用UTF-16而不是UTF-8是为未来考虑的设计,你的123步都是没有依据的...以文件形式存储的字符都必须明确声明编码方式,.NET在存储时是对未经声明编码的字符以UTF-8存储,对于声明了编码方式的当然还是按该编码...你要记住程序是不会自作主张的,所有转换规则都是“人”事先定义的...我感觉你已经有点钻牛角尖了...
      

  17.   

    你34楼的“设想”根本不需要“设想”...因为这是HTTP协议的“约定”,去看看HTTP协议吧...还是那句话...程序是不会自作主张的,所有规则、约定都是“人”事先定义的...