<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>简单生活 -- Kevin Yang的博客 &#187; 编解码</title>
	<atom:link href="http://www.imkevinyang.com/tags/%e7%bc%96%e8%a7%a3%e7%a0%81/feed" rel="self" type="application/rss+xml" />
	<link>http://www.imkevinyang.com</link>
	<description>It&#039;s all about sharing</description>
	<lastBuildDate>Sun, 05 Feb 2012 15:37:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Asp.Net页面的编码问题</title>
		<link>http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html</link>
		<comments>http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html#comments</comments>
		<pubDate>Fri, 27 Nov 2009 06:13:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[疑难杂症]]></category>
		<category><![CDATA[AspDotNet]]></category>
		<category><![CDATA[Content-Type]]></category>
		<category><![CDATA[HTTP Watch]]></category>
		<category><![CDATA[Response]]></category>
		<category><![CDATA[字符集]]></category>
		<category><![CDATA[样式表]]></category>
		<category><![CDATA[编解码]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html</guid>
		<description><![CDATA[莫名其妙的问题
<p>这些天，一个客户的网站遇到了一些莫名其妙的问题。先是首页在Firefox下看正常，但是在IE上看，同个样式表文件，却有部分样式没能加载，导致导航菜单没有背景并且走位了。后来样式的问题解决了，但是又出现了一个页面上，部分文字乱码部分正常的诡异问题。</p>
字符编码导致的样式文件解析错误
<p>对于第一个&#8230;</p>]]></description>
			<content:encoded><![CDATA[<h2>莫名其妙的问题</h2>
<p>这些天，一个客户的网站遇到了一些莫名其妙的问题。先是首页在Firefox下看正常，但是在IE上看，同个样式表文件，却有部分样式没能加载，导致导航菜单没有背景并且走位了。后来样式的问题解决了，但是又出现了一个页面上，部分文字乱码部分正常的诡异问题。</p>
<h2>字符编码导致的样式文件解析错误</h2>
<p>对于第一个问题我的第一反应是CSS样式表中部分样式存在不兼容性。但是检查了导航菜单样式的写法，没有看出来有什么特别的，都是常见的属性常见的值。但是用IE自带的开发者工具看了一下出问题的元素的样式，发现和在Firebug中看到的样式居然不同。后来无意中在HTTP Watch中看了style.css文件的内容，发现注释有乱码，当即联想到以前写过的文章《<a title="文档字符集导致的脚本错误" href="http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html" target="_blank">文档字符集导致的脚本错误</a>》。当一个文档（HTML文档或是CSS文档）的文件存储字符集和浏览器解码使用的字符集不一致的时候会出现类似的问题，特别是utf-8编码过的文档却以gb2312去解码的时候，出现的问题就更诡异了。</p>
<p>于是我在IE上改用UTF-8去解析网页，结果果然，导航菜单的样式正常了，背景图片也正常加载了（虽然其他地方出现了一些乱码情况）。这证明了我的思路是对的。但是具体是哪个地方出了问题呢，为什么Firefox、Opera和Chrome下都没问题，偏偏就IE有问题呢？</p>
<p>我又仔细查看了客户给出的网页和样式文件，又分析了相关的HTTP消息，发现请求.aspx文件（出问题的网页文档）的时候，服务端返回的Content-Type是text/html;charset=gb2312，那么所有浏览器自然会以服务器返回的字符集来解析文档，这个没问题，但是<strong><font color="#008000">当网页中引用了外部资源的时候（在这里是css样式表），IE是使用当前网页的文档字符集去解析此外部资源，除非外部资源声明了编码格式（HTTP响应头中声明或是在文档最前方使用@charset声明），而Firefox、Opera和Chrome在CSS文件没有显式声明字符集的情况下，始终是以UTF-8来解码的。</font></strong></p>
<p>问题既然和样式相关，也就是说在使用gb2312解析该样式表的时候出现了问题，那可以猜到，样式表文件实际的存储格式是utf-8的。</p>
<p>为了找到具体出问题的地方，我用Notepad++——貌似手头只有这软件可以自由编解码——模拟了一下使用gb2312解码此utf-8格式的样式表的场景，发现了其中一段出问题的样式，UTF-8解码后很正常，因为本身就是UTF-8编码的：</p>
<pre class="csharpcode"><span class="rem">/*新导航*/</span>
#new_nav ul{ width:672px; height:33px; margin:0px; padding:0px;  }</pre>
<p>当使用gb2312解码之后得到如下:</p>
<pre class="csharpcode">/*鏂板鑸?/
#new_nav ul{ width:672px; height:33px; margin:0px; padding:0px;}</pre>
<p>很明显的，下面的样式都被注释掉了。自然一切问题都得以解释了。</p>
<p>解决办法很多种，但目标都是一个，保证文档声明和实际字符集的一致。对于CSS样式表，我们可以在文件头显式设置@charset ‘XXX’来声明字符集。或者在使用link引用外部样式表的时候显式加上charset属性。</p>
<p>另外，如果所有文件都能保存为utf-8 with signature的话，也就是带BOM标记的UTF-8编码格式，那么所有浏览器都能自识别，而不会产生识别错误的问题。</p>
<h2>Asp.Net中涉及到的编码问题</h2>
<p>第二个问题虽然我知道还是编解码的环节出了问题，但还是分析了我半天才找到问题所在。</p>
<h3>测试环境简化</h3>
<p>为了简单，我把第二个问题中涉及到的页面简化成如下两个文件：</p>
<p>Default.aspx文件：</p>
<pre class="csharpcode"><span class="asp">&lt;%@ Page Language=&quot;C#&quot; AutoEventWireup=&quot;true&quot; CodeFile=&quot;Default.aspx.cs&quot; Inherits=&quot;_Default&quot; %&gt;</span>
<span class="kwrd">&lt;!</span><span class="html">DOCTYPE</span> <span class="attr">html</span> <span class="attr">PUBLIC</span> <span class="kwrd">&quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span> <span class="kwrd">&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">html</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://www.w3.org/1999/xhtml&quot;</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">head</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">head</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">body</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span><span class="asp">&lt;%</span>= Msg <span class="asp">%&gt;</span><span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
        Aspx页面中的中文
    <span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">body</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">html</span><span class="kwrd">&gt;</span></pre>
<p>Default.aspx.cs后台代码文件：</p>
<pre class="csharpcode"><span class="kwrd">using</span> System;
<span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> _Default : System.Web.UI.Page
{
    <span class="kwrd">public</span> String Msg = <span class="str">&quot;代码中的中文&quot;</span>;
    <span class="kwrd">protected</span> <span class="kwrd">void</span> Page_Load(<span class="kwrd">object</span> sender, EventArgs e)
    {
    }
}</pre>
<p>两个文件非常简单，从aspx文件中输出一段文字，从cs文件中输出一段文件。</p>
<h3>Asp.Net页面涉及到的编解码环节</h3>
<p>为了理解第二个问题，我们首先先来看一下在Asp.Net中一个页面究竟会涉及到什么编码环节。</p>
<p><font color="#800080">1. 文件本身存储使用的编码（在Visual Studio中新建文件的默认编码是UTF-8 With BOM）</font></p>
<p><font color="#800080">2. 文件被Asp.Net引擎转换处理时使用的编码</font></p>
<p><font color="#800000">3. 文件写到HTTP响应流时使用的编码</font></p>
<p><font color="#800000">4. 文件在HTTP头声明的编码（Content-Type=”text/html;charset=xxx”）</font></p>
<p>对于第一个环节就不需要说了，直接“Advanced Save As..”然后选择相应编码即可。对于2、3、4环节中涉及到的编码，asp.Net提供了全局配置还有页面级配置两种方式。</p>
<p>在web.config文件中可以管理全局编码配置。</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">configuration</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">system.web</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">globalization</span> <span class="attr">responseEncoding</span><span class="kwrd">=&quot;utf-8&quot;</span> <span class="attr">fileEncoding</span><span class="kwrd">=&quot;utf-8&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">system.web</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">configuration</span><span class="kwrd">&gt;</span></pre>
<p>在system.web一节下添加globalization元素，它有几个可配置选项，具体参见<a title="Configures the globalization settings for an application" href="http://msdn.microsoft.com/en-us/library/hy4kkhe0.aspx" target="_blank">MSDN</a>。其中有两个属性和此次的问题相关，一个是fileEncoding（注意区分大小写），这个配置项决定了asp.net引擎在将aspx文件以及cs文件合并成html文档时使用的编码。<strong><font color="#008000">如果aspx或者cs文件的格式和此属性配置的不一致，那么就有可能导致生成的html文档出现乱码</font></strong>。默认情况下，该属性的值为ANSI编码，也就是说中文系统下为GB2312。但是如果文档本身存储格式是UTF-8 with BOM，那么asp.net将始终以UTF-8编码来解析aspx和cs文件。这也是为什么默认情况下什么都不需要配置的缘故。</p>
<p>另外一个属性是responseEncoding，这个配置决定了上述的第3、4环节，也就是当asp.net生成好html文档之后，将其写入HTTP响应正文时使用的编码，同时会设置HTTP的Content-Type响应头中的charset域。如果前面的环节没有问题，html生成正常的话，那么这里无论设置什么编码浏览器均会正常解码，页面上都不会有乱码。但是如果前面的步骤出了问题，那自然就会有乱码产生了。</p>
<p>注意上面4个环节我分别用了两种颜色来标明，看了上面的解释之后你就很明白了，1和2环节编码需一致，否则中间生成的html文档就已经有乱码了。3和4环节的编码须一致，否则浏览器显示不正常。</p>
<p>客户网站出现的部分文字乱码问题的原因就是因为aspx文件存储的格式是不带BOM标记的UTF-8（天知道他是怎么给整成这个编码的）而CS文件没有改动过，还是UTF-8 with BOM，而全局的fileEncoding没有配置，因此在第二个环节的时候使用gb2312去解析一个utf-8的文档，自然有问题，因此aspx文件中的中文显示为乱码，而cs文件中指定的中文正常显示。</p>
<p>上面介绍的是asp.net中的全局编码配置，其实针对每个页面还可以进行特殊配置。例如在aspx页面中的Page指令中可以添加ResponseEncoding属性。</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb22.png" width="244" height="36" /> </p>
<p>或者我们可以在后台C#代码中利用Response对象。</p>
<p>Response对象提供了两个和字符集编码相关的属性，Response.Charset和Response.ContentEncoding。这两个有什么区别呢？ContentEncoding和web.config中配置的responseEncoding是等价的，都是既影响HTTP响应流编码又影响Content-Type响应头，而Charset影响的只是响应头Content-Type而已。 将其设置为null的话，Content-Type中就不会有charset域了。</p>
<p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/aspdotnet" title="AspDotNet" rel="tag">AspDotNet</a>, <a href="http://www.imkevinyang.com/tags/content-type" title="Content-Type" rel="tag">Content-Type</a>, <a href="http://www.imkevinyang.com/tags/http-watch" title="HTTP Watch" rel="tag">HTTP Watch</a>, <a href="http://www.imkevinyang.com/tags/response" title="Response" rel="tag">Response</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e7%ac%a6%e9%9b%86" title="字符集" rel="tag">字符集</a>, <a href="http://www.imkevinyang.com/tags/%e6%a0%b7%e5%bc%8f%e8%a1%a8" title="样式表" rel="tag">样式表</a>, <a href="http://www.imkevinyang.com/categories/techarticles/knottyproblems" title="疑难杂症" rel="tag">疑难杂症</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%96%e8%a7%a3%e7%a0%81" title="编解码" rel="tag">编解码</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/04/excel%e4%b8%ad%e4%bd%bf%e7%94%a8vba%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%bb%a7%e7%bb%adurl%e7%bc%96%e7%a0%81.html" title="Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8） (2009/04/28)">Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8）</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e3%80%90%e6%8e%a8%e8%8d%90%e3%80%91%e4%b8%a4%e6%ac%behttp%e6%b5%81%e9%87%8f%e5%88%86%e6%9e%90%e5%b7%a5%e5%85%b7%e7%9a%84%e6%af%94%e8%be%83.html" title="【推荐】两款HTTP流量分析工具的比较 (2009/11/08)">【推荐】两款HTTP流量分析工具的比较</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/06/%e5%85%b3%e4%ba%8e%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%ef%bc%8c%e4%bd%a0%e6%89%80%e9%9c%80%e8%a6%81%e7%9f%a5%e9%81%93%e7%9a%84.html" title="关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312&#8230;） (2010/06/18)">关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312&#8230;）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/02/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81%e7%9a%84%e6%95%85%e4%ba%8b%ef%bc%88ascii%ef%bc%8cansi%ef%bc%8cunicode%ef%bc%8cutf-8%e5%8c%ba%e5%88%ab%ef%bc%89.html" title="字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别） (2009/02/28)">字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e5%ad%97%e7%ac%a6%ef%bc%8c%e5%ad%97%e8%8a%82%e5%92%8c%e7%bc%96%e7%a0%81.html" title="字符，字节和编码 (2009/11/27)">字符，字节和编码</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html" title="文档字符集导致的脚本错误 (2009/08/19)">文档字符集导致的脚本错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3xaml%e4%b8%ad%e5%8c%85%e5%90%ab%e4%b8%ad%e6%96%87%e5%af%bc%e8%87%b4%e6%97%a0%e6%b3%95%e7%bc%96%e8%af%91%e7%9a%84%e9%97%ae%e9%a2%98.html" title="解决Xaml中包含中文导致无法编译的问题 (2009/09/29)">解决Xaml中包含中文导致无法编译的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html" title="详解Javascript中的Url编码/解码 (2009/08/19)">详解Javascript中的Url编码/解码</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/07/%ef%bc%88%e8%bd%ac%ef%bc%89http-%e8%af%b7%e6%b1%82%e5%a4%84%e7%90%86%e6%b5%81%e7%a8%8b.html" title="（转）Http 请求处理流程 (2009/07/20)">（转）Http 请求处理流程</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>文档字符集导致的脚本错误</title>
		<link>http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html</link>
		<comments>http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html#comments</comments>
		<pubDate>Tue, 18 Aug 2009 18:01:25 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[Web传统技术]]></category>
		<category><![CDATA[charset]]></category>
		<category><![CDATA[字符集]]></category>
		<category><![CDATA[引用外部脚本]]></category>
		<category><![CDATA[文档字符集]]></category>
		<category><![CDATA[编解码]]></category>
		<category><![CDATA[脚本]]></category>
		<category><![CDATA[脚本异常]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html</guid>
		<description><![CDATA[<p>Html页面中可以通过meta标签指定页面文档使用的字符集，这样浏览器就会根据此标签使用指定的字符集去解析文档流，而不用靠“猜”了。</p>
<pre class="csharpcode"><span class="kwrd">&#60;</span><span class="html">meta</span> <span class="attr">http-equiv</span><span class="kwrd">=&#34;Content-Type&#34;</span> <span class="attr">content</span><span class="kwrd">=&#34;text/html; charset=utf-8&#038;quo&#8230;</span></pre>]]></description>
			<content:encoded><![CDATA[<p>Html页面中可以通过meta标签指定页面文档使用的字符集，这样浏览器就会根据此标签使用指定的字符集去解析文档流，而不用靠“猜”了。</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">meta</span> <span class="attr">http-equiv</span><span class="kwrd">=&quot;Content-Type&quot;</span> <span class="attr">content</span><span class="kwrd">=&quot;text/html; charset=utf-8&quot;</span> <span class="kwrd">/&gt;</span></pre>
<p>文档字符集需要对应文件实际存储使用的字符集，否则会引发很多意料不到而又难以调试的Bug。</p>
<h2>问题1——页面显示乱码</h2>
<p>如果文档中指定的字符集和文件实际存储的字符集不一致，那么就会造成页面的非ASCII字符显示为乱码。如下面的HTML页面（文件的实际存储格式为UTF-8）：</p>
<pre class="csharpcode">

<span class="kwrd">&lt;!</span><span class="html">DOCTYPE</span> <span class="attr">html</span> <span class="attr">PUBLIC</span> <span class="kwrd">&quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span> <span class="kwrd">&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">html</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://www.w3.org/1999/xhtml&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">head</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">meta</span> <span class="attr">http-equiv</span><span class="kwrd">=&quot;Content-Type&quot;</span> <span class="attr">content</span><span class="kwrd">=&quot;text/html; charset=gb2312&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">head</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">body</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">div</span><span class="kwrd">&gt;</span>中文<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">body</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">html</span><span class="kwrd">&gt;</span>

<span class="kwrd"></span>&#160;
</pre>
<p>“中文”会变成“涓枃”。</p>
<h2>问题2——脚本执行结果不正确</h2>
<p>问题1实际上还是比较容易发现的，因为一看到乱码就可以猜到和字符集相关了。但是如果假设你在上面这个页面的基础上写了如下Javascript代码：</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">=&quot;text/javascript&quot;</span><span class="kwrd">&gt;</span>
    location.href = <span class="str">&quot;http://www.example.com/search?q=&quot;</span> + encodeURI(<span class="str">&quot;中文&quot;</span>);
<span class="kwrd">&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span></pre>
<p>你期望将用户重定向到一个特定的页面，你直接在页面中使用了Unicode字符串，并期望encodeURI会使用UTF-8对其进行Url编码。但是实际上你获得的Url却是：</p>
<p>http://www.example.com/search?q=%E6%B6%93%EE%85%9F%E6%9E%83</p>
<p>后台在解析这个Url参数的时候无论使用何种字符集进行Url解码，都无法得到“中文”这个字符串。原因和文章开头提到的乱码问题实际上是同一个问题。<strong><font color="#008000">如果你的文档字符集和页面存储字符集不一致，那么你在使用非ASCII码字符作字面量（就是直接写在代码里面的字符串）的时候就会出现意料不到的各种问题</font></strong>。</p>
<h2>问题3——脚本抛出异常</h2>
<p>在问题2举的例子中，脚本执行的时候没有抛出异常，但是其执行的结果却不是我们所期望的。在下面这个例子中，脚本的执行过程甚至会抛出莫名其妙的异常。</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">=&quot;text/javascript&quot;</span><span class="kwrd">&gt;</span>
    alert(<span class="str">&quot;对象初始化&quot;</span>);
<span class="kwrd">&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span></pre>
<p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/08/image_thumb9.png" width="565" height="93" /></p>
<p>如果你真到第8行去看那段脚本，你会发现，你死活就是看不出问题来，直到你把中文替换成英文之后你才可能会恍然大悟。</p>
<h2>问题4——引用外部脚本导致的异常</h2>
<p>现在我们把页面存储成gb2312，再运行问题3中的示例代码，这个时候就没有问题了。为了Html页面的纯洁性，我们将脚本移到一个独立的Js文件中去，并在Html中引用这个脚本文件。如下：</p>
<pre class="csharpcode">

页面index.html
<span class="kwrd">&lt;!</span><span class="html">DOCTYPE</span> <span class="attr">html</span> <span class="attr">PUBLIC</span> <span class="kwrd">&quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span> <span class="kwrd">&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">html</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://www.w3.org/1999/xhtml&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">head</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">meta</span> <span class="attr">http-equiv</span><span class="kwrd">=&quot;Content-Type&quot;</span> <span class="attr">content</span><span class="kwrd">=&quot;text/html; charset=gb2312&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">head</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">body</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">=&quot;text/javascript&quot;</span> <span class="attr">src</span><span class="kwrd">=&quot;script/test.js&quot;</span><span class="kwrd">&gt;&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">body</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">html</span><span class="kwrd">&gt;</span>

脚本script/test.js
alert(&quot;对象初始化&quot;);

&#160;
</pre>
<p>这个时候再查看index.html页面的时候，我们发现，脚本又抛出问题3的异常来了。这是为什么呢？</p>
<p>这是因为，当Html页面在引用一个外部资源的时候，使用的字符集就是当前文档字符集。因此test.js文件会被浏览器使用gb2312字符集去解析，而我在Aptana中建此文件的时候，默认的文件存储格式就是utf-8，因此还是回归到了文档字符集和存储字符集不一致的问题上来。</p>
<p>这个问题，我们可以通过在引用外部资源的时候显式指定charset属性来解决。</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">=&quot;text/javascript&quot;</span> <span class="attr">src</span><span class="kwrd">=&quot;script/test.js&quot;</span> <span class="attr">charset</span><span class="kwrd">=&quot;utf-8&quot;</span><span class="kwrd">&gt;&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span></pre>
<p>&#160;</p>
<p><font color="#ff0000"><em><strong>update:</strong></em></font></p>
<p>以上试验提到的UTF-8均指UTF-8 without BOM，即不带标记的UTF-8。IE、Chrome、Opera和Safari均能支持BOM标记，这就意味着，如果你的文件本身是以UTF-8 with BOM编码的，那么无需指定charset，浏览器也能正确解析。此优先级最高。Firefox则无法正确识别BOM标记，因此总会以页面中指定的charset或者HTTP响应中的charset来解析文档。</p>
<p align="right">&#160;</p>
<p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/charset" title="charset" rel="tag">charset</a>, <a href="http://www.imkevinyang.com/categories/techarticles/web%e4%bc%a0%e7%bb%9f%e6%8a%80%e6%9c%af" title="Web传统技术" rel="tag">Web传统技术</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e7%ac%a6%e9%9b%86" title="字符集" rel="tag">字符集</a>, <a href="http://www.imkevinyang.com/tags/%e5%bc%95%e7%94%a8%e5%a4%96%e9%83%a8%e8%84%9a%e6%9c%ac" title="引用外部脚本" rel="tag">引用外部脚本</a>, <a href="http://www.imkevinyang.com/tags/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86" title="文档字符集" rel="tag">文档字符集</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%96%e8%a7%a3%e7%a0%81" title="编解码" rel="tag">编解码</a>, <a href="http://www.imkevinyang.com/tags/%e8%84%9a%e6%9c%ac" title="脚本" rel="tag">脚本</a>, <a href="http://www.imkevinyang.com/tags/%e8%84%9a%e6%9c%ac%e5%bc%82%e5%b8%b8" title="脚本异常" rel="tag">脚本异常</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html" title="Asp.Net页面的编码问题 (2009/11/27)">Asp.Net页面的编码问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/excel%e4%b8%ad%e4%bd%bf%e7%94%a8vba%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%bb%a7%e7%bb%adurl%e7%bc%96%e7%a0%81.html" title="Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8） (2009/04/28)">Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/firebug%e5%9c%a8edithtml%e6%97%b6%e4%b8%a2%e5%a4%b1%e4%ba%8b%e4%bb%b6%e5%a4%84%e7%90%86%e5%87%bd%e6%95%b0-2.html" title="Firebug在EditHtml时丢失事件处理函数 (2009/08/19)">Firebug在EditHtml时丢失事件处理函数</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/06/%e5%85%b3%e4%ba%8e%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%ef%bc%8c%e4%bd%a0%e6%89%80%e9%9c%80%e8%a6%81%e7%9f%a5%e9%81%93%e7%9a%84.html" title="关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312&#8230;） (2010/06/18)">关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312&#8230;）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/02/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81%e7%9a%84%e6%95%85%e4%ba%8b%ef%bc%88ascii%ef%bc%8cansi%ef%bc%8cunicode%ef%bc%8cutf-8%e5%8c%ba%e5%88%ab%ef%bc%89.html" title="字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别） (2009/02/28)">字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e5%ad%97%e7%ac%a6%ef%bc%8c%e5%ad%97%e8%8a%82%e5%92%8c%e7%bc%96%e7%a0%81.html" title="字符，字节和编码 (2009/11/27)">字符，字节和编码</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/02/%e5%bd%93%e5%89%8d%e6%97%a5%e6%9c%9f110%e5%b9%b4.html" title="当前日期110年 (2010/02/12)">当前日期110年</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3xaml%e4%b8%ad%e5%8c%85%e5%90%ab%e4%b8%ad%e6%96%87%e5%af%bc%e8%87%b4%e6%97%a0%e6%b3%95%e7%bc%96%e8%af%91%e7%9a%84%e9%97%ae%e9%a2%98.html" title="解决Xaml中包含中文导致无法编译的问题 (2009/09/29)">解决Xaml中包含中文导致无法编译的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html" title="详解Javascript中的Url编码/解码 (2009/08/19)">详解Javascript中的Url编码/解码</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>详解Javascript中的Url编码/解码</title>
		<link>http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html</link>
		<comments>http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html#comments</comments>
		<pubDate>Tue, 18 Aug 2009 17:21:35 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[Web传统技术]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[RFC文档]]></category>
		<category><![CDATA[UrlEncode]]></category>
		<category><![CDATA[Url编码]]></category>
		<category><![CDATA[字符集]]></category>
		<category><![CDATA[编解码]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html</guid>
		<description><![CDATA[摘要
<p>本文主要针对URI编解码的相关问题做了介绍，对Url编码中哪些字符需要编码、为什么需要编码做了详细的说明，并对比分析了Javascript中和编解码相关的几对函数escape / unescape,encodeURI / decodeURI和encodeURIComponent / decodeURICom&#8230;</p>]]></description>
			<content:encoded><![CDATA[<h2>摘要</h2>
<p>本文主要针对URI编解码的相关问题做了介绍，对Url编码中哪些字符需要编码、为什么需要编码做了详细的说明，并对比分析了Javascript中和编解码相关的几对函数escape / unescape,encodeURI / decodeURI和encodeURIComponent / decodeURIComponent。</p>
<h2>预备知识</h2>
<p>&#160;&#160; foo://example.com:8042/over/there?name=ferret#nose&#160; <br />&#160;&#160; \_/&#160; \______________/ \________/\_________/ \__/     <br />&#160;&#160;&#160;&#160; |&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |     <br />scheme&#160;&#160;&#160;&#160; authority&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; path&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; query&#160;&#160;&#160;&#160;&#160; fragment</p>
<p>URI是统一资源标识的意思，通常我们所说的Url只是URI的一种。典型Url的格式如上面所示。下面提到的Url编码，实际上应该指的是URI编码。</p>
<h2>为什么需要Url编码</h2>
<p>通常如果一样东西需要编码，说明这样东西并不适合传输。原因多种多样，如Size过大，包含隐私数据，<strong><font color="#008000">对于Url来说，之所以要进行编码，是因为Url中有些字符会引起歧义</font></strong>。</p>
<p>例如Url参数字符串中使用key=value键值对这样的形式来传参，键值对之间以&amp;符号分隔，如/s?q=abc&amp;ie=utf-8。如果你的value字符串中包含了=或者&amp;，那么势必会造成接收Url的服务器解析错误，因此必须将引起歧义的&amp;和=符号进行转义，也就是对其进行编码。</p>
<p>又如，Url的编码格式采用的是ASCII码，而不是Unicode，这也就是说你不能在Url中包含任何非ASCII字符，例如中文。否则如果客户端浏览器和服务端浏览器支持的字符集不同的情况下，中文可能会造成问题。</p>
<p><strong><font color="#008000">Url编码的原则就是使用安全的字符（没有特殊用途或者特殊意义的可打印字符）去表示那些不安全的字符。</font></strong></p>
<h2>哪些字符需要编码</h2>
<blockquote><p>RFC3986文档规定，Url中只允许包含英文字母（a-zA-Z）、数字（0-9）、-_.~4个特殊字符以及所有保留字符。</p>
</blockquote>
<p>RFC3986文档对Url的编解码问题做出了详细的建议，指出了哪些字符需要被编码才不会引起Url语义的转变，以及对为什么这些字符需要编码做出了相应的解释。</p>
<h3>US-ASCII字符集中没有对应的可打印字符</h3>
<p>Url中只允许使用可打印字符。US-ASCII码中的10-7F字节全都表示控制字符，这些字符都不能直接出现在Url中。同时，对于80-FF字节（ISO-8859-1），由于已经超出了US-ACII定义的字节范围，因此也不可以放在Url中。</p>
<h3>保留字符</h3>
<p>Url可以划分成若干个组件，协议、主机、路径等。有一些字符（:/?#[]@）是用作分隔不同组件的。例如:冒号用于分隔协议和主机，/用于分隔主机和路径，?用于分隔路径和查询参数，等等。还有一些字符（!$&amp;'()*+,;=）用于在每个组件中起到分隔作用的，如=用于表示查询参数中的键值对，&amp;符号用于分隔查询多个键值对。当组件中的普通数据包含这些特殊字符时，需要对其进行编码。</p>
<p>RFC3986中指定了以下字符为保留字符：</p>
<table border="1" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td title="Exclamation mark">!</td>
<td title="Asterisk">*</td>
<td title="Apostrophe (mark)">'</td>
<td title="Bracket">(</td>
<td title="Bracket">)</td>
<td title="Semicolon">;</td>
<td title="Colon (punctuation)">:</td>
<td title="@">@</td>
<td title="Ampersand">&amp;</td>
<td title="Equal sign">=</td>
<td title="Plus sign">+</td>
<td title="Dollar sign">$</td>
<td title="Comma (punctuation)">,</td>
<td title="Slash (punctuation)">/</td>
<td title="Question mark">?</td>
<td title="Number sign">#</td>
<td title="Bracket">[</td>
<td title="Bracket">]</td>
</tr>
</tbody>
</table>
<h3>不安全字符</h3>
<p>还有一些字符，当他们直接放在Url中的时候，可能会引起解析程序的歧义。这些字符被视为不安全字符，原因有很多。</p>
<table border="1" cellspacing="0" cellpadding="2" width="575">
<tbody>
<tr>
<td valign="top" width="72">空格</td>
<td valign="top" width="501">Url在传输的过程，或者用户在排版的过程，或者文本处理程序在处理Url的过程，都有可能引入无关紧要的空格，或者将那些有意义的空格给去掉</td>
</tr>
<tr>
<td valign="top" width="72">引号以及&lt;&gt;</td>
<td valign="top" width="501">引号和尖括号通常用于在普通文本中起到分隔Url的作用</td>
</tr>
<tr>
<td valign="top" width="72">#</td>
<td valign="top" width="501">通常用于表示书签或者锚点</td>
</tr>
<tr>
<td valign="top" width="72">%</td>
<td valign="top" width="501">百分号本身用作对不安全字符进行编码时使用的特殊字符，因此本身需要编码</td>
</tr>
<tr>
<td valign="top" width="72">{}|\^[]`~</td>
<td valign="top" width="501">某一些网关或者传输代理会篡改这些字符</td>
</tr>
</tbody>
</table>
<p>&#160;</p>
<p><strong><font color="#008000">需要注意的是，对于Url中的合法字符，编码和不编码是等价的，但是对于上面提到的这些字符，如果不经过编码，那么它们有可能会造成Url语义的不同。因此对于Url而言，只有普通英文字符和数字，特殊字符$-_.+!*'()还有保留字符，才能出现在未经编码的Url之中</font></strong>。其他字符均需要经过编码之后才能出现在Url中。</p>
<p>但是由于历史原因，目前尚存在一些不标准的编码实现。例如对于~符号，虽然RFC3986文档规定，对于波浪符号~，不需要进行Url编码，但是还是有很多老的网关或者传输代理会</p>
<h2>如何对Url中的非法字符进行编码</h2>
<p>Url编码通常也被称为百分号编码（Url Encoding，also known as percent-encoding），是因为它的编码方式非常简单，使用%百分号加上两位的字符——0123456789ABCDEF——代表一个字节的十六进制形式。Url编码默认使用的字符集是US-ASCII。例如a在US-ASCII码中对应的字节是0x61，那么Url编码之后得到的就是%61，我们在地址栏上输入http://g.cn/search?q=%61%62%63，实际上就等同于在google上搜索abc了。又如@符号在ASCII字符集中对应的字节为0x40，经过Url编码之后得到的是%40。</p>
<p>常见字符的Url编码列表：</p>
<table border="1" cellspacing="0" cellpadding="6">
<caption>保留字符的Url编码</caption>
<tbody>
<tr>
<td>!</td>
<td>*</td>
<td>&quot;</td>
<td>'</td>
<td>(</td>
<td>)</td>
<td>;</td>
<td>:</td>
<td>@</td>
<td>&amp;</td>
</tr>
<tr>
<td><code>%21</code></td>
<td><code>%2A</code></td>
<td><code>%22</code></td>
<td><code>%27</code></td>
<td><code>%28</code></td>
<td><code>%29</code></td>
<td><code>%3B</code></td>
<td><code>%3A</code></td>
<td><code>%40</code></td>
<td><code>%26</code></td>
</tr>
<tr>
<td>=</td>
<td>+</td>
<td>$</td>
<td>,</td>
<td>/</td>
<td>?</td>
<td>%</td>
<td>#</td>
<td>[</td>
<td>]</td>
</tr>
<tr>
<td><code>%3D</code></td>
<td><code>%2B</code></td>
<td><code>%24</code></td>
<td><code>%2C</code></td>
<td><code>%2F</code></td>
<td><code>%3F</code></td>
<td><code>%25</code></td>
<td><code>%23</code></td>
<td><code>%5B</code></td>
<td><code>%5D</code></td>
</tr>
</tbody>
</table>
<p><strong><font color="#008000">对于非ASCII字符，需要使用ASCII字符集的超集进行编码得到相应的字节，然后对每个字节执行百分号编码</font></strong>。对于Unicode字符，RFC文档建议使用utf-8对其进行编码得到相应的字节，然后对每个字节执行百分号编码。如“中文”使用UTF-8字符集得到的字节为0xE4 0xB8 0xAD 0xE6 0x96 0x87，经过Url编码之后得到“%E4%B8%AD%E6%96%87”。</p>
<p><strong><font color="#008000">如果某个字节对应着ASCII字符集中的某个非保留字符，则此字节无需使用百分号表示</font></strong>。例如“Url编码”，使用UTF-8编码得到的字节是0x55 0x72 0x6C 0xE7 0xBC 0x96 0xE7 0xA0 0x81，由于前三个字节对应着ASCII中的非保留字符“Url”，因此这三个字节可以用非保留字符“Url”表示。最终的Url编码可以简化成“Url%E7%BC%96%E7%A0%81” ，当然，如果你用&quot;%55%72%6C%E7%BC%96%E7%A0%81”也是可以的。</p>
<p>由于历史的原因，有一些Url编码实现并不完全遵循这样的原则，下面会提到。</p>
<h2>Javascript中的escape,encodeURI和encodeURIComponent的区别</h2>
<p>Javascript中提供了3对函数用来对Url编码以得到合法的Url，它们分别是escape / unescape,encodeURI / decodeURI和encodeURIComponent / decodeURIComponent。由于解码和编码的过程是可逆的，因此这里只解释编码的过程。</p>
<p>这三个编码的函数——escape，encodeURI，encodeURIComponent——都是用于将不安全不合法的Url字符转换为合法的Url字符表示，它们有以下几个不同点。</p>
<h3>安全字符不同</h3>
<p>下面的表格列出了这三个函数的安全字符（即函数不会对这些字符进行编码）</p>
<table border="1" cellspacing="0" cellpadding="2" width="531">
<tbody>
<tr>
<td valign="top" width="214">&#160;</td>
<td valign="top" width="315">安全字符</td>
</tr>
<tr>
<td valign="top" width="214">escape（69个）</td>
<td valign="top" width="315">*/@+<font color="#000080">-._0-9a-zA-Z</font></td>
</tr>
<tr>
<td valign="top" width="214">encodeURI（82个）</td>
<td valign="top" width="315">!#$&amp;'()*+,/:;=?@<font color="#000080">-._~0-9a-zA-Z </font></td>
</tr>
<tr>
<td valign="top" width="214">encodeURIComponent（71个）</td>
<td valign="top" width="315">!'()*<font color="#000080">-._~0-9a-zA-Z</font></td>
</tr>
</tbody>
</table>
<h3>兼容性不同</h3>
<p>escape函数是从Javascript1.0的时候就存在了，其他两个函数是在Javascript1.5才引入的。但是由于Javascript1.5已经非常普及了，所以实际上使用encodeURI和encodeURIComponent并不会有什么兼容性问题。</p>
<h3>对Unicode字符的编码方式不同</h3>
<p>这三个函数对于ASCII字符的编码方式相同，均是使用百分号+两位十六进制字符来表示。但是对于Unicode字符，escape的编码方式是%u<i>xxxx</i>，其中的xxxx是用来表示unicode字符的4位十六进制字符。这种方式已经被W3C废弃了。但是在ECMA-262标准中仍然保留着escape的这种编码语法。<strong><font color="#008000">encodeURI和encodeURIComponent则使用UTF-8对非ASCII字符进行编码，然后再进行百分号编码</font></strong>。这是RFC推荐的。因此建议尽可能的使用这两个函数替代escape进行编码。</p>
<h3>适用场合不同</h3>
<p>encodeURI被用作对一个完整的URI进行编码，而encodeURIComponent被用作对URI的一个组件进行编码。</p>
<p>从上面提到的安全字符范围表格来看，我们会发现，encodeURIComponent编码的字符范围要比encodeURI的大。我们上面提到过，保留字符一般是用来分隔URI组件（一个URI可以被切割成多个组件，参考预备知识一节）或者子组件（如URI中查询参数的分隔符），如:号用于分隔scheme和主机，?号用于分隔主机和路径。由于encodeURI操纵的对象是一个完整的的URI，这些字符在URI中本来就有特殊用途，因此这些保留字符不会被encodeURI编码，否则意义就变了。</p>
<p>组件内部有自己的数据表示格式，但是这些数据内部不能包含有分隔组件的保留字符，否则就会导致整个URI中组件的分隔混乱。因此对于单个组件使用encodeURIComponent，需要编码的字符就更多了。</p>
<h2>表单提交</h2>
<p>当Html的表单被提交时，每个表单域都会被Url编码之后才在被发送。由于历史的原因，表单使用的Url编码实现并不符合最新的标准。例如对于空格使用的编码并不是%20，而是+号，如果表单使用的是Post方法提交的，我们可以在HTTP头中看到有一个Content-Type的header，值为application/x-www-form-urlencoded。大部分应用程序均能处理这种非标准实现的Url编码，但是在客户端Javascript中，并没有一个函数能够将+号解码成空格，只能自己写转换函数。还有，对于非ASCII字符，使用的编码字符集取决于当前文档使用的字符集。例如我们在Html头部加上</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">meta</span> <span class="attr">http-equiv</span><span class="kwrd">=&quot;Content-Type&quot;</span> <span class="attr">content</span><span class="kwrd">=&quot;text/html; charset=gb2312&quot;</span> <span class="kwrd">/&gt;</span></pre>
<p>这样浏览器就会使用gb2312去渲染此文档（注意，当HTML文档中没有设置此meta标签，则浏览器会根据当前用户喜好去自动选择字符集，用户也可以强制当前网站使用某个指定的字符集）。当提交表单时，Url编码使用的字符集就是gb2312。</p>
<h2>文档字符集会影响encodeURI吗？</h2>
<p>之前在使用Aptana（为什么专指aptana下面会提到）遇到一个很迷惑的问题，就是在使用encodeURI的时候，发现它编码得到的结果和我想的很不一样。下面是我的示例代码：</p>
<pre class="csharpcode">

<span class="kwrd">&lt;!</span><span class="html">DOCTYPE</span> <span class="attr">html</span> <span class="attr">PUBLIC</span> <span class="kwrd">&quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span> <span class="kwrd">&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">html</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://www.w3.org/1999/xhtml&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">head</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">meta</span> <span class="attr">http-equiv</span><span class="kwrd">=&quot;Content-Type&quot;</span> <span class="attr">content</span><span class="kwrd">=&quot;text/html; charset=gb2312&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">head</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">body</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">=&quot;text/javascript&quot;</span><span class="kwrd">&gt;</span>
            document.write(encodeURI(<span class="str">&quot;中文&quot;</span>));
        <span class="kwrd">&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">body</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">html</span><span class="kwrd">&gt;</span>

<span class="kwrd"></span>&#160;
</pre>
<p>运行结果输出%E6%B6%93%EE%85%9F%E6%9E%83。显然这并不是使用UTF-8字符集进行Url编码得到的结果（在Google上搜索“中文”，Url中显示的是%E4%B8%AD%E6%96%87）。</p>
<p>所以我当时就很质疑，难道encodeURI还跟页面编码有关，但是我发现，正常情况下，如果你使用gb2312进行Url编码也不会得到这个结果的才是。后来终于被我发现，原来是<strong><font color="#008000">页面文件存储使用的字符集和Meta标签中指定的字符集不一致导致的问题</font></strong>。Aptana的编辑器默认情况下使用UTF-8字符集。也就是说这个文件实际存储的时候使用的是UTF-8字符集。但是由于Meta标签中指定了gb2312，这个时候，浏览器就会按照gb2312去解析这个文档，那么自然在“中文”这个字符串这里就会出错，因为“中文”字符串用UTF-8编码过后得到的字节是0xE4 0xB8 0xAD 0xE6 0x96 0x87，这6个字节又被浏览器拿gb2312去解码，那么就会得到另外三个汉字“涓枃”（GBK中一个汉字占两个字节），这三个汉字在传入encodeURI函数之后得到的结果就是%E6%B6%93%EE%85%9F%E6%9E%83。因此，encodeURI使用的还是UTF-8，并不会受到页面字符集的影响。</p>
<h2>其他和Url编码相关的问题</h2>
<p>对于包含中文的Url的处理问题，不同浏览器有不同的表现。例如对于IE，如果你勾选了高级设置“总是以UTF-8发送Url”，那么Url中的路径部分的中文会使用UTF-8进行Url编码之后发送给服务端，而查询参数中的中文部分使用系统默认字符集进行Url编码。为了保证最大互操作性，建议所有放到Url中的组件全部显式指定某个字符集进行Url编码，而不依赖于浏览器的默认实现。</p>
<p>另外，很多HTTP监视工具或者浏览器地址栏等在显示Url的时候会自动将Url进行一次解码（使用UTF-8字符集），这就是为什么当你在Firefox中访问Google搜索中文的时候，地址栏显示的Url包含中文的缘故。但实际上发送给服务端的原始Url还是经过编码的。你可以在地址栏上使用Javascript访问location.href就可以看出来了。在研究Url编解码的时候千万别被这些假象给迷惑了。</p>
<p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/javascript" title="Javascript" rel="tag">Javascript</a>, <a href="http://www.imkevinyang.com/tags/rfc%e6%96%87%e6%a1%a3" title="RFC文档" rel="tag">RFC文档</a>, <a href="http://www.imkevinyang.com/tags/urlencode" title="UrlEncode" rel="tag">UrlEncode</a>, <a href="http://www.imkevinyang.com/tags/url%e7%bc%96%e7%a0%81" title="Url编码" rel="tag">Url编码</a>, <a href="http://www.imkevinyang.com/categories/techarticles/web%e4%bc%a0%e7%bb%9f%e6%8a%80%e6%9c%af" title="Web传统技术" rel="tag">Web传统技术</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e7%ac%a6%e9%9b%86" title="字符集" rel="tag">字符集</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%96%e8%a7%a3%e7%a0%81" title="编解码" rel="tag">编解码</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html" title="Asp.Net页面的编码问题 (2009/11/27)">Asp.Net页面的编码问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/button%e6%a0%87%e7%ad%be%e9%bc%a0%e6%a0%87%e7%82%b9%e5%87%bb%e4%ba%8b%e4%bb%b6%e7%9a%84%e8%a7%a6%e5%8f%91%e6%ba%90%e9%97%ae%e9%a2%98.html" title="Button标签鼠标点击事件的触发源问题 (2009/11/27)">Button标签鼠标点击事件的触发源问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/excel%e4%b8%ad%e4%bd%bf%e7%94%a8vba%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%bb%a7%e7%bb%adurl%e7%bc%96%e7%a0%81.html" title="Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8） (2009/04/28)">Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/ie%e4%b8%ad%e4%bd%bf%e7%94%a8windowopen%e6%89%93%e5%bc%80%e6%96%b0%e7%aa%97%e5%8f%a3%e6%97%b6%e6%97%a0%e6%b3%95%e8%8e%b7%e5%8f%96referrer%e5%af%b9%e8%b1%a1.html" title="IE中使用window.open打开新窗口时无法获取Referrer对象 (2009/03/07)">IE中使用window.open打开新窗口时无法获取Referrer对象</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/07/javajs%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f%e5%8c%b9%e9%85%8d%e5%b5%8c%e5%a5%97html%e6%a0%87%e7%ad%be.html" title="Java/Js如何使用正则表达式匹配嵌套Html标签 (2010/07/30)">Java/Js如何使用正则表达式匹配嵌套Html标签</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/07/javascript-%e4%b8%ad%e7%9a%84false%e9%9b%b6%e5%80%bcnullundefined%e5%92%8c%e7%a9%ba%e5%ad%97%e7%ac%a6%e4%b8%b2%e5%af%b9%e8%b1%a1.html" title="Javascript 中的false,零值,null,undefined和空字符串对象 (2009/07/07)">Javascript 中的false,零值,null,undefined和空字符串对象</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/javascript%e4%b8%ad%e8%8e%b7%e5%8f%96%e5%87%ba%e9%94%99%e4%bb%a3%e7%a0%81%e6%89%80%e5%9c%a8%e6%96%87%e4%bb%b6%e5%8f%8a%e8%a1%8c%e6%95%b0.html" title="Javascript中获取出错代码所在文件及行数 (2009/05/18)">Javascript中获取出错代码所在文件及行数</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/javascript%e5%ad%97%e7%ac%a6%e4%b8%b2%e5%93%88%e5%b8%8c%e5%87%bd%e6%95%b0.html" title="Javascript字符串哈希函数 (2009/04/11)">Javascript字符串哈希函数</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/06/javascript%e6%93%8d%e7%ba%b5cookie.html" title="Javascript操纵Cookie (2009/06/11)">Javascript操纵Cookie</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/05/%e4%b8%ba%e4%bb%80%e4%b9%88iis77-5%e7%9a%84gzip%e4%b8%8d%e8%b5%b7%e4%bd%9c%e7%94%a8.html" title="为什么IIS7/7.5的Gzip不起作用 (2010/05/08)">为什么IIS7/7.5的Gzip不起作用</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8）</title>
		<link>http://www.imkevinyang.com/2009/04/excel%e4%b8%ad%e4%bd%bf%e7%94%a8vba%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%bb%a7%e7%bb%adurl%e7%bc%96%e7%a0%81.html</link>
		<comments>http://www.imkevinyang.com/2009/04/excel%e4%b8%ad%e4%bd%bf%e7%94%a8vba%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%bb%a7%e7%bb%adurl%e7%bc%96%e7%a0%81.html#comments</comments>
		<pubDate>Mon, 27 Apr 2009 18:09:58 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[代码库]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[Office]]></category>
		<category><![CDATA[UrlEncode]]></category>
		<category><![CDATA[UTF-8]]></category>
		<category><![CDATA[VBA]]></category>
		<category><![CDATA[中文编码]]></category>
		<category><![CDATA[函数]]></category>
		<category><![CDATA[工具技巧]]></category>
		<category><![CDATA[技巧]]></category>
		<category><![CDATA[编解码]]></category>
		<category><![CDATA[自定义函数]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/04/excel%e4%b8%ad%e4%bd%bf%e7%94%a8vba%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%bb%a7%e7%bb%adurl%e7%bc%96%e7%a0%81.html</guid>
		<description><![CDATA[<p>Excel是个非常强大的工具，工作中因为需要用到他老完成一些表格数据的处理，所以抽空学了一点小技巧。</p>
<p>VBA是Visual Basic Application的全称，我们在Office的产品家族里面会经常看到它的身影。甚至SQL Server里头也有它的足迹，善于使用这些VBA函数或者自定义一些函数能够帮我&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>Excel是个非常强大的工具，工作中因为需要用到他老完成一些表格数据的处理，所以抽空学了一点小技巧。</p>
<p>VBA是Visual Basic Application的全称，我们在Office的产品家族里面会经常看到它的身影。甚至SQL Server里头也有它的足迹，善于使用这些VBA函数或者自定义一些函数能够帮我们实现一些看似很强大的功能而又不用花费太大的精力。</p>
<p><strong>步骤一. 打开Excel 2007中的Visual Basic编辑器</strong></p>
<p>在Excel 2007中的开发工具菜单下，点击Visual Basic，即可弹出Visual Basic的编辑界面。默认情况下，这个开发工具在功能区是不显示的，需要在Excel设置中勾选上，如下图。</p>
<p><img style="border-right-width: 0px; margin: 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/04/image-thumb5.png" width="654" height="172" /></p>
<p><img style="border-right-width: 0px; margin: 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/04/image-thumb6.png" width="408" height="202" /> </p>
<p><img style="border-right-width: 0px; margin: 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/04/image-thumb7.png" width="482" height="581" /> </p>
<p><strong>步骤二. 编写自定义函数</strong></p>
<p>选择菜单-&gt;插入-&gt;模块，就会弹出一个编辑窗口，在其中输入下面代码，即可定义一个UrlEncode的函数。</p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Function</span> UrlEncode(<span class="kwrd">ByRef</span> szString <span class="kwrd">As</span> <span class="kwrd">String</span>) <span class="kwrd">As</span> <span class="kwrd">String</span>
       <span class="kwrd">Dim</span> szChar   <span class="kwrd">As</span> <span class="kwrd">String</span>
       <span class="kwrd">Dim</span> szTemp   <span class="kwrd">As</span> <span class="kwrd">String</span>
       <span class="kwrd">Dim</span> szCode   <span class="kwrd">As</span> <span class="kwrd">String</span>
       <span class="kwrd">Dim</span> szHex    <span class="kwrd">As</span> <span class="kwrd">String</span>
       <span class="kwrd">Dim</span> szBin    <span class="kwrd">As</span> <span class="kwrd">String</span>
       <span class="kwrd">Dim</span> iCount1  <span class="kwrd">As</span> <span class="kwrd">Integer</span>
       <span class="kwrd">Dim</span> iCount2  <span class="kwrd">As</span> <span class="kwrd">Integer</span>
       <span class="kwrd">Dim</span> iStrLen1 <span class="kwrd">As</span> <span class="kwrd">Integer</span>
       <span class="kwrd">Dim</span> iStrLen2 <span class="kwrd">As</span> <span class="kwrd">Integer</span>
       <span class="kwrd">Dim</span> lResult  <span class="kwrd">As</span> <span class="kwrd">Long</span>
       <span class="kwrd">Dim</span> lAscVal  <span class="kwrd">As</span> <span class="kwrd">Long</span>
       szString = Trim$(szString)
       iStrLen1 = Len(szString)
       <span class="kwrd">For</span> iCount1 = 1 <span class="kwrd">To</span> iStrLen1
           szChar = Mid$(szString, iCount1, 1)
           lAscVal = AscW(szChar)
           <span class="kwrd">If</span> lAscVal &gt;= &amp;H0 <span class="kwrd">And</span> lAscVal &lt;= &amp;HFF <span class="kwrd">Then</span>
              <span class="kwrd">If</span> (lAscVal &gt;= &amp;H30 <span class="kwrd">And</span> lAscVal &lt;= &amp;H39) <span class="kwrd">Or</span> _
                 (lAscVal &gt;= &amp;H41 <span class="kwrd">And</span> lAscVal &lt;= &amp;H5A) <span class="kwrd">Or</span> _
                 (lAscVal &gt;= &amp;H61 <span class="kwrd">And</span> lAscVal &lt;= &amp;H7A) <span class="kwrd">Then</span>
                 szCode = szCode &amp; szChar
              <span class="kwrd">Else</span>

                 szCode = szCode &amp; <span class="str">&quot;%&quot;</span> &amp; Hex(AscW(szChar))
              <span class="kwrd">End</span> <span class="kwrd">If</span>
           <span class="kwrd">Else</span>
              szHex = Hex(AscW(szChar))
              iStrLen2 = Len(szHex)
              <span class="kwrd">For</span> iCount2 = 1 <span class="kwrd">To</span> iStrLen2
                  szChar = Mid$(szHex, iCount2, 1)
                  <span class="kwrd">Select</span> <span class="kwrd">Case</span> szChar
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;0&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;0000&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;1&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;0001&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;2&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;0010&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;3&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;0011&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;4&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;0100&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;5&quot;</span>
                        szBin = szBin &amp; <span class="str">&quot;0101&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;6&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;0110&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;7&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;0111&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;8&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;1000&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;9&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;1001&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;A&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;1010&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;B&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;1011&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;C&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;1100&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;D&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;1101&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;E&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;1110&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Is</span> = <span class="str">&quot;F&quot;</span>
                              szBin = szBin &amp; <span class="str">&quot;1111&quot;</span>
                         <span class="kwrd">Case</span> <span class="kwrd">Else</span>
                  <span class="kwrd">End</span> <span class="kwrd">Select</span>
              <span class="kwrd">Next</span> iCount2
              szTemp = <span class="str">&quot;1110&quot;</span> &amp; Left$(szBin, 4) &amp; <span class="str">&quot;10&quot;</span> &amp; Mid$(szBin, 5, 6) &amp; <span class="str">&quot;10&quot;</span> &amp; Right$(szBin, 6)
              <span class="kwrd">For</span> iCount2 = 1 <span class="kwrd">To</span> 24
                  <span class="kwrd">If</span> Mid$(szTemp, iCount2, 1) = <span class="str">&quot;1&quot;</span> <span class="kwrd">Then</span>
                     lResult = lResult + 1 * 2 ^ (24 - iCount2)
                  <span class="kwrd">Else</span>: lResult = lResult + 0 * 2 ^ (24 - iCount2)
                  <span class="kwrd">End</span> <span class="kwrd">If</span>
              <span class="kwrd">Next</span> iCount2
              szTemp = Hex(lResult)
                    szCode = szCode &amp; <span class="str">&quot;%&quot;</span> &amp; Left$(szTemp, 2) &amp; <span class="str">&quot;%&quot;</span> &amp; Mid$(szTemp, 3, 2) &amp; <span class="str">&quot;%&quot;</span> &amp; Right$(szTemp, 2)
           <span class="kwrd">End</span> <span class="kwrd">If</span>
           szBin = vbNullString
           lResult = 0
       <span class="kwrd">Next</span> iCount1
       UrlEncode = szCode
<span class="kwrd">End</span> Function</pre>
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</p>
</p>
<p><strong>步骤三：测试</strong></p>
<p>定义完之后，我们选择菜单-&gt;文件-&gt;关闭并返回Excel。然后我们就可以在Excel中测试刚才定义的这个函数了。如下图所示。</p>
<p><img style="border-right-width: 0px; margin: 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/05/image-thumb.png" width="342" height="28" /></p>
<p>注意，使用了VBA函数的excel文件需要在打开时启用宏，否则函数无效。</p>

	标签：<a href="http://www.imkevinyang.com/tags/excel" title="Excel" rel="tag">Excel</a>, <a href="http://www.imkevinyang.com/tags/office" title="Office" rel="tag">Office</a>, <a href="http://www.imkevinyang.com/tags/urlencode" title="UrlEncode" rel="tag">UrlEncode</a>, <a href="http://www.imkevinyang.com/tags/utf-8" title="UTF-8" rel="tag">UTF-8</a>, <a href="http://www.imkevinyang.com/tags/vba" title="VBA" rel="tag">VBA</a>, <a href="http://www.imkevinyang.com/tags/%e4%b8%ad%e6%96%87%e7%bc%96%e7%a0%81" title="中文编码" rel="tag">中文编码</a>, <a href="http://www.imkevinyang.com/categories/techarticles/codebase" title="代码库" rel="tag">代码库</a>, <a href="http://www.imkevinyang.com/tags/%e5%87%bd%e6%95%b0" title="函数" rel="tag">函数</a>, <a href="http://www.imkevinyang.com/tags/toolskills" title="工具技巧" rel="tag">工具技巧</a>, <a href="http://www.imkevinyang.com/tags/%e6%8a%80%e5%b7%a7" title="技巧" rel="tag">技巧</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%96%e8%a7%a3%e7%a0%81" title="编解码" rel="tag">编解码</a>, <a href="http://www.imkevinyang.com/tags/%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0" title="自定义函数" rel="tag">自定义函数</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html" title="Asp.Net页面的编码问题 (2009/11/27)">Asp.Net页面的编码问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/javascript%e5%ad%97%e7%ac%a6%e4%b8%b2%e5%93%88%e5%b8%8c%e5%87%bd%e6%95%b0.html" title="Javascript字符串哈希函数 (2009/04/11)">Javascript字符串哈希函数</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/onenote-2010-beta2-%e4%bd%93%e9%aa%8c.html" title="OneNote 2010 beta2 体验 (2009/11/25)">OneNote 2010 beta2 体验</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/php%e5%a4%84%e7%90%86bom%e6%a0%87%e8%ae%b0%e7%9a%84utf-8%e6%96%87%e4%bb%b6%e5%af%bc%e8%87%b4%e7%9a%84%e9%97%ae%e9%a2%98.html" title="PHP处理BOM标记的UTF-8文件导致的问题 (2009/05/05)">PHP处理BOM标记的UTF-8文件导致的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/02/word%e7%bc%96%e8%be%91%e5%8c%ba%e9%bc%a0%e6%a0%87%e5%a4%b1%e6%95%88.html" title="Word编辑区鼠标失效 (2009/02/28)">Word编辑区鼠标失效</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/%e4%bd%bf%e7%94%a8vba%e5%87%bd%e6%95%b0%e5%9c%a8excel%e5%8d%95%e5%85%83%e6%a0%bc%e4%b8%ad%e7%94%9f%e6%88%90%e6%8b%bc%e9%9f%b3%e7%bc%a9%e5%86%99.html" title="使用VBA函数在Excel单元格中生成拼音缩写 (2009/05/15)">使用VBA函数在Excel单元格中生成拼音缩写</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/06/%e5%85%b3%e4%ba%8e%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%ef%bc%8c%e4%bd%a0%e6%89%80%e9%9c%80%e8%a6%81%e7%9f%a5%e9%81%93%e7%9a%84.html" title="关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312&#8230;） (2010/06/18)">关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312&#8230;）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/02/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81%e7%9a%84%e6%95%85%e4%ba%8b%ef%bc%88ascii%ef%bc%8cansi%ef%bc%8cunicode%ef%bc%8cutf-8%e5%8c%ba%e5%88%ab%ef%bc%89.html" title="字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别） (2009/02/28)">字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html" title="文档字符集导致的脚本错误 (2009/08/19)">文档字符集导致的脚本错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html" title="详解Javascript中的Url编码/解码 (2009/08/19)">详解Javascript中的Url编码/解码</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/04/excel%e4%b8%ad%e4%bd%bf%e7%94%a8vba%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%bb%a7%e7%bb%adurl%e7%bc%96%e7%a0%81.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>字符编解码的故事（ASCII，ANSI，Unicode，Utf-8区别）</title>
		<link>http://www.imkevinyang.com/2009/02/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81%e7%9a%84%e6%95%85%e4%ba%8b%ef%bc%88ascii%ef%bc%8cansi%ef%bc%8cunicode%ef%bc%8cutf-8%e5%8c%ba%e5%88%ab%ef%bc%89.html</link>
		<comments>http://www.imkevinyang.com/2009/02/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81%e7%9a%84%e6%95%85%e4%ba%8b%ef%bc%88ascii%ef%bc%8cansi%ef%bc%8cunicode%ef%bc%8cutf-8%e5%8c%ba%e5%88%ab%ef%bc%89.html#comments</comments>
		<pubDate>Sun, 01 Mar 2009 00:58:15 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[好文分享]]></category>
		<category><![CDATA[ANSI]]></category>
		<category><![CDATA[ASCII]]></category>
		<category><![CDATA[Unicode]]></category>
		<category><![CDATA[UTF-8]]></category>
		<category><![CDATA[字符编解码]]></category>
		<category><![CDATA[字符集]]></category>
		<category><![CDATA[编解码]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/?p=36</guid>
		<description><![CDATA[<p><span style="color: #ff0000;">（关于字符编码的深入解释，请参见我的原创文章《<a title="关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312…）" href="http://www.imkevinyang.com/2010/06/%E5%85%B3%E4%BA%8E%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%EF%BC%8C%E4%BD%A0%E6%89%80%E9%9C%80%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84.html" target="_self">关于字符编码，你所需要知道的</a>》。）</span></p>
<p><span style="color: #ff0000;">此文为转载，有少许修订，原文出处不详。</span></p>
<p>很久很久以前，有一群人，他们决定用8个可以开合的晶体管来组合成不同的状态，以表示世界上的万物。他们认为8个开关状态作为原子单位很好，于是他们把这称为"字节"。</p>
<p>再后来，他们又做了一些可&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p><span style="color: #ff0000;">（关于字符编码的深入解释，请参见我的原创文章《<a title="关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312…）" href="http://www.imkevinyang.com/2010/06/%E5%85%B3%E4%BA%8E%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%EF%BC%8C%E4%BD%A0%E6%89%80%E9%9C%80%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84.html" target="_self">关于字符编码，你所需要知道的</a>》。）</span></p>
<p><span style="color: #ff0000;">此文为转载，有少许修订，原文出处不详。</span></p>
<p>很久很久以前，有一群人，他们决定用8个可以开合的晶体管来组合成不同的状态，以表示世界上的万物。他们认为8个开关状态作为原子单位很好，于是他们把这称为"字节"。</p>
<p>再后来，他们又做了一些可以处理这些字节的机器，机器开动了，可以用字节来组合出更多的状态，状态开始变来变去。他们看到这样是好的，于是它们就这机器称为"计算机"。</p>
<p>开始计算机只在美国用。八位的字节一共可以组合出256（2的8次方）种不同的状态。</p>
<p>他们把其中的编号从0开始的32种状态分别规定了特殊的用途，一但终端设备或者打印机遇上这些约定好的字节时，就要做一些约定的动作。遇上 00x10, 终端就换行，遇上0x07, 终端就向人们嘟嘟叫，例好遇上0x1b, 打印机就打印反白的字，对于终端就用彩色显示字母。他们看到这样很好，于是就把这些0x20（十进制32）以下的字节状态称为"控制码"。</p>
<p>他们又把所有的空格、标点符号、数字、大小写字母分别用连续的字节状态表示，一直编到了第127号，这样计算机就可以用不同字节来存储英语的 文字了。大家看到这样，都感觉很好，于是大家都把这个方案叫做 ANSI 的"Ascii"编码（American Standard Code for Information Interchange，美国信息互换标准代码）。当时世界上所有的计算机都用同样的ASCII方案来保存英文文字。</p>
<p>后来，就像建造巴比伦塔一样，世界各地的都开始使用计算机，但是很多国家用的不是英文，他们用到的许多字母在ASCII中根本没有，为了也可以在计算机中保存他们的文字，他们决定采用127号之后的空位来表示这些新的字母、符号，还加入了很多画表格时需要用下到的横线、竖线、交叉等形状，一直把序号编到了最后一个状态255。从128到255这一页的字符集被称"扩展字符集"。从此之后，贪婪的人类再没有新的状态可以用了，美帝国主义可能没有想到还有第三世界国家的人们也希望可以用到计算机吧！</p>
<p>等中国人们得到计算机时，已经没有可以利用的字节状态来表示汉字，况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民，我们不客气地把那些127号之后的奇异符号们直接取消掉，并且规定：一个小于127的字符的意义与原来相同，但两个大于127的字符连在一起时，就表示一个汉字，前面的一个字节（他称之为高字节）从0xA1用到 0xF7，后面一个字节（低字节）从0xA1到0xFE，这样我们就可以组合出大约7000多个简体汉字了。在这些编码里，我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了，连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码，这就是常说的"全角"字符，而原来在127号以下的那些就叫"半角"字符了。</p>
<p>中国人民看到这样很不错，于是就把这种汉字方案叫做"GB2312"。GB2312 是对 ASCII 的中文扩展。</p>
<p>但是中国的汉字太多了，我们很快就就发现有许多人的人名没有办法在这里打出来，特别是某些很会麻烦别人的国家领导人（如朱镕基的“镕”字）。于是我们不得不继续把 GB2312 没有用到的码位找出来老实不客气地用上。</p>
<p>后来还是不够用，于是干脆不再要求低字节一定是127号之后的内码，只要第一个字节是大于127就固定表示这是一个汉字的开始，不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准，GBK 包括了 GB2312 的所有内容，同时又增加了近20000个新的汉字（包括繁体字）和符号。</p>
<p>后来少数民族也要用电脑了，于是我们再扩展，又加了几千个新的少数民族的字，GBK 扩成了 GB18030。从此之后，中华民族的文化就可以在计算机时代中传承了。</p>
<p>中国的程序员们看到这一系列汉字编码的标准是好的，于是通称他们叫做 "DBCS"（Double Byte Charecter Set 双字节字符集）。在DBCS系列标准里，最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里，因此他们写的程序为了支持中文处理，必须要注意字串里的每一个字节的值，如果这个值是大于127的，那么就认为一个双字节字符集里的字符出现了。那时候凡是受过加持，会编程的计算机僧侣们都要每天念下面这个咒语数百遍：</p>
<p>"一个汉字算两个英文字符！一个汉字算两个英文字符……"</p>
<p>因为当时各个国家都像中国这样搞出一套自己的编码标准，结果互相之间谁也不懂谁的编码，谁也不支持别人的编码，连大陆和台湾这样只相隔了150海里，使用着同一种语言的兄弟地区，也分别采用了不同的 DBCS 编码方案——当时的中国人想让电脑显示汉字，就必须装上一个"汉字系统"，专门用来处理汉字的显示、输入的问题，但是那个台湾的愚昧封建人士写的算命程序就必须加装另一套支持 BIG5 编码的什么"倚天汉字系统"才可以用，装错了字符系统，显示就会乱了套！这怎么办？而且世界民族之林中还有那些一时用不上电脑的穷苦人民，他们的文字又怎么办？</p>
<p>真是计算机的巴比伦塔命题啊！</p>
<p>正在这时，大天使加百列及时出现了——一个叫 ISO （国际标谁化组织）的国际组织决定着手解决这个问题。他们采用的方法很简单：废了所有的地区性编码方案，重新搞一个包括了地球上所有文化、所有字母和符号的编码！他们打算叫它"Universal Multiple-Octet Coded Character Set"，简称 UCS, 俗称 "UNICODE"。</p>
<p>UNICODE 开始制订时，计算机的存储器容量极大地发展了，空间再也不成为问题了。于是 ISO 就直接规定必须用两个字节，也就是16位来统一表示所有的字符，对于ascii里的那些"半角"字符，UNICODE 包持其原编码不变，只是将其长度由原来的8位扩展为16位，而其他文化和语言的字符则全部重新统一编码。由于"半角"英文符号只需要用到低8位，所以其高 8位永远是0，因此这种大气的方案在保存英文文本时会多浪费一倍的空间。</p>
<p>这时候，从旧社会里走过来的程序员开始发现一个奇怪的现象：他们的strlen函数靠不住了，一个汉字不再是相当于两个字符了，而是一个！是 的，从 UNICODE 开始，无论是半角的英文字母，还是全角的汉字，它们都是统一的"一个字符"！同时，也都是统一的"两个字节"，请注意"字符"和"字节"两个术语的不同， "字节"是一个8位的物理存贮单元，而"字符"则是一个文化相关的符号。在UNICODE 中，一个字符就是两个字节。一个汉字算两个英文字符的时代已经快过去了。</p>
<p>从前多种字符集存在时，那些做多语言软件的公司遇上过很大麻烦，他们为了在不同的国家销售同一套软件，就不得不在区域化软件时也加持那个双字节字符集咒语，不仅要处处小心不要搞错，还要把软件中的文字在不同的字符集中转来转去。UNICODE 对于他们来说是一个很好的一揽子解决方案，于是从 Windows NT 开始，MS 趁机把它们的操作系统改了一遍，把所有的核心代码都改成了用 UNICODE 方式工作的版本，从这时开始，WINDOWS 系统终于无需要加装各种本土语言系统，就可以显示全世界上所有文化的字符了。</p>
<p>但是，UNICODE 在制订时没有考虑与任何一种现有的编码方案保持兼容，这使得 GBK 与UNICODE 在汉字的内码编排上完全是不一样的，没有一种简单的算术方法可以把文本内容从UNICODE编码和另一种编码进行转换，这种转换必须通过查表来进行。</p>
<p>如前所述，UNICODE 是用两个字节来表示为一个字符，他总共可以组合出65535不同的字符，这大概已经可以覆盖世界上所有文化的符号。如果还不够也没有关系，ISO已经准备了UCS-4方案，说简单了就是四个字节来表示一个字符，这样我们就可以组合出21亿个不同的字符出来（最高位有其他用途），这大概可以用到银河联邦成立那一天吧！</p>
<p>UNICODE 来到时，一起到来的还有计算机网络的兴起，UNICODE 如何在网络上传输也是一个必须考虑的问题，于是面向传输的众多 UTF（UCS Transfer Format）标准出现了，顾名思义，UTF8就是每次8个位传输数据，而UTF16就是每次16个位，只不过为了传输时的可靠性，从UNICODE到 UTF时并不是直接的对应，而是要过一些算法和规则来转换。</p>
<p>受到过网络编程加持的计算机僧侣们都知道，在网络里传递信息时有一个很重要的问题，就是对于数据高低位的解读方式，一些计算机是采用低位先发送的方法，例如我们PC机采用的 INTEL 架构；而另一些是采用高位先发送的方式。在网络中交换数据时，为了核对双方对于高低位的认识是否是一致的，采用了一种很简便的方法，就是在文本流的开始时向对方发送一个标志符——如果之后的文本是高位在位，那就发送"FEFF"，反之，则发送"FFFE"。不信你可以用二进制方式打开一个UTF-X格式的文件，看看开头两个字节是不是这两个字节？</p>
<p>下面是Unicode和UTF-8转换的规则</p>
<blockquote><p>Unicode</p>
<p>UTF-8</p>
<p>0000 - 007F</p>
<p>0xxxxxxx</p>
<p>0080 - 07FF</p>
<p>110xxxxx 10xxxxxx</p>
<p>0800 - FFFF</p>
<p>1110xxxx 10xxxxxx 10xxxxxx</p></blockquote>
<p>例如"汉"字的Unicode编码是6C49。6C49在0800-FFFF之间，所以要用3字节模板：1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是：0110 1100 0100 1001，将这个比特流按三字节模板的分段方法分为0110 110001 001001，依次代替模板中的x，得到：1110-0110 10-110001 10-001001，即E6 B1 89，这就是其UTF8的编码。</p>
<p>讲到这里，我们再顺便说说一个很著名的奇怪现象：当你在 windows 的记事本里新建一个文件，输入"联通"两个字之后，保存，关闭，然后再次打开，你会发现这两个字已经消失了，代之的是几个乱码！呵呵，有人说这就是联通之所以拼不过移动的原因。</p>
<p>其实这是因为GB2312编码与UTF8编码产生了编码冲撞的原因。</p>
<p>当一个软件打开一个文本时，它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件一般采用三种方式来决定文本的字符集和编码：</p>
<p>检测文件头标识，提示用户选择，根据一定的规则猜测</p>
<p>最标准的途径是检测文本最开头的几个字节，开头字节 Charset/encoding,如下表：</p>
<blockquote><p>EF BB BF UTF-8</p>
<p>FF FE UTF-16/UCS-2, little endian</p>
<p>FE FF UTF-16/UCS-2, big endian</p>
<p>FF FE 00 00 UTF-32/UCS-4, little endian.</p>
<p>00 00 FE FF UTF-32/UCS-4, big-endian.</p></blockquote>
<p>当你新建一个文本文件时，记事本的编码默认是ANSI（代表系统默认编码，在中文系统中一般是GB系列编码）, 如果你在ANSI的编码输入汉字，那么他实际就是GB系列的编码方式，在这种编码下，"联通"的内码是：</p>
<blockquote><p>c1 1100 0001</p>
<p>aa 1010 1010</p>
<p>cd 1100 1101</p>
<p>a8 1010 1000</p></blockquote>
<p>注意到了吗？第一二个字节、第三四个字节的起始部分的都是"110"和"10"，正好与UTF8规则里的两字节模板是一致的，</p>
<p>于是当我们再次打开记事本时，记事本就误认为这是一个UTF8编码的文件，让我们把第一个字节的110和第二个字节的10去掉，我们就得到了"00001 101010"，再把各位对齐，补上前导的0，就得到了"0000 0000 0110 1010"，不好意思，这是UNICODE的006A，也就是小写的字母"j"，而之后的两字节用UTF8解码之后是0368，这个字符什么也不是。这就是只有"联通"两个字的文件没有办法在记事本里正常显示的原因。</p>
<p>而如果你在"联通"之后多输入几个字，其他的字的编码不见得又恰好是110和10开始的字节，这样再次打开时，记事本就不会坚持这是一个utf8编码的文件，而会用ANSI的方式解读之，这时乱码又不出现了。</p>

	标签：<a href="http://www.imkevinyang.com/tags/ansi" title="ANSI" rel="tag">ANSI</a>, <a href="http://www.imkevinyang.com/tags/ascii" title="ASCII" rel="tag">ASCII</a>, <a href="http://www.imkevinyang.com/tags/unicode" title="Unicode" rel="tag">Unicode</a>, <a href="http://www.imkevinyang.com/tags/utf-8" title="UTF-8" rel="tag">UTF-8</a>, <a href="http://www.imkevinyang.com/categories/greatpoststoshare" title="好文分享" rel="tag">好文分享</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81" title="字符编解码" rel="tag">字符编解码</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e7%ac%a6%e9%9b%86" title="字符集" rel="tag">字符集</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%96%e8%a7%a3%e7%a0%81" title="编解码" rel="tag">编解码</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html" title="Asp.Net页面的编码问题 (2009/11/27)">Asp.Net页面的编码问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/excel%e4%b8%ad%e4%bd%bf%e7%94%a8vba%e8%87%aa%e5%ae%9a%e4%b9%89%e5%87%bd%e6%95%b0%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%bb%a7%e7%bb%adurl%e7%bc%96%e7%a0%81.html" title="Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8） (2009/04/28)">Excel中使用VBA自定义函数对字符串进行Url编码（UTF-8）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/php%e5%a4%84%e7%90%86bom%e6%a0%87%e8%ae%b0%e7%9a%84utf-8%e6%96%87%e4%bb%b6%e5%af%bc%e8%87%b4%e7%9a%84%e9%97%ae%e9%a2%98.html" title="PHP处理BOM标记的UTF-8文件导致的问题 (2009/05/05)">PHP处理BOM标记的UTF-8文件导致的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/06/%e5%85%b3%e4%ba%8e%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81%ef%bc%8c%e4%bd%a0%e6%89%80%e9%9c%80%e8%a6%81%e7%9f%a5%e9%81%93%e7%9a%84.html" title="关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312&#8230;） (2010/06/18)">关于字符编码，你所需要知道的（ASCII,Unicode,Utf-8,GB2312&#8230;）</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e5%ad%97%e7%ac%a6%ef%bc%8c%e5%ad%97%e8%8a%82%e5%92%8c%e7%bc%96%e7%a0%81.html" title="字符，字节和编码 (2009/11/27)">字符，字节和编码</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e6%96%87%e6%a1%a3%e5%ad%97%e7%ac%a6%e9%9b%86%e5%af%bc%e8%87%b4%e7%9a%84%e8%84%9a%e6%9c%ac%e9%94%99%e8%af%af.html" title="文档字符集导致的脚本错误 (2009/08/19)">文档字符集导致的脚本错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3xaml%e4%b8%ad%e5%8c%85%e5%90%ab%e4%b8%ad%e6%96%87%e5%af%bc%e8%87%b4%e6%97%a0%e6%b3%95%e7%bc%96%e8%af%91%e7%9a%84%e9%97%ae%e9%a2%98.html" title="解决Xaml中包含中文导致无法编译的问题 (2009/09/29)">解决Xaml中包含中文导致无法编译的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/%e8%af%a6%e8%a7%a3javascript%e4%b8%ad%e7%9a%84url%e7%bc%96%e8%a7%a3%e7%a0%81.html" title="详解Javascript中的Url编码/解码 (2009/08/19)">详解Javascript中的Url编码/解码</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/02/%e5%ad%97%e7%ac%a6%e7%bc%96%e8%a7%a3%e7%a0%81%e7%9a%84%e6%95%85%e4%ba%8b%ef%bc%88ascii%ef%bc%8cansi%ef%bc%8cunicode%ef%bc%8cutf-8%e5%8c%ba%e5%88%ab%ef%bc%89.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using disk: enhanced

Served from: www.imkevinyang.com @ 2012-02-08 19:34:21 -->
