<?xml version="1.0" encoding="GBK" ?>
<rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dcterms="http://purl.org/dc/terms/">
 <channel>
  	  <title><![CDATA[工欲善其事，必先利其器]]></title>
	  <link>http://lklkdawei.blog.163.com</link>
	  <description><![CDATA[努力做一个好人 不是很开朗,不是很快乐]]></description>
	  <language>zh-CN</language>
	  <pubDate>Mon, 6 Oct 2008 08:59:26 +0800</pubDate>
	  <lastBuildDate>Mon, 6 Oct 2008 08:59:26 +0800</lastBuildDate>
	  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
	  <generator><![CDATA[NetEase Space]]></generator>
	  <managingEditor><![CDATA[lklkdawei]]></managingEditor>
	  <webMaster><![CDATA[lklkdawei]]></webMaster>
		  <ttl>120</ttl>
	  <image>
	  	<title><![CDATA[工欲善其事，必先利其器]]></title>
	  	<url>http://ava.blog.163.com/photo/zlTwqG-lZ9I7t5IKhVtrBA==/169729410956794625.jpg</url>
	  	<link>http://lklkdawei.blog.163.com</link>
	  </image>
  <item>
  	<title><![CDATA[今天，我种下了一朵小红花]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/3257410920089685834595</link>
    <description><![CDATA[<div>今天，我在网易花园里为Lisa 露露种了一朵小红花。希望它给我们带来幸福和爱，直到永远...
<div style="text-align: center;">
	<embed src="http://iou.163.com/loveGarden/swf/card.swf" flashVars="url=http://iou.163.com/flowerInBlog/32574109/2003760/" quality="high" bgcolor="#ffffff" width="600" height="400" wmode="transparent"  align="middle"  allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</div>
<div style="text-align: center;">
	<img style="width: 184px; height: 78px;margin-right:10px;" src="http://img.blog.163.com/photo/6gu9J6u0Gyp_5KXSVa3I_w==/1420604207459534393.jpg">
	<a href="http://iou.163.com/?centerId=2003760" target="_blank" style="top: -18px; ; font-size: 12px;">去花园广场看花&gt;&gt;</a>
</div></div>]]></description>
	    <author><![CDATA[lklkdawei]]></author>
	    <comments>http://lklkdawei.blog.163.com/blog/static/3257410920089685834595</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://lklkdawei.blog.163.com/blog/static/3257410920089685834595</guid>
    <pubDate>Mon, 6 Oct 2008 08:58:34 +0800</pubDate>
    <dcterms:modified>2008-10-06T08:58:34+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[今天，我种下了一朵小红花]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/32574109200882894240408</link>
    <description><![CDATA[<div>今天，我在网易花园里为Julie种了一朵小红花。希望它给我们带来幸福和爱，直到永远...
<div style="text-align: center;">
	<embed src="http://iou.163.com/loveGarden/swf/card.swf" flashVars="url=http://iou.163.com/flowerInBlog/32574109/1900518/" quality="high" bgcolor="#ffffff" width="600" height="400" wmode="transparent"  align="middle"  allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</div>
<div style="text-align: center;">
	<img style="width: 184px; height: 78px;margin-right:10px;" src="http://img.blog.163.com/photo/6gu9J6u0Gyp_5KXSVa3I_w==/1420604207459534393.jpg">
	<a href="http://iou.163.com/?centerId=1900518" target="_blank" style="top: -18px; ; font-size: 12px;">去花园广场看花&gt;&gt;</a>
</div></div>]]></description>
	    <author><![CDATA[lklkdawei]]></author>
	    <comments>http://lklkdawei.blog.163.com/blog/static/32574109200882894240408</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://lklkdawei.blog.163.com/blog/static/32574109200882894240408</guid>
    <pubDate>Sun, 28 Sep 2008 09:42:40 +0800</pubDate>
    <dcterms:modified>2008-09-28T09:42:40+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[SQL中的left outer join,inner join,right outer join用法]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/3257410920088271054322</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">使用关系代数合并数据</P>
<P style="TEXT-INDENT: 2em">1 关系代数</P>
<P style="TEXT-INDENT: 2em">合并数据集合的理论基础是关系代数，它是由E.F.Codd于1970年提出的。</P>
<P style="TEXT-INDENT: 2em">在关系代数的形式化语言中：</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用表、或者数据集合表示关系或者实体。</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用行表示元组。</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用列表示属性。</P>
<P style="TEXT-INDENT: 2em">关系代数包含以下8个关系运算符</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 选取――返回满足指定条件的行。</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 投影――从数据集合中返回指定的列。</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 笛卡尔积――是关系的乘法，它将分别来自两个数据集合中的行以所有可能的方式进行组合。</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 并――关系的加法和减法，它可以在行的方向上合并两个表中的数据，就像把一个表垒在另一个表之上一样。</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 交――返回两个数据集合所共有的行。</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 差――返回只属于一个数据集合的行。</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 连接――在水平方向上合并两个表，其方法是：将两个表中在共同数据项上相互匹配的那些行合并起来。</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 除――返回两个数据集之间的精确匹配。</P>
<P style="TEXT-INDENT: 2em">此外，作为一种实现现代关系代数运算的方法，SQL还提供了：</P>
<P style="TEXT-INDENT: 2em">?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 子查询――类似于连接，但更灵活；在外部查询中，方式可以使用表达式、列表或者数据集合的地方都可以使用子查询的结果。</P>
<P style="TEXT-INDENT: 2em">本章将主要讲述多种类型的连接、简单的和相关的子查询、几种类型的并、关系除以及其他的内容。</P>
<P style="TEXT-INDENT: 2em">2 使用连接</P>
<P style="TEXT-INDENT: 2em">2.1 连接类型</P>
<P style="TEXT-INDENT: 2em">在关系代数中，连接运算是由一个笛卡尔积运算和一个选取运算构成的。首先用笛卡尔积完成对两个数据集合的乘运算，然后对生成的结果集合进行选取运算，确保只把分别来自两个数据集合并且具有重叠部分的行合并在一起。连接的全部意义在于在水平方向上合并两个数据集合（通常是表），并产生一个新的结果集合，其方法是将一个数据源中的行于另一个数据源中和它匹配的行组合成一个新元组。</P>
<P style="TEXT-INDENT: 2em">SQL提供了多种类型的连接方式，它们之间的区别在于：从相互交叠的不同数据集合中选择用于连接的行时所采用的方法不同。</P>
<P style="TEXT-INDENT: 2em">连接类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 定义</P>
<P style="TEXT-INDENT: 2em">内连接&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 只连接匹配的行</P>
<P style="TEXT-INDENT: 2em">左外连接&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 包含左边表的全部行（不管右边的表中是否存在与它们匹配的行），以及右边表中全部匹配的行</P>
<P style="TEXT-INDENT: 2em">右外连接&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 包含右边表的全部行（不管左边的表中是否存在与它们匹配的行），以及左边表中全部匹配的行</P>
<P style="TEXT-INDENT: 2em">全外连接&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 包含左、右两个表的全部行，不管另外一边的表中是否存在与它们匹配的行。</P>
<P style="TEXT-INDENT: 2em">(H)(theta)连接&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用等值以外的条件来匹配左、右两个表中的行</P>
<P style="TEXT-INDENT: 2em">交叉连接&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 生成笛卡尔积－它不使用任何匹配或者选取条件，而是直接将一个数据源中的每个行与另一个数据源的每个行都一一匹配</P>
<P style="TEXT-INDENT: 2em">在INFORMIX中连接表的查询</P>
<P style="TEXT-INDENT: 2em">如果FROM子句指定了多于一个表引用，则查询会连接来自多个表的行。连接条件指定各列之间（每个表至少一列）进行连接的关系。因为正在比较连接条件中的列，所以它们必须具有一致的数据类型。</P>
<P style="TEXT-INDENT: 2em">SELECT语句的FROM子句可以指定以下几种类型的连接</P>
<P style="TEXT-INDENT: 2em">FROM子句关键字&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 相应的结果集</P>
<P style="TEXT-INDENT: 2em">CROSS JOIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 笛卡尔乘积（所有可能的行对）</P>
<P style="TEXT-INDENT: 2em">INNER JOIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 仅对满足连接条件的CROSS中的列</P>
<P style="TEXT-INDENT: 2em">LEFT OUTER JOIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个表满足条件的行，和另一个表的所有行</P>
<P style="TEXT-INDENT: 2em">RIGHT OUTER JOIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 与LEFT相同，但两个表的角色互换</P>
<P style="TEXT-INDENT: 2em">FULL OUTER JOIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LEFT OUTER 和 RIGHT OUTER中所有行的超集</P>
<P style="TEXT-INDENT: 2em">2.2 内连接（Inner Join）</P>
<P style="TEXT-INDENT: 2em">内连接是最常见的一种连接，它页被称为普通连接，而E.FCodd最早称之为自然连接。</P>
<P style="TEXT-INDENT: 2em">下面是ANSI SQL－92标准</P>
<P style="TEXT-INDENT: 2em">select * </P>
<P style="TEXT-INDENT: 2em">from&nbsp;&nbsp;&nbsp; t_institution i </P>
<P style="TEXT-INDENT: 2em">inner join t_teller t </P>
<P style="TEXT-INDENT: 2em">on i.inst_no = t.inst_no</P>
<P style="TEXT-INDENT: 2em">where i.inst_no = "5801"</P>
<P style="TEXT-INDENT: 2em">其中inner可以省略。</P>
<P style="TEXT-INDENT: 2em">等价于早期的连接语法</P>
<P style="TEXT-INDENT: 2em">select * </P>
<P style="TEXT-INDENT: 2em">from t_institution i, t_teller t </P>
<P style="TEXT-INDENT: 2em">where i.inst_no = t.inst_no</P>
<P style="TEXT-INDENT: 2em">and i.inst_no = "5801"</P>
<P style="TEXT-INDENT: 2em">2.3 外连接</P>
<P style="TEXT-INDENT: 2em">2.3.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 左外连接(Left Outer Jion)</P>
<P style="TEXT-INDENT: 2em">select * </P>
<P style="TEXT-INDENT: 2em">from&nbsp;&nbsp;&nbsp; t_institution i </P>
<P style="TEXT-INDENT: 2em">left outer join t_teller t </P>
<P style="TEXT-INDENT: 2em">on i.inst_no = t.inst_no</P>
<P style="TEXT-INDENT: 2em">其中outer可以省略。</P>
<P style="TEXT-INDENT: 2em">2.3.2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 右外连接(Rigt Outer Jion)</P>
<P style="TEXT-INDENT: 2em">select * </P>
<P style="TEXT-INDENT: 2em">from&nbsp;&nbsp;&nbsp; t_institution i </P>
<P style="TEXT-INDENT: 2em">right outer join t_teller t </P>
<P style="TEXT-INDENT: 2em">on i.inst_no = t.inst_no</P>
<P style="TEXT-INDENT: 2em">2.3.3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 全外连接(Full Outer)</P>
<P style="TEXT-INDENT: 2em">全外连接返回参与连接的两个数据集合中的全部数据，无论它们是否具有与之相匹配的行。在功能上，它等价于对这两个数据集合分别进行左外连接和右外连接，然后再使用消去重复行的并操作将上述两个结果集合并为一个结果集。</P>
<P style="TEXT-INDENT: 2em">在现实生活中，参照完整性约束可以减少对于全外连接的使用，一般情况下左外连接就足够了。在数据库中没有利用清晰、规范的约束来防范错误数据情况下，全外连接就变得非常有用了，你可以使用它来清理数据库中的数据。</P>
<P style="TEXT-INDENT: 2em">select * </P>
<P style="TEXT-INDENT: 2em">from&nbsp;&nbsp;&nbsp; t_institution i </P>
<P style="TEXT-INDENT: 2em">full outer join t_teller t </P>
<P style="TEXT-INDENT: 2em">on i.inst_no = t.inst_no</P>
<P style="TEXT-INDENT: 2em">2.3.4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 外连接与条件配合使用</P>
<P style="TEXT-INDENT: 2em">当在内连接查询中加入条件是，无论是将它加入到join子句，还是加入到where子句，其效果是完全一样的，但对于外连接情况就不同了。当把条件加入到join子句时，SQL Server、Informix会返回外连接表的全部行，然后使用指定的条件返回第二个表的行。如果将条件放到where子句中，SQL Server将会首先进行连接操作，然后使用where子句对连接后的行进行筛选。下面的两个查询展示了条件放置位子对执行结果的影响：</P>
<P style="TEXT-INDENT: 2em">条件在join子句</P>
<P style="TEXT-INDENT: 2em">select * </P>
<P style="TEXT-INDENT: 2em">from&nbsp;&nbsp;&nbsp; t_institution i </P>
<P style="TEXT-INDENT: 2em">left outer join t_teller t </P>
<P style="TEXT-INDENT: 2em">on i.inst_no = t.inst_no</P>
<P style="TEXT-INDENT: 2em">and i.inst_no = “5801”</P>
<P style="TEXT-INDENT: 2em">结果是：</P>
<P style="TEXT-INDENT: 2em">inst_no&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inst_name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inst_no&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; teller_no&nbsp;&nbsp;&nbsp; teller_name</P>
<P style="TEXT-INDENT: 2em">5801&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 天河区&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5801&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tom</P>
<P style="TEXT-INDENT: 2em">5801&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 天河区&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5801&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0002&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; david</P>
<P style="TEXT-INDENT: 2em">5802&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 越秀区</P>
<P style="TEXT-INDENT: 2em">5803&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 白云区</P>
<P style="TEXT-INDENT: 2em">条件在where子句</P>
<P style="TEXT-INDENT: 2em">select * </P>
<P style="TEXT-INDENT: 2em">from&nbsp;&nbsp;&nbsp; t_institution i </P>
<P style="TEXT-INDENT: 2em">left outer join t_teller t </P>
<P style="TEXT-INDENT: 2em">on i.inst_no = t.inst_no</P>
<P style="TEXT-INDENT: 2em">where i.inst_no = “5801”</P>
<P style="TEXT-INDENT: 2em">结果是：</P>
<P style="TEXT-INDENT: 2em">inst_no&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inst_name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inst_no&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; teller_no&nbsp;&nbsp;&nbsp; teller_name</P>
<P style="TEXT-INDENT: 2em">5801&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 天河区&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5801&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tom</P>
<P style="TEXT-INDENT: 2em">5801&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 天河区&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5801&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0002&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; david</P>
<P style="TEXT-INDENT: 2em">2.4 自身连接</P>
<P style="TEXT-INDENT: 2em">自身连接是指同一个表自己与自己进行连接。这种一元连接通常用于从自反关系（也称作递归关系）中抽取数据。例如人力资源数据库中雇员与老板的关系。</P>
<P style="TEXT-INDENT: 2em">下面例子是在机构表中查找本机构和上级机构的信息。</P>
<P style="TEXT-INDENT: 2em">select s.inst_no superior_inst, s.inst_name sup_inst_name, i.inst_no, i.inst_name</P>
<P style="TEXT-INDENT: 2em">from t_institution i</P>
<P style="TEXT-INDENT: 2em">join t_institution s</P>
<P style="TEXT-INDENT: 2em">on i.superior_inst = s.inst_no</P>
<P style="TEXT-INDENT: 2em">结果是：</P>
<P style="TEXT-INDENT: 2em">superior_inst sup_inst_name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inst_no&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inst_name</P>
<P style="TEXT-INDENT: 2em">800&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 广州市&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5801&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 天河区</P>
<P style="TEXT-INDENT: 2em">800&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 广州市&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5802&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 越秀区</P>
<P style="TEXT-INDENT: 2em">800&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 广州市&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5803&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 白云区</P>
<P style="TEXT-INDENT: 2em">2.5 交叉(无限制) 连接</P>
<P style="TEXT-INDENT: 2em">交叉连接用于对两个源表进行纯关系代数的乘运算。它不使用连接条件来限制结果集合，而是将分别来自两个数据源中的行以所有可能的方式进行组合。数据集合中一的每个行都要与数据集合二中的每一个行分别组成一个新的行。例如，如果第一个数据源中有5个行，而第二个数据源中有4个行，那么在它们之间进行交叉连接就会产生20个行。人们将这种类型的结果集称为笛卡尔乘积。</P>
<P style="TEXT-INDENT: 2em">大多数交叉连接都是由于错误操作而造成的；但是它们却非常适合向数据库中填充例子数据，或者预先创建一些空行以便为程序执行期间所要填充的数据保留空间。</P>
<P style="TEXT-INDENT: 2em">select *</P>
<P style="TEXT-INDENT: 2em">from&nbsp;&nbsp;&nbsp; t_institution i </P>
<P style="TEXT-INDENT: 2em">cross join t_teller t</P>
<P style="TEXT-INDENT: 2em">在交叉连接中没有on条件子句</P>
<P style="TEXT-INDENT: 2em"></P></div>]]></description>
	    <author><![CDATA[lklkdawei]]></author>
	    <comments>http://lklkdawei.blog.163.com/blog/static/3257410920088271054322</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://lklkdawei.blog.163.com/blog/static/3257410920088271054322</guid>
    <pubDate>Sat, 27 Sep 2008 10:05:04 +0800</pubDate>
    <dcterms:modified>2008-09-27T10:05:04+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[一种通用的输入校验方法和气球泡提示的实现【转】]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/3257410920088249251685</link>
    <description><![CDATA[<div><P>键盘用户界面模块使用说明</P>
<P>&nbsp;</P>
<P>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 键盘用户界面模块介绍</P>
<P>健盘用户界面模块是一个处理WEB编程中常用的针对健盘用户界面交互功能的通用javascript模块，主要功能有输入强制性验证，回车切换输入域，快捷键执行功能按钮或切换输入域，输入域活动提示，友好提示信息显示等主要功能。</P>
<P>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 模块所处位置与调用说明</P>
<P>该模块处在：defaultroot/platform/js/UiKey.js</P>
<P>调用方式为：</P>
<P>&lt;script src="/defaultroot/platform/js/UiKey.js "&gt;&lt;/script&gt;</P>
<P>该名必须必须放在&lt;/body&gt;标签的前一句<BR>提交前验证:<BR>function SubmitForm(form)<BR>{<BR>&nbsp;&nbsp;&nbsp; if(!checkFormInput(form)) return false;<BR>&nbsp;&nbsp;&nbsp; form.submit();<BR>}</P>
<P><BR>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 功能介绍与实现说明</P>
<P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输入强制性验证</P>
<P>比如有如下输入框，该输入框只能输入数字字符，用如下方式声明</P>
<P>&lt;input type="text" name="credNumber" minlength="5" maxlength="16" charset="Number" datatype="Cardnumber" nullable="true" size="40" tabindex="9" value=""&gt;</P>
<P>charset=”Number”属性就能定义该输入框所能输入的字符类型</P>
<P>注意：其实在实现上，该例子模块会自动调用isNumber(handle,keyCode)来进行验证，系统默认提供了几个验证函数，当需要其它验证方式时，可以自己定义相关的验证函数来进行验证</P>
<P>比如，我有一个输入框，需要输入IP地址，则可以如下声明：</P>
<P>Number:&lt;input type="text" name="credNumber" minlength="5" maxlength="16" charset="Ip" datatype="Cardnumber" nullable="true" size="40" tabindex="9" value=""&gt;</P>
<P>然后实现isIP(handle,keyCode)函数即可纳入统一的验证框架之下</P>
<P>本验证只实现输入过程中的验证，至于输入完后格式正确性的验证由如下实现:<BR>&lt;input type="text" name="credNumber" minlength="5" maxlength="16" charset="Number" datatype="Cardnumber" nullable="true" size="40" tabindex="9" value=""&gt;<BR>datetype=”Cardnumber”属性就能定义该输入框所需要输入的数据类型</P>
<P>注意：其实在实现上，该例子模块会自动调用isCardnumber(handle)来进行验证，系统默认提供了几个验证函数，当需要其它验证方式时，可以自己定义相关的验证函数来进行验证</P>
<P>比如，我有一个输入框，需要输入移动电话地址，则可以如下声明：</P>
<P>Number:&lt;input type="text" name="Phone" minlength="5" maxlength="16" charset="Number" datatype="Mobile" nullable="true" size="40" tabindex="9" value=""&gt;</P>
<P>然后实现isMobile(handle)函数(其实已经实现)即可纳入统一的验证框架之下</P>
<P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 回车切换输入域</P>
<P>一般情况下，用户在有多输入域的时候都希望在敲下回车后切换到下一输入域，本模块以统一的方式实现了，并且能够识别普通输入域与按钮（包括图片按钮，注意，只要图片有onclick事件，则认为是按钮），在按钮上敲回车将会执行该按钮功能。</P>
<P>要实现该功能，只要定义输入的域tabindex属性即可，如下所示</P>
<P>Number:&lt;input type="text" id="test1" charset="Number" tabindex=1&gt;</P>
<P>&lt;p&gt;</P>
<P>Visible:&lt;input type="text" id="test5" charset="Visible" tabindex=2&gt;</P>
<P>&lt;p&gt;</P>
<P>&lt;IMG SRC="http://www.QQread.com/Java/D:/eclipse/workspace/PFE/defaultroot/style/tempstylefolder/images/3_ico_3.gif" border="5" WIDTH="48" HEIGHT="40" BORDER="0" charset="ddd" AccessKey="Z" onclick="alert('image1 click');" tabindex=3 &gt;</P>
<P>&lt;INPUT TYPE="button" accessKey="5" value="(1)" onclick="alert('button click');" tabindex=4&gt;</P>
<P>如果一路按回车键，则焦点会按tabindex的顺序往下跳，在图片按钮与普通按钮上则不回跳，直接执行onclcik事件</P>
<P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 快捷键功能</P>
<P>本模块能够定义各页面元素的快捷键，包括图片按钮，普通按钮，各输入域，其定义方式为设置对象的accessKey属性，如下所示</P>
<P>Number:&lt;input type="text" id="test1" charset="Number" tabindex=1 accessKey=”1”&gt;</P>
<P>&lt;p&gt;</P>
<P>Visible:&lt;input type="text" id="test5" charset="Visible" tabindex=2 accessKey=”2”&gt;</P>
<P>&lt;p&gt;</P>
<P>&lt;IMG SRC="http://www.qqread.com/java/D:/eclipse/workspace/PFE/defaultroot/style/tempstylefolder/images/3_ico_3.gif" border="5" WIDTH="48" HEIGHT="40" BORDER="0" charset="ddd" accessKey="Z" onclick="alert('image1 click');" tabindex=3 &gt;</P>
<P>&lt;INPUT TYPE="button" accessKey="5" value="(1)" onclick="alert('button click');" tabindex=4&gt;</P>
<P>当按下ALT+1或者ALT+2后，第一个输入框和第二个输入框会得到焦点</P>
<P>当按下ALT+z或者ALT+5时，图片的onclick事件与按钮的onclick事件会执行</P>
<P>本模块模认定义home键将焦点落在第一个输入域上，end键将焦点落在最后一个输入区域上</P>
<P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输入域活动提示</P>
<P>本模块会自动完成，当某一个输入域获得焦点时，会加重显示该输入域，当文本输入域</P>
<P>获得焦点时会自动选择其所有文本</P>
<P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 友好提示信息</P>
<P>信息提示一直采用alert的方式，这种方式不友好，用户要点击确定后才能继续进行下去，本模块提供汽球型友好提示方式，调用方式如下：</P>
<P>showTip(handle,”必须输入用户名!”);</P>
<P>handle为输入框的句柄<BR>注意，为了显示对应的汽泡提示，还有几个对应的小图片，可以自己帮，也可以找我要!<BR>如果要用在struts 标签库中也是可以的，不过要改一下标签库，如果有需要的也可以直接联系我!<BR>QQ:6045306<BR>EMAIL:huijunzi@21cn.com </P>
<P></P>
<P>//以下为代码<BR>/*<BR>说明:文本框输入格式验证与气球提示实现,图片快捷键功能实现<BR>版权:Copyright (C) 2004 Cyril<BR>作者:Cyril<BR>调用方式:<BR>&lt;script src="UIKey.js"&gt;&lt;/script&gt;<BR>必须放在&lt;/body&gt;标签的前一句<BR>*/<BR>//初始化调用<BR>//先提示画层<BR>drawTipDiv();<BR>//输出样式表<BR>drawStyle();<BR>//装载侦听器<BR>addListener();<BR>//容错处理<BR>function killErrors() {<BR>return true;<BR>}<BR>//window.onerror = killErrors;<BR>//================以下为系统函数区=======================//<BR>//全局变量区<BR>var oldInputStyle;<BR>var oldImgStyle;<BR>var firstInput;<BR>var endInput;<BR>var timer;</P>
<P>//显示提示信息层<BR>function showTip(handle,msg) {<BR>&nbsp;&nbsp;&nbsp; //alert(handle.type);<BR>&nbsp;&nbsp;&nbsp; handle.focus();&nbsp;&nbsp;&nbsp; <BR>&nbsp;var pos = getPosition(handle);<BR>&nbsp;var t = pos.top;<BR>&nbsp;var l = pos.left;<BR>&nbsp;document.all.checkMsgDiv.style.left=l-10+getTextLength(handle);<BR>&nbsp;&nbsp;&nbsp; document.all.checkMsgDiv.style.top=t+handle.clientHeight;<BR>&nbsp;&nbsp;&nbsp; document.all.checkMsgTd.innerHTML=msg;<BR>&nbsp;document.all.checkMsgDiv.style.visibility = 'visible';<BR>&nbsp;//隐藏被层遮挡的选择框<BR>&nbsp;HideOverSels("checkMsgDiv");<BR>&nbsp;timer = setTimeout("hideTip();", 2500);<BR>&nbsp;return false;<BR>}</P>
<P>//表单校验函数<BR>function checkFormInput(handle) {<BR>&nbsp; var controlList = handle.elements;<BR>&nbsp; var controlObj;<BR>&nbsp; for(var i=0;i&lt;controlList.length;i++) {<BR>&nbsp;&nbsp; //如果是text控件,需要进行数据校验<BR>&nbsp;&nbsp; controlObj = controlList[i];<BR>&nbsp;&nbsp; if(isControlVisible(controlObj)) {<BR>&nbsp;&nbsp;&nbsp; if(controlObj.type=='text' controlObj.type=='passWord') {<BR>&nbsp;&nbsp;&nbsp;&nbsp; //如果不充许为空,则需要判断<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((controlObj.nullable=="false") &amp;&amp; (controlObj.value=="")) {<BR>hideTip();<BR><BR>&nbsp;&nbsp;&nbsp; showTip(controlObj,"此输入域不能为空!");<BR>&nbsp;&nbsp;&nbsp; return false;<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; //如果有最小长度限制,则需要判断<BR>&nbsp;&nbsp;&nbsp;&nbsp; if(controlObj.value!='' &amp;&amp; controlObj.minlength!=null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp; var realLength = controlObj.value.length;<BR>&nbsp;&nbsp;&nbsp;&nbsp; var needLength = controlObj.minlength;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(realLength&lt;needLength) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hideTip();<BR>&nbsp;&nbsp;&nbsp;&nbsp; showTip(controlObj,"此输入域至少需要"+needLength+"个字符!");<BR>&nbsp;&nbsp;&nbsp;&nbsp; return false;<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; //判断数据的类型，调用相关的数据校验函数<BR>&nbsp;&nbsp;&nbsp;&nbsp; if(controlObj.datatype!=null &amp;&amp; controlObj.value!='') {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var typeStr = controlObj.datatype.toLowerCase();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var firstChar = typeStr.substring(0,1);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; firstChar = firstChar.toUpperCase();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeStr = firstChar+typeStr.substring(1,typeStr.length);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var tempMsg=eval("is"+typeStr+"(controlObj);");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tempMsg!=true)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hideTip();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; showTip(controlObj,"此输入域"+tempMsg);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>&nbsp; }<BR>&nbsp; return true;<BR>} </P>
<P></P>
<P>//系统调用接口<BR>function handleKeyDown(event) {<BR><BR>&nbsp; //有按键就要关闭tip层<BR>&nbsp; hideTip();<BR>&nbsp; //home键与end键定位第一个与最后一个输入域上<BR>&nbsp; if(event.srcElement.type!="text" &amp;&amp; event.srcElement.type!="textarea" &amp;&amp; event.keyCode==36) {<BR>&nbsp;&nbsp; if(firstInput) firstInput.focus();<BR>&nbsp; }<BR>&nbsp; if(event.srcElement.type!="text" &amp;&amp; event.srcElement.type!="textarea" &amp;&amp; event.keyCode==35) {<BR>&nbsp;&nbsp; if(endInput) endInput.focus();<BR>&nbsp; }<BR>&nbsp; //处理回车切换焦点以及按钮与图片执行功能<BR>&nbsp; if(event.keyCode==13 &amp;&amp; event.srcElement.type!="button" &amp;&amp; event.srcElement.type!="reset" &amp;&amp; event.srcElement.type!="" &amp;&amp; event.srcElement.type!="textarea") {<BR>&nbsp;&nbsp; if(event.srcElement.src) {<BR>&nbsp;&nbsp;&nbsp; if(event.srcElement.onclick) {<BR>&nbsp;&nbsp;&nbsp; event.srcElement.fireEvent("onclick")<BR>&nbsp;&nbsp;&nbsp; return;<BR>&nbsp;&nbsp;&nbsp; } else {<BR>&nbsp;&nbsp;&nbsp; event.keyCode=9;<BR>&nbsp;&nbsp;&nbsp; return;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; } else {<BR>&nbsp;&nbsp;&nbsp; event.keyCode=9;<BR>&nbsp;&nbsp;&nbsp; return;<BR>&nbsp;&nbsp; }<BR>&nbsp; }</P>
<P>&nbsp; //处理图片按钮的快捷键<BR>&nbsp; if(event.altKey &amp;&amp; event.keyCode!=18) {<BR>&nbsp;&nbsp; var shortKey=String.fromCharCode(event.keyCode);<BR>&nbsp;&nbsp; var quickKey = "";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(var i=0;i&lt;document.images.length;i++) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quickKey = document.images[i].accessKey;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quickKey = quickKey.toUpperCase();<BR>&nbsp;&nbsp;&nbsp; if(quickKey==shortKey) {<BR>&nbsp;if(document.images[i].onclick) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; document.images[i].fireEvent("onclick");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<BR>&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>&nbsp;&nbsp; //处理输入对象快捷方式<BR>&nbsp;&nbsp; var inputList = document.body.getElementsByTagName("INPUT");<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(var i=0;i&lt;inputList.length;i++) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quickKey = inputList[i].accessKey;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quickKey = quickKey.toUpperCase();<BR>&nbsp; if(quickKey==shortKey) {<BR>&nbsp;&nbsp;&nbsp; inputList[i].focus();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<BR>&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; return;<BR>&nbsp; }<BR>&nbsp; if(event.srcElement.type=='text' &amp;&amp; event.srcElement.charset!=null) {<BR>&nbsp;&nbsp;&nbsp; //alert(event.srcElement.charset);<BR>&nbsp;if((event.keyCode&gt;48 &amp;&amp; event.keyCode&lt;112) (event.keyCode&gt;127 &amp;&amp; event.keyCode!=144))&nbsp; checkInputChar(event.srcElement,event.keyCode);<BR>&nbsp; }<BR>} </P>
<P></P>
<P>//有效性判断入口<BR>function checkInputChar(handle,keyCode) {<BR>&nbsp;&nbsp;&nbsp; hideTip();<BR>&nbsp;var typeStr = handle.charset.toLowerCase();<BR>&nbsp;var firstChar = typeStr.substring(0,1);<BR>&nbsp;firstChar = firstChar.toUpperCase();<BR>&nbsp;typeStr = firstChar+typeStr.substring(1,typeStr.length);<BR>&nbsp;var tempMsg=eval("input"+typeStr+"(handle,keyCode);");<BR>&nbsp;if (tempMsg!=true)<BR>&nbsp;{<BR>&nbsp; hideTip();<BR>&nbsp; showTip(handle,tempMsg);<BR>&nbsp;}<BR>}</P>
<P>//关闭提示信息层<BR>function hideTip() {<BR>&nbsp; document.all.checkMsgDiv.style.visibility = 'hidden';<BR>&nbsp; //显示被隐藏了的选择框<BR>&nbsp; ShowOverSels("checkMsgDiv");<BR>&nbsp;clearTimeout(timer);<BR>} </P>
<P></P>
<P>//获得文本框中文本的象素单位的宽度<BR>function getTextLength(handle)<BR>{<BR>&nbsp;&nbsp;&nbsp; var range = handle.createTextRange();<BR>&nbsp;&nbsp;&nbsp; return range.boundingWidth;<BR>&nbsp;&nbsp;&nbsp; //return 0;<BR>}</P>
<P>//画一个隐藏的层<BR>function drawTipDiv() {<BR>&nbsp; document.write("&lt;div id=\"checkMsgDiv\"&nbsp; style=\"position:absolute; width:218px; overflow: visible; z-index:1; visibility:hidden; left: 103px; top: 69px; height: 66px; border: 1px none #000000;\"&gt; ");<BR>&nbsp; document.write("&nbsp; &lt;table width=\"218\" height=\"65\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"&nbsp; id=\"checkMsgTable\"&gt;");<BR><BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp; &lt;tr&gt; ");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td height=\"13\" valign=\"top\"&gt;&lt;img src=\"/platform/js/t_top.gif\" width=\"218\" height=\"26\"&gt;&lt;/td&gt;");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp; &lt;/tr&gt;");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp; &lt;tr&gt; ");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td height=\"42\" valign=\"top\" background=\"/platform/js/t_bg.gif\"&gt;");<BR>&nbsp; document.write("&nbsp; &lt;table width=\"95%\" border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" style=\"font:9pt 宋体;\"&gt;");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td id=\"checkMsgTd\"&gt;sdafs &lt;/td&gt;");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/table&gt;&lt;/td&gt;");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp; &lt;/tr&gt;");</P>
<P>document.write("&nbsp;&nbsp;&nbsp; &lt;tr&gt;");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td height=\"10\" valign=\"bottom\"&gt;&lt;img src=\"/platform/js/t_bottom.gif\" width=\"218\" height=\"10\"&gt;&lt;/td&gt;");<BR>&nbsp; document.write("&nbsp;&nbsp;&nbsp; &lt;/tr&gt;");<BR>&nbsp; document.write("&nbsp; &lt;/table&gt;");<BR>&nbsp; document.write("&lt;/div&gt;");<BR>} </P>
<P></P>
<P>//输出样式表<BR>function drawStyle() {<BR>&nbsp; document.write("&lt;style type=\"text/Css\"&gt;");<BR>&nbsp; document.write("input.activeInput{border-top-color:#0000CC;border-top-width:1px;border-bottom-color:#0000CC;border-bottom-width:1px;border-left-color:#0000CC;border-left-width:1px;border-right-color:#0000CC;border-right-width:1px;}");<BR>&nbsp; document.write("img.activeImg{border-top-color:#3366FF;border-top-width:1px;border-bottom-color:#3366FF;border-bottom-width:1px;border-left-color:#3366FF;border-left-width:1px;border-right-color:#3366FF;border-right-width:1px;}");<BR><BR>&nbsp; document.write("&lt;/style&gt;");<BR>}</P>
<P>//控件onFocus事件的侦听器<BR>function onInputFocus() {<BR>&nbsp; if(window.event.srcElement.src) {<BR>&nbsp;if(window.event.srcElement.onclick) {<BR>&nbsp;oldImgStyle = window.event.srcElement.style;<BR>&nbsp;&nbsp;&nbsp; window.event.srcElement.className="activeImg";<BR>&nbsp;}<BR>&nbsp; } else {<BR>&nbsp;oldInputStyle = window.event.srcElement.style;<BR>&nbsp;window.event.srcElement.className="activeInput";<BR>&nbsp;if(window.event.srcElement.select) window.event.srcElement.select();<BR>&nbsp; }<BR>}</P>
<P>//控件onblur事件的侦听器<BR>function onInputBlur() {<BR>&nbsp; if(window.event.srcElement.src) {<BR>&nbsp;&nbsp;&nbsp; window.event.srcElement.className = "";<BR>&nbsp; } else {<BR>&nbsp;&nbsp;&nbsp; window.event.srcElement.className = "";<BR>&nbsp; }<BR>} </P>
<P></P>
<P>//控件onkeypress事件的侦听器<BR>function onInputKeydown () {<BR>&nbsp; handleKeyDown(window.event);<BR>}</P>
<P>//控件onPaste事件的侦听器<BR>function onInputPaste () {<BR>&nbsp;return false;<BR>}</P>
<P>//表单onSubmit事件的侦听器<BR>function onFormSubmit () {<BR>&nbsp; return checkFormInput(window.event.srcElement);<BR>}</P>
<P>//控件onMouseover事件的侦听器<BR>function onInputMouseover () {<BR>&nbsp; onInputFocus();&nbsp; <BR>}</P>
<P>//控年onMouseout事件的侦听器<BR>function onInputMouseout () {<BR>&nbsp; onInputBlur();<BR>}</P>
<P>//为每个可输入控件装载侦听器<BR>function addListener() {<BR>&nbsp;var inputList = document.body.getElementsByTagName("INPUT");<BR>&nbsp;if(inputList[0]) firstInput = inputList[0];<BR>&nbsp;&nbsp;&nbsp; for(var i=0;i&lt;inputList.length;i++) {<BR>&nbsp;&nbsp; inputList[i].attachEvent ('onkeydown', onInputKeydown);<BR>&nbsp;&nbsp; inputList[i].attachEvent ('onfocus', onInputFocus);<BR>&nbsp;&nbsp; inputList[i].attachEvent ('onblur', onInputBlur);<BR>&nbsp;&nbsp; //inputList[i].attachEvent ('onpaste', onInputPaste);<BR>&nbsp;&nbsp; inputList[i].attachEvent ('onmouseover', onInputMouseover);<BR>&nbsp;&nbsp; inputList[i].attachEvent ('onmouseout', onInputMouseout);<BR>&nbsp;&nbsp; }<BR>&nbsp;&nbsp; if(inputList[i-1]) endInput = inputList[i-1];<BR><BR>&nbsp;&nbsp; var inputList = document.body.getElementsByTagName("IMG");<BR>&nbsp;&nbsp; for(var i=0;i&lt;inputList.length;i++) {<BR>&nbsp;&nbsp; inputList[i].attachEvent ('onkeydown', onInputKeydown);<BR>&nbsp;&nbsp; inputList[i].attachEvent ('onfocus', onInputFocus);<BR>&nbsp;&nbsp; inputList[i].attachEvent ('onblur', onInputBlur);<BR>&nbsp;&nbsp; }<BR>&nbsp;&nbsp; document.body.attachEvent('onkeydown', onInputKeydown);</P>
<P>&nbsp;&nbsp; var formList = document.body.getElementsByTagName("FORM");<BR>&nbsp;&nbsp; for(var i=0;i&lt;formList.length;i++) {<BR>&nbsp;formList[i].attachEvent ('onsubmit',onFormSubmit);<BR>&nbsp;&nbsp; }<BR>} </P>
<P></P>
<P>// 隐藏被ID为objID的对象（层）遮挡的所有select<BR>function HideOverSels(objID)<BR>{<BR>&nbsp;&nbsp;&nbsp; var sels = document.getElementsByTagName('select');<BR>&nbsp;&nbsp;&nbsp; for (var i = 0; i &lt; sels.length; i++)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (Obj1OverObj2(document.all[objID], sels[i]))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sels[i].style.visibility = 'hidden';<BR>}</P>
<P>// 显示被ID为objID的对象（层）遮挡的所有select<BR>function ShowOverSels(objID)<BR>{<BR>&nbsp;&nbsp;&nbsp; var sels = document.getElementsByTagName('select');<BR>&nbsp;&nbsp;&nbsp; for (var i = 0; i &lt; sels.length; i++)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (Obj1OverObj2(document.all[objID], sels[i]))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sels[i].style.visibility = 'visible';<BR>}</P>
<P>//判断obj1是否遮挡了obj2<BR>function Obj1OverObj2(obj1, obj2)<BR>{<BR>&nbsp; var pos1 = getPosition(obj1)<BR>&nbsp; var pos2 = getPosition(obj2)<BR>&nbsp; var result = true;<BR>&nbsp; var obj1Left = pos1.left - window.document.body.scrollLeft;<BR>&nbsp; var obj1Top = pos1.top - window.document.body.scrollTop;<BR>&nbsp; var obj1Right = obj1Left + obj1.offsetWidth;<BR>&nbsp; var obj1Bottom = obj1Top + obj1.offsetHeight;<BR>&nbsp; var obj2Left = pos2.left - window.document.body.scrollLeft;<BR>&nbsp; var obj2Top = pos2.top - window.document.body.scrollTop;<BR>&nbsp; var obj2Right = obj2Left + obj2.offsetWidth;<BR><BR>&nbsp; var obj2Bottom = obj2Top + obj2.offsetHeight;<BR>&nbsp; if (obj1Right &lt;= obj2Left obj1Bottom &lt;= obj2Top <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj1Left &gt;= obj2Right obj1Top &gt;= obj2Bottom)<BR>&nbsp;&nbsp;&nbsp; result = false;<BR>&nbsp; return result;<BR>}</P>
<P>// 获取对象的坐标<BR>function getPosition(Obj)<BR>{<BR></P>
<P> var sumTop=0;<BR>&nbsp;&nbsp;&nbsp; var sumLeft=0;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; while(Obj!=window.document.body) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sumTop+=Obj.offsetTop;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Obj.tagName.toLowerCase()=='div') {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sumTop-=Obj.scrollTop;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sumLeft+=Obj.offsetLeft;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Obj=Obj.offsetParent;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;return {left:sumLeft,top:sumTop}<BR>} </P>
<P></P>
<P>//判断控件的可见性<BR>function isControlVisible(handle) {<BR>&nbsp; var retValue = true;<BR>&nbsp; while(handle.tagName.toLowerCase()!='form' &amp;&amp; handle.style.display.toLowerCase()!='none') {<BR>&nbsp;&nbsp;&nbsp; handle = handle.parentElement;<BR>&nbsp; }<BR>&nbsp; if(handle.style.display=='none') retValue = false;<BR>&nbsp; return retValue;<BR>}</P>
<P>//================以上为系统函数区=======================//</P>
<P>//以下为输入过程中输入内容即时验证函数<BR>//必须输入是数字<BR>function inputNumber(handle,keyCode) {<BR>&nbsp; if(!((keyCode&gt;=48&amp;&amp;keyCode&lt;=57)(keyCode&gt;=96&amp;&amp;keyCode&lt;=105))) {<BR>&nbsp;window.event.returnValue=false;<BR>&nbsp;return "必须输入数字!即如下字符:&lt;br&gt;1234567890";<BR>&nbsp; } else return true;<BR>}<BR>//必须输入字母<BR>function inputLetter(handle,keyCode) {<BR>&nbsp; if(!((keyCode&gt;=97&amp;&amp;keyCode&lt;=122)(keyCode&gt;=65&amp;&amp;keyCode&lt;=90))) {<BR>&nbsp;window.event.returnValue=false;<BR>&nbsp;return "必须输入大小写字母!即如下字符:&lt;br&gt;abcdefghijklmnopqrstuvwxyz&lt;br&gt;ABCDEFGHIJKLMNOPQRSTUVWXYZ";<BR>&nbsp; } else return true;<BR>}<BR>//必须输入所有可见字符<BR>function inputVisible(handle,keyCode) {<BR><BR>&nbsp;var pattern = "&lt;,-[]{}?/+=\\\'\":;~!#$%"&gt;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.@&gt;&lt;,-[]{}?/+=\\\'\":;~!#$%()`";<BR>var keyValue=String.fromCharCode(keyCode);<BR>&nbsp;if(keyCode==190) keyValue = ".";<BR>&nbsp;if(keyCode==189) keyValue = "-";<BR>&nbsp;if(keyCode==188) keyValue = "&lt;";<BR>&nbsp;if(keyCode==219) keyValue = "[";<BR>&nbsp;if(keyCode==221) keyValue = "]";<BR>&nbsp;if(keyCode==191) keyValue = "?";<BR>&nbsp;if(keyCode==187) keyValue = "+";<BR>&nbsp;if(keyCode==220) keyValue = "";<BR>&nbsp;if(keyCode==222) keyValue = "'";<BR>&nbsp;if(keyCode==186) keyValue = ";";<BR>&nbsp;if(keyCode==192) keyValue = "~";<BR>&nbsp;if(pattern.indexOf(keyValue)!=-1) {<BR>&nbsp; window.event.returnValue=true;<BR>&nbsp; return true;<BR>&nbsp;}else{<BR>&nbsp; window.event.returnValue=false;<BR>&nbsp; return "必须输入可见字符!即如下字符:&lt;br&gt;ABCDEFGHIJKLMNOPQRSTUVWXYZ&lt;br&gt;abcdefghijklmnopqrstuvwxyz&lt;br&gt;0123456789.@&gt;&lt;,-[]{}?/+=\\\'\":&lt;br&gt;;~!#$%()`";<BR>&nbsp;}<BR>}<BR>//必须输入字母与数字<BR>function inputNormal(handle,keyCode) {<BR>&nbsp;var pattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";<BR>&nbsp;var keyValue=String.fromCharCode(keyCode);<BR>&nbsp;if(pattern.indexOf(keyValue)!=-1) {<BR>&nbsp; window.event.returnValue=true;<BR>&nbsp; return true;<BR>&nbsp;}else{<BR>&nbsp; window.event.returnValue=false;<BR>&nbsp; return "必须输入可见字符!即如下字符:&lt;br&gt;ABCDEFGHIJKLMNOPQRSTUVWXYZ&lt;br&gt;abcdefghijklmnopqrstuvwxyz&lt;br&gt;0123456789";<BR>&nbsp;}<BR>} </P>
<P></P>
<P>//================以下为校验函数区=======================//<BR>//函数名说明:is+TypeName,TypeName首字母大写<BR>//参数handle为当前控件句柄<BR>//参数keyCode为当前按钮的值<BR>//返回说明:通过返回"",不通过返回不通过的原因描述<BR>/*格式支持例表<BR>格式字符&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 格式描述&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 格式说明<BR>Number&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数字型<BR>Userid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户ID<BR>Username&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户名称<BR>Enterprisename&nbsp;&nbsp;&nbsp;&nbsp; 企业单位名称<BR>Loginname&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 登录名称<BR>Cardnumber&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 证件号码<BR>Address&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 地址<BR>Phone&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 电话号码<BR>Mobile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 手机号码<BR>Postcode&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 邮政编码<BR>Email&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 电子邮件<BR>Namesimplicity&nbsp;&nbsp;&nbsp;&nbsp; 姓名简拼<BR>Password&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 密码<BR>Namestr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 名称字符串<BR>DescStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 描述字符串<BR>Pageurl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 页面URL<BR>Dirctory&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 磁盘路径<BR>*/ </P>
<P></P>
<P>//判断是否是数字<BR>&nbsp;function isNumber(handle){<BR>&nbsp; var pattern = /^(\d){1,14}$/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须输入数字!";<BR>&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//判断是否是用户账号<BR>&nbsp;function isUserid(handle){<BR>&nbsp; var pattern = /^(\d\w){3,14}$/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须输入数字&lt;br&gt;且长度需大于等于3位小于等于14位!";<BR>&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//判断是否用户名称可以是字母也可以是中文<BR>&nbsp;function isUsername(handle){<BR>&nbsp; var pattern = /^[a-zA-Z\u4E00-\u9FA5]{2,50}$/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是中文字母或者数字&lt;br&gt;且长度需大于等于2位小于等于50位!"<BR>&nbsp;return true;<BR>&nbsp;&nbsp;&nbsp; }<BR>//判断是否是企业名称:可以是字母 数字 中文 - _<BR>&nbsp;&nbsp;&nbsp; function isEnterprisename(handle){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var pattern = /^[a-zA-Z0-9-_\u4E00-\u9FA5]{2,200}$/;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是中文字母或者数字&lt;br&gt;且长度需大于等于2位小于等于200位!";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;&nbsp;&nbsp; }<BR>//判断是否是登录名称<BR>&nbsp;&nbsp;&nbsp; function isLoginname(handle){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var pattern = /^([a-z][A-Z][0-9]){2,25}$/;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是字母或者数字&lt;br&gt;且长度需大于等于2位小于等于25位!";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//判断是否是证件号码<BR>&nbsp;function isCardnumber(handle){<BR>&nbsp;&nbsp; var pattern;<BR>&nbsp; pattern = /^(\d){5,18}$/;<BR>&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是数字&lt;br&gt;且长度需大于等于5位小于等于16位!";<BR>&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//地址<BR>&nbsp;function isAddress(handle){<BR>&nbsp; var pattern = /^[a-zA-Z0-9\u4E00-\u9FA5]{2,200}$/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是中文字母或者数字&lt;br&gt;且长度需大于等于2位小于等于200位!";<BR>&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//联系电话<BR>&nbsp;function isPhone(handle){<BR>&nbsp; var pattern = /^(\d){6,30}$/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是数字&lt;br&gt;且长度需大于等于6位小于等于30位!";<BR>&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//手机<BR>&nbsp;function isMobile(handle){<BR>&nbsp; var pattern = /^[1][3](\d){9}$/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是数字&lt;br&gt;且首两位是13长度是11位!";<BR>&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//邮编<BR>&nbsp;function isPostcode(handle){<BR>var pattern = /^(\d){6}$/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是数字&lt;br&gt;且长度需是6位!";<BR>&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//email<BR><BR>&nbsp;function isEmail(handle){<BR>&nbsp; var pattern = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须符合电子邮件地址格式";<BR>&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//简拼<BR>&nbsp;function isNamesimplicity(handle){<BR>&nbsp; var pattern = /^([a-zA-Z]){2,25}$/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是字母&lt;br&gt;且长度需大于等于2位小于等于25位!";<BR>&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//密码<BR>&nbsp;function isPassword(handle){<BR>&nbsp; var pattern = /^([a-zA-Z][0-9]){2,25}$/;<BR>&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是字母或者数字&lt;br&gt;且长度需大于等于2位小于等于25位!";<BR>&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;}<BR>//判断是否是名称:可以是字母 数字 中文 - _<BR>&nbsp;&nbsp;&nbsp; function isNamestr(handle){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var pattern = /^[a-zA-Z0-9-_\u4E00-\u9FA5]{1,40}$/;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是中文字母或者数字&lt;br&gt;且长度需大于等于1位小于等于40位!";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;&nbsp;&nbsp; }<BR>//判断是否是描述信息:可以是字母 数字 中文 - _ , .<BR>&nbsp;&nbsp;&nbsp; function isDescstr(handle){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var pattern = /^[a-zA-Z0-9-_,.\u4E00-\u9FA5]{1,50}$/;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是中文字母或者数字&lt;br&gt;且长度需大于等于1位小于等于50位!";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;&nbsp;&nbsp; } </P>
<P></P>
<P>//页面URL<BR>&nbsp;&nbsp;&nbsp; function isPageurl(handle){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var pattern = /^[a-zA-Z0-9-_,./\u4E00-\u9FA5]{1,80}$/;<BR>&nbsp;if (!pattern.exec(handle.value)) return "必须是中文字母或者数字&lt;br&gt;且长度需大于等于`位小于等于80位!";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;&nbsp;&nbsp; } </P>
<P></P>
<P>//目录路径<BR>&nbsp;&nbsp;&nbsp; function isDirctoryurl(handle){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var pattern = /^[a-zA-Z0-9-_,.\\u4E00-\u9FA5]{1,300}$/;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!pattern.exec(handle.value)) return "必须是中文字母或者数字&lt;br&gt;且长度需大于等于1位小于等于300位!";<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P><BR>/*<BR>//高强度身份号码验证<BR>var aCity={11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙江",31:"上海",32:"江苏",33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山东",41:"河南",42:"湖北",43:"湖南",44:"广东",45:"广西",46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏",61:"陕西",62:"甘肃",63:"青海",64:"宁夏",65:"新疆",71:"台湾",81:"香港",82:"澳门",91:"国外"}<BR>function cidInfo(sId){<BR>&nbsp;var iSum=0<BR>&nbsp;var info=""<BR>&nbsp;if(!/^\d{17}(\dx)$/i.test(sId))return false;<BR>&nbsp;sId=sId.replace(/x$/i,"a");<BR>&nbsp;if(aCity[parseInt(sId.substr(0,2))]==null)return "Error:非法地区";<BR>&nbsp;sBirthday=sId.substr(6,4)+"-"+Number(sId.substr(10,2))+"-"+Number(sId.substr(12,2));<BR>&nbsp;var d=new Date(sBirthday.replace(/-/g,"/"))<BR>&nbsp;if(sBirthday!=(d.getFullYear()+"-"+ (d.getMonth()+1) + "-" + d.getDate()))return "Error:非法生日";<BR>&nbsp;for(var i = 17;i&gt;=0;i --) iSum += (Math.pow(2,i) % 11) * parseInt(sId.charAt(17 - i),11)<BR>&nbsp;if(iSum%11!=1)return "Error:非法证号";<BR>&nbsp;return aCity[parseInt(sId.substr(0,2))]+","+sBirthday+","+(sId.substr(16,1)%2?"男":"女")<BR>}</P>
<P>document.write(cidInfo("380524198002300016"),"&lt;br/&gt;");<BR>document.write(cidInfo("340524198002300019"),"&lt;br/&gt;")<BR>document.write(cidInfo("340524197711111111"),"&lt;br/&gt;")<BR>document.write(cidInfo("34052419800101001x"),"&lt;br/&gt;"); </P>
<P></P>
<P>function isip(s){<BR>&nbsp;var check=function(v){try{return (v&lt;=255 &amp;&amp; v&gt;=0)}catch(x){return false}};<BR>&nbsp;var re=s.split(".")<BR>&nbsp;return (re.length==4)?(check(re[0]) &amp;&amp; check(re[1]) &amp;&amp; check(re[2]) &amp;&amp; check(re[3])):false<BR>}</P>
<P>var s="202.197.78.129";<BR>alert(isip(s))*/</P>
<P>//================以上为校验函数区=======================//<BR><BR></P></div>]]></description>
	    <author><![CDATA[lklkdawei]]></author>
	    <comments>http://lklkdawei.blog.163.com/blog/static/3257410920088249251685</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://lklkdawei.blog.163.com/blog/static/3257410920088249251685</guid>
    <pubDate>Wed, 24 Sep 2008 09:25:01 +0800</pubDate>
    <dcterms:modified>2008-09-24T09:25:01+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[字符，字节和编码【转】]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/32574109200882492012743</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">[转载：<A href="http://www.regexlab.com/zh/encoding.htm">http://www.regexlab.com/zh/encoding.htm</A>] 
</P><P style="TEXT-INDENT: 2em">&nbsp; 
</P><P>级别：初级</P>
<BLOCKQUOTE>
<P>摘要：本文将完整，通俗地介绍字符编码，软件国际化等相关概念，也就是编码问题，内容涵盖常说的“中文问题”，“乱码问题”。本文针对亚洲的读者，讲解了产生乱码问题的原理以及解决办法。同时也针对西方的读者，讲解了字符编码的概念，为西方国家的朋友开发国际化软件打一个必要的基础。</P></BLOCKQUOTE>
<H4><A></A>引言</H4>
<P>“编码问题”是一个被经常讨论的话题。即使这样，时常出现的乱码仍然困扰着大家。虽然有很多的办法可以用来消除乱码，但我们并不一定理解这些办法的内在原理。我们在写出代码并尝试所掌握的办法之前，仍然无法保证乱码不会出现。而有的乱码产生的原因，实际上是 JDBC 驱动或 ODBC 驱动本身有问题所导致的。因此，不仅是初学者会对编码问题感到模糊，不少的编程高手同样对编码问题缺乏准确的理解。</P>
<P>本文将讲解编码问题产生的由来，编码概念的正确理解，各种环节编码的处理办法，以及产生乱码的原因和解决办法。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H4><A></A>1. 编码问题的由来</H4>
<P>最早诞生的 <STRONG>ASCII 码</STRONG>只包含了英语字母和一些常用标点符号，编号为0~127。后来制定了<STRONG>扩展 ASCII 码</STRONG>，增加了一些欧洲语言中的字母和其他的一些符号，编号为0~255。在计算机中，使用一个字节来存储一个字母或符号。</P>
<P>随着计算机的发展，各个国家和地区为了能在计算机上使用自己的语言，纷纷研究技术方案和制定相关标准。通常采取的办法是，保留 ASCII 中的0~127部分不变，然后使用128~255范围的2个字节来表示1个字符。比如：汉字‘中’在 GB2312 标准中，使用 [D6][D0] 这两个字节表示。不同的国家和地区制定了不同的标准，由此产生了 GB2312, BIG5, JIS 等各自的编码标准。</P>
<P>这些所有使用 2 个字节来代表一个字符的各种汉字延伸编码方式，称为 <STRONG>ANSI 编码</STRONG>。在简体中文系统下，ANSI 编码代表 GB2312 编码，在繁体中文系统下，ANSI 编码代表 BIG5 编码，在日文操作系统下，ANSI 编码代表 JIS 编码。</P>
<P>这些标准之间互不兼容，比如：在汉语和日语中都有‘中’字，同样为了表示‘中’字，GB2312 使用的两个字节与 JIS 使用的两个字节是不一样的。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H4>2. 正确的理解相关概念</H4>
<H5><A></A>2.1 字符与字节</H5>
<P>在很长一段时间里，计算机只支持英语和欧洲的语言，一个字母或符号就用一个字节表示，字符的含义就相当于字节。比如 C 语言中的一个字符(<SPAN><FONT color=#0000ff>char</FONT></SPAN>)就表示一个字节。当汉语等语言被支持以后，汉字需要使用多个字节表示，因此，字符的含义不再等同于字节。现在我们必须明确区分这两者的概念：</P>
<TABLE cellSpacing=0 cellPadding=3 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD vAlign=top noWrap>
<P>字符：</P></TD>
<TD>
<P>人们使用的记号，抽象意义上的一个符号。比如：‘1’,‘中’,‘a’,‘$’,‘￥’,……。它们之间的地位完全平等。</P></TD></TR>
<TR>
<TD vAlign=top noWrap>
<P>字节：</P></TD>
<TD>
<P>计算机中存储数据的单元，一个8位的二进制数，是一个很具体的存储空间。</P></TD></TR></TBODY></TABLE>
<P>在这里，我们对字符和字节的含义进行了区分。当提到“<STRONG>字符</STRONG>”的时候，我们只需要想到它是一个符号，不要去考虑它在内存中是什么样子。当我们提到“<STRONG>字节</STRONG>”的时候，我们只需要想到它是一个8位二进制数，不要去考虑它表示哪个字符。对于某个字符，不同的编码标准可能会规定不同的字节来表示。因此，单纯的问：“计算机中某个字符是用怎么存储的”这个问题是没有意义的。</P>
<P>在 Java 语言中 <SPAN><FONT color=#0000ff>char</FONT></SPAN> 的含义与在 C 语言中是不同的。Java 中的 <SPAN><FONT color=#0000ff>char</FONT></SPAN> 表示“字符”，代表一个抽象意义上的符号，<SPAN><FONT color=#0000ff>byte</FONT></SPAN> 表示“字节”。而在 C 语言中 <SPAN><FONT color=#0000ff>char</FONT></SPAN> 代表一个字节。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>2.2 字符集，编码</H5>
<P>不同的国家和地区所制定的不同标准，都只规定了各自所需的字符。比如：汉字标准（GB2312）中就没有规定韩国语字符的表示办法。这些标准中规定的内容有两层含义：</P>
<OL>
<LI>使用哪些字符：哪些汉字，字母和符号会被收入标准中。所包含字符的集合就叫做“<STRONG>字符集</STRONG>”。 
</LI><LI>规定每一个字符怎样用字节存储的，这个规定就叫做“<STRONG>编码</STRONG>”。 </LI></OL>
<P>各个国家和地区在制定编码标准的时候，“字符的集合”和“编码”都是同时制定的。因此，平常我们所说的“字符集”，比如：GB2312, GBK, JIS 等，除了有“字符的集合”这层含义外，同时也包含了“编码”的含义。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>2.3 UNICODE 字符集</H5>
<P>不同字符集的编码规则互不兼容。两个不同字符分别属于两个字符集，采用各自编码规则后可能得到相同的字节，因此，当我们想要在计算机中同时表示这两个字符时就无法做到。</P>
<P>为了解决这个问题，使国际间信息交流更加方便，国际组织制定了 <STRONG>UNICODE 字符集</STRONG>。UNICODE 包含了各种语言里面所使用到的所有字符，并为每一个字符赋予了一个唯一的序号。不论在什么平台下，什么程序中，不论用在什么语言里，UNICODE 对同一个字符赋予的序号总是相同的。</P>
<P>与其他“字符集”不同的是，“UNICODE”并不代表一种“编码”，只代表一个“字符的集合”。用来给 UNICODE 字符集编码的标准有很多种，比如：UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig 等。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H4>3. 实际应用中编码问题的处理方法</H4>
<P>在大家正确理解了相关概念后，以下的章节都是对这些概念在实际应用场合的更深入的讲解。如果你在进行以下章节的过程中，感觉理解比较困难，说明前面所讲的概念你还没有理解正确，有必要回头去复习一下第 2 节中的内容。</P>
<H5><A></A>3.1 操作系统中的字符串</H5>
<P>在 UNICODE 被采用之前，计算机想要记录一段文字，内存中实际存放的内容是：按照指定编码规则得到的字节串。也就是按照 <A href="http://www.regexlab.com/zh/encoding.htm#yl">ANSI 编码</A>方式存储在内存中的。比如：在中文 DOS, Windows 95, Windows 98 操作系统中，字符串 <SPAN><FONT color=#ff00ff>"中文123"</FONT></SPAN> 存放在内存中时，实际存放的是 [D6][D0][CE][C4][31][32][33] 这7个字节。（<SPAN><FONT color=#ff00ff>'中' </FONT></SPAN>和<SPAN><FONT color=#ff00ff> '文' </FONT></SPAN>分别占2个字节。）</P>
<P>而在 UNICODE 被采用之后，计算机想要记录一段文字时，内存中不再存放根据特定编码而得到的字节串，而改为存放各个字符在 <A href="http://www.regexlab.com/zh/encoding.htm#un">UNICODE</A> 中的序号。比如：在 Windows NT/2000/XP, Linux, Java 系统中，字符串 <SPAN><FONT color=#ff00ff>"中文123"</FONT></SPAN> 存放在内存中时，实际记录的是 20013, 25991, 49, 50, 51 这5个序号。当不同语言中的字符需要同时表示时，不会因为编码冲突而无法表示。</P>
<P>字符串实际所占内存空间的大小，要取决于当前系统采用多少字节来存放一个“序号”。如果使用2个字节存放一个序号，那么 <SPAN><FONT color=#ff00ff>"中文123"</FONT></SPAN> 在内存中就占10个字节。如果使用4个字节存放一个序号，那么 <SPAN><FONT color=#ff00ff>"中文123"</FONT></SPAN> 就占20个字节。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>3.2 Java, C++ 中的字符与字节</H5>
<P>在 Java 和 C++ 中，分别代表字节和字符的数据类型是： 
<TABLE cellSpacing=0 cellPadding=3 bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TH>
<P>　</P></TH>
<TH>
<P>字节</P></TH>
<TH>
<P>字符</P></TH>
<TH>
<P>字节串</P></TH>
<TH>
<P>字符串</P></TH></TR>
<TR>
<TH>
<P>Java</P></TH>
<TD>
<P>byte</P></TD>
<TD>
<P>char</P></TD>
<TD>
<P><SPAN><FONT color=#0000ff>byte</FONT></SPAN>[]</P></TD>
<TD>
<P>String</P></TD></TR>
<TR>
<TH>
<P>C++</P></TH>
<TD>
<P>char</P></TD>
<TD>
<P>wchar_t</P></TD>
<TD>
<P><SPAN><FONT color=#0000ff>char</FONT></SPAN>*</P></TD>
<TD>
<P><SPAN><FONT color=#0000ff>char</FONT></SPAN>*<SPAN><FONT color=#008000>(ANSI)</FONT></SPAN>, wchar_t*<SPAN><FONT color=#008000>(UNICODE)</FONT></SPAN>, CString<SPAN><FONT color=#008000>(Visual C++)</FONT></SPAN></P></TD></TR></TBODY></TABLE></P>
<P>在 Java 中，“字符串”与“字节串”之间可以方便地按照指定编码规则进行转化： 
<TABLE cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><FONT face="Lucida Console"><SPAN><FONT color=#0000ff>byte</FONT></SPAN> [] b = <SPAN><FONT color=#ff00ff>"中文123"</FONT></SPAN>.getBytes(<SPAN><FONT color=#ff00ff>"GB2312"</FONT></SPAN>); <FONT color=#008000><SPAN>// 从字符串按照 GB2312 得到字节串</SPAN><BR></FONT><SPAN><FONT color=#ff0000>System</FONT></SPAN>.out.println(b.length); <FONT color=#008000><SPAN>// 得到长度为7个 (D6,D0,CE,C4,31,32,33)</SPAN><BR><BR></FONT><SPAN><FONT color=#ff0000>String</FONT></SPAN> str = <SPAN><FONT color=#0000ff>new</FONT></SPAN> <SPAN><FONT color=#ff0000>String</FONT></SPAN>(b, <SPAN><FONT color=#ff00ff>"GB2312"</FONT></SPAN>); <FONT color=#008000><SPAN>// 从字节串按照 GB2312 得到字符串</SPAN><BR><BR></FONT><SPAN><FONT color=#ff0000>System</FONT></SPAN>.out.println(<SPAN><FONT color=#ff00ff>"中文123"</FONT></SPAN>.length()); <SPAN><FONT color=#008000>// 得到长度为5，因为是5个字符</FONT></SPAN></FONT></TD></TR></TBODY></TABLE></P>
<P>在 java.io.* 包里面有很多类，其中，以“Stream”结尾的类都是用来操作“字节串”的类，以“Reader”，“Writer”结尾的类都是用来操作“字符串”的类。任何一个文件保存到硬盘上的时候，都是以字节为单位保存的，当要把“字符串”保存到硬盘上的文本文件，必然要选择一种编码。 </P>
<P>有两种方法来指定编码： 
<TABLE cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><FONT face="Lucida Console"><SPAN><FONT color=#ff0000>String</FONT></SPAN> str = <SPAN><FONT color=#ff00ff>"中文123"</FONT></SPAN>;<BR><BR><FONT color=#008000><SPAN>// 第一种办法：先用指定编码转化成字节串，然后用 Stream 类写入</SPAN><BR></FONT>OutputStream os = <SPAN><FONT color=#0000ff>new</FONT></SPAN> FileOutputStream(<SPAN><FONT color=#ff00ff>"1.txt"</FONT></SPAN>);<BR><SPAN><FONT color=#0000ff>byte</FONT></SPAN> [] b = str.getBytes(<SPAN><FONT color=#ff00ff>"utf-8"</FONT></SPAN>);<BR>os.write(b);<BR>os.close();<BR><BR><FONT color=#008000><SPAN>// 第二种办法：构造指定编码的 Writer 来写入字符串</SPAN><BR></FONT>Writer ow = <SPAN><FONT color=#0000ff>new</FONT></SPAN> OutputStreamWriter(<SPAN><FONT color=#0000ff>new</FONT></SPAN> FileOutputStream(<SPAN><FONT color=#ff00ff>"2.txt"</FONT></SPAN>), <SPAN><FONT color=#ff00ff>"utf-8"</FONT></SPAN>);<BR>ow.write(str);<BR>ow.close();<BR><BR><SPAN><FONT color=#008000>// 最后得到的 1.txt 和 2.txt 都是 9 个字节。（汉字在 utf-8 编码规则中占3字节）</FONT></SPAN></FONT></TD></TR></TBODY></TABLE></P>
<P>在 C++ 中，操作字节串（char*）和操作字符串（wchar_t*）各有一套函数。在 Windows API 中，字符串与字节串相互转化的函数是：MultiByteToWideChar() 和 WideCharToMultiByte()。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>3.3 数据库编码</H5>
<P>我们在安装数据库的时候，比如安装 MySQL、MS SQL Server、Oracle 时，都会要求选择一种编码。数据库中跟字符串相关的类型有：char, varchar, text, nchar, nvarchar, ntext 等。其中，char, varchar, text 这几种类型的存储方式，是按照所选编码将文本转化为<A href="http://www.regexlab.com/zh/encoding.htm#zf">字节</A>进行存储的。char(10) 和 varchar(10) 的长度限制，指的是<A href="http://www.regexlab.com/zh/encoding.htm#zf">字节</A>的长度限制。另外的 nchar, nvarchar, ntext 这几种类型的存储方式，是直接按照<A href="http://www.regexlab.com/zh/encoding.htm#un">字符的 UNICODE 序号</A>进行存储的，nchar(10) 和 nvarchar(10) 的长度限制，指的是<A href="http://www.regexlab.com/zh/encoding.htm#zf">字符</A>数限制。</P>
<P>比如，在使用 GB2312 编码的 SQL Server 数据库中，对于如下表： 
<TABLE cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><FONT face="Lucida Console"><SPAN><FONT color=#0000ff>CREATE</FONT></SPAN> <SPAN><FONT color=#0000ff>TABLE</FONT></SPAN> TEST(<BR>&nbsp; &nbsp; VAR_10 varchar(<SPAN><FONT color=#6d66a5>10</FONT></SPAN>) <SPAN><FONT color=#0000ff>NULL</FONT></SPAN>,<BR>&nbsp; &nbsp; NVAR_10 nvarchar(<SPAN><FONT color=#6d66a5>10</FONT></SPAN>) <FONT color=#0000ff><SPAN>NULL</SPAN><BR></FONT>)</FONT></TD></TR></TBODY></TABLE></P>
<P>能够存储的最大字符串长度分别是：<BR><IMG height=61 alt="" src="http://www.regexlab.com/images/encoding/dbexample.gif" width=241 border=0 twffan="done"></P>
<P>对于 MySQL 和 Oracle ，细节的地方不一定完全相同。</P>
<P>访问数据库最常用的接口是 JDBC 或者 ODBC。这些访问接口在读取字符串字段时，负责与数据库服务器交互，获知数据库服务器使用的是哪一种编码，并将数据库服务器传输过来的字节流，按照正确的编码还原成“字符”串，然后交给应用程序。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>3.4 网页表单提交时的编码</H5>
<P>当网页上的表单（form）提交数据到 Web 服务器时，'?', '&amp;', '=', '%', '+' 等符号在提交的数据中都有特殊的定义和用途。因此，如果所要提交的某个表单项中，包含这些符号，那么这些符号就需要进行一下转化，然后服务器再进行逆向转化而得到本来所要提交的数据。</P>
<P>转化的格式是：%XX （百分号再跟上被转化符号的16进制编码）。比如：'?' 会被转化成 '%3F'，空格 ' ' 会被转化成 '+' 或者 '%20'。</P>
<P>如果所要提交的表单数据中，包含有汉字，那么浏览器会将会将每个汉字根据当前页面所使用的的编码转化成字节，然后将每个字节采用 %XX 的格式提交到服务器。服务器端遇到 %XX 格式的数据时，会根据 XX 编号得到字节，然后再根据同样的编码得到字符串。</P>
<P>举例说明：提交内容“a=%D6%D0%CE%C4%31%32%33”到服务器，通过服务器提供的功能获取表单项“a”得到的内容是：“中文123”。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>3.5 电子邮件中的编码</H5>
<P>当一段 Text 或者 HTML 通过电子邮件传送时，发送的内容首先通过一种指定的<STRONG>字符编码</STRONG>转化成“字节串”，然后再将得到的“字节串”通过一种指定的<STRONG>传输编码</STRONG>（Content-Transfer-Encoding）进行转化得到另一串“字节串”。比如，打开一封电子邮件源代码，可以看到： 
<TABLE cellSpacing=0 cellPadding=6 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD>Content-Type: text/plain;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#ff0000>charset="gb2312"</FONT><BR><FONT color=#ff0000>Content-Transfer-Encoding: base64</FONT><BR><BR>sbG+qcrQuqO17cf4yee74bGjz9W7+b3wudzA7dbQ0MQNCg0KvPKzxqO6uqO17cnnsaPW0NDEDQoNCg==</TD></TR></TBODY></TABLE></P>
<P>当二进制文件，比如图片、word文档等，通过电子邮件发送时，不存在通过字符编码进行转化这个步骤，而是直接按照字节流，通过传输编码（Content-Transfer-Encoding）进行转化得到另一串“字节串”。 
<TABLE cellSpacing=0 cellPadding=6 width="100%" bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD>Content-Type: application/x-zip-compressed;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name="=?gb2312?B?XEytWy2LzQLnppcA==?="<BR><FONT color=#ff0000>Content-Transfer-Encoding: base64</FONT><BR>Content-Disposition: attachment;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filename="=?gb2312?B?XEytWy2LzQLnppcA==?="<BR><BR>UEsDBAoAAAAAAGNJHzMAAAAAAAAAAAAAAAAJAAAAyO28/rmyz+0vUEsDBBQAAAAIALZ9HjPyoUd36gAA……（省略）</TD></TR></TBODY></TABLE></P>
<P>使用<STRONG>传输编码</STRONG>进行转化的目的，主要是为了使电子邮件源代码都处于可打印字符范围之内。</P>
<P>最常用的 Content-Transfer-Encoding 有：Base64 和 Quoted-Printable 两种。在对二进制文件和中文文本进行转化时，Base64 得到的“字节串”比 Quoted-Printable 更短。在英文文本进行转化时，Quoted-Printable 得到的“字节串”比 Base64 更短。</P>
<P>需要注意的是，Base64 和 Quoted-Printable 等编码属于“Content-Transfer-Encoding”，是将“字节串”转化成为另一个“字节串”的编码，与平时提到的 GB2312, BIG5, JIS, UTF8 等字符编码是两种完全不同类型的概念，不能混淆。</P>
<H5>邮件标题的表示方法</H5>
<P>邮件标题，或者附件的文件名，表示方法为：“=?gb2312?B?XEytWy2LzQLnppcA==?=”，虽然看起来很复杂，其实同样也是“字符编码”与“传输编码”两个概念：</P>
<UL>
<LI>第一个“=?”与“?”中间的部分指定了字符编码。 
</LI><LI>第二个“?”和第三个“?”之间的 B 代表 Base64。也有可能是 Q，代表 Quoted-Printable。 
</LI><LI>第三个“?”与最后的“?=”之间的部分就是内容。 </LI></UL>
<P>在使用 JavaMail 发送邮件时，字符编码和传输编码的指定方法为： 
<TABLE cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><FONT face="Lucida Console"><FONT color=#008000><SPAN>// 设定标题</SPAN><BR></FONT>msg.setSubject(<SPAN><FONT color=#ff00ff>"标题 - 测试"</FONT></SPAN>);<BR><BR><FONT color=#008000><SPAN>// 设定内容，并指定字符编码</SPAN><BR></FONT>msg.setText&nbsp; &nbsp;(<SPAN><FONT color=#ff00ff>"内容 - 中文123"</FONT></SPAN>, <SPAN><FONT color=#ff00ff>"GB2312"</FONT></SPAN>);<BR><BR><FONT color=#008000><SPAN>// 指定传输编码</SPAN><BR></FONT>msg.setHeader (<SPAN><FONT color=#ff00ff>"Content-Transfer-Encoding"</FONT></SPAN>,<SPAN><FONT color=#ff00ff>"Quoted-Printable"</FONT></SPAN>);</FONT></TD></TR></TBODY></TABLE></P>
<P>将指定传输编码的 setHeader() 位于 setText() 之前，则不能起作用。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H4>4. 乱码产生的原因及解决办法</H4>
<P>一直在微软的平台下进行开发的程序员，很少遇到乱码问题，比如：Visual Basic, ASP, .NET 等。并不是因为他们全都掌握和理解字符与编码的相关技术，而是因为微软的平台没有概念上的错误，所提供的 ODBC 驱动，ASP 引擎，.NET 平台等没有将编码问题遗留给使用者。</P>
<P>而我们常用的很多开源项目，中间往往有一些处理不正确的环节。比如：Tomcat，JDBC，MySQL 等项目。有些乱码产生的根源，就是由这些开源项目中的错误造成的。这些项目大部分参与者都是西方人，他们对怎样支持亚洲语言容易产生一个误解。而 JDK 本身没有问题。</P>
<P>这些遗留的编码问题，留给了本不应该来处理这些问题的广大程序员们，也就是我们。我们中的几乎所有人，在刚开始遇到乱码时，都不知所措。现在，经过大家的努力，虽然我们有了很多方法可以消除乱码，但仍然对编码问题存在误解。在想办法消除乱码时，只能是试，而并不理解。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>4.1 非 UNICODE 软件在国际间移植时显示乱码</H5>
<P>非 UNICODE 软件所使用的字符串，在内存中都是以 <A href="http://www.regexlab.com/zh/encoding.htm#yl">ANSI 编码</A>方式存储的。软件在日文环境下开发，软件中的字符串常量就是以 JIS 编码的字节形式存储的，软件在简体中文环境下开发，就是以 GB2312 编码的字节形式存储的。软件在运行时，只是直接将这些字节交给系统提供的 API，系统则按照本地 ANSI 编码的字符串来处理。如果运行时的语言环境与开发时不同，界面上显示出来的就是乱码。</P>
<P>相比之下，采用 UNICODE 的软件，字符串常量都是以 UNICODE 的序号来存储的。不管在什么语言环境下，同一个编号都代表同一个符号。因此，采用 UNICODE 的日文软件，在中文操作系统上运行时，仍然可以看到正常的日文界面。</P>
<P>非 UNICODE 软件将逐渐被淘汰。过渡时期，出现了“南极星”“AppLocale”等软件，可以用来在一个语言环境下模拟另一个语言环境，运行在不同环境下开发的软件。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>4.2 东西方人对编码问题通常的误解</H5>
<P>东西方人对编码误解是不同的： 
<TABLE cellSpacing=0 cellPadding=3 bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TH noWrap>　</TH>
<TH>
<P>对编码的误解</P></TH></TR>
<TR>
<TH noWrap>
<P>东方人</P></TH>
<TD>
<P>一直以来的非 UNICODE 软件开发，字符串都是以 ANSI 编码的字节形式存在的。这种以字节形式存在的字符串，必须知道是哪种编码才能被正确显示。这使我们形成了一个惯性思维：“字符串”的编码。</P>
<P>当 UNICODE 被支持后，Java 中的 String 是以字符的“序号”来存储的，不是以“某种编码的字节”来存储的，因此已经不存在“字符串的编码”这个概念了。只有在“字符串”与“字节串”转化时，或者，将一个“字节串”当成一个 ANSI 字符串时，才有编码的概念。</P></TD></TR>
<TR>
<TH noWrap>
<P>西方人</P></TH>
<TD>
<P>西方的同行们，在将“字节串”转化成“字符串”时，容易产生的误解是：认为每“一个字节”就是“一个字符”。而事实上，应该按照编码规则，有可能“多个字节”才能得到“一个字符”。</P>
<P>在字符集标准中，ISO-8859-1 字符集的范围是 0~255，字符与字节的转换关系是：一一对应。</P>
<P>认为每“一个字节”就是“一个字符”而得到的“字符串”，只能再通过 getBytes() 得到了之前的“字节串”，重新进行处理。这就是为什么我们经常使用<BR>str = <SPAN><FONT color=#0000ff>new</FONT></SPAN> <SPAN><FONT color=#ff0000>String</FONT></SPAN>(str.getBytes(<SPAN><FONT color=#ff00ff>"ISO-8859-1"</FONT></SPAN>), <SPAN><FONT color=#ff00ff>"GB2312"</FONT></SPAN>);<BR>的原因。 </P></TD></TR></TBODY></TABLE></P>
<P>底层开发的人对编码的误解，导致的乱码的产生。上层人员对编码的误解，导致了消除乱码的复杂性。只要对概念理解正确，乱码问题其实也容易解决。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>4.3 通过 ODBC 或者 JDBC 从数据库获取字符串字段时得到乱码</H5>
<P>如果 ODBC 或 JDBC 驱动在读取字符串字段时，没有正确的将数据库发送过来的“字节流”使用正确的“编码”进行转化，所得到的字符串就是乱码。通常的错误同样是：简单的认为每“一个字节”就是“一个字符”。而没有根据数据库所选的编码进行转化。</P>
<P>解决的办法通常是：getBytes(<SPAN><FONT color=#ff00ff>"ISO-8859-1"</FONT></SPAN>) 的到原始的字节，再使用正确的编码重新new String()。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>4.4 Tomcat 中，通过 request.getParameter() 获取表单数据时得到乱码</H5>
<P>在 Tomcat 3.3 以前，request.getParameter() 所得到的字符串，都是以每“一个字节”就是“一个字符”的方式返回的。从页面提交到 Tomcat 服务器的中文内容，request.getParameter() 得到的字符串都是乱码。</P>
<P>要得到正确的中文字符串，只能是使用 getBytes(<SPAN><FONT color=#ff00ff>"ISO-8859-1"</FONT></SPAN>) 的到原始的“字节串”，再按照正确的编码重新 new String()。这个乱码问题的产生，是由 Tomcat 自身引起的，采用 <SPAN><FONT color=#0000ff>new</FONT></SPAN> <SPAN><FONT color=#ff0000>String</FONT></SPAN>(str.getBytes(<SPAN><FONT color=#ff00ff>"ISO-8859-1"</FONT></SPAN>), <SPAN><FONT color=#ff00ff>"GB2312"</FONT></SPAN>) 这样的用法也是迫不得已。</P>
<P>从 Tomcat 4 以后，request 中增加了一个新的接口方法：request.setCharsetEncoding()。这个方法的作用是：在调用 request.getParameter() 之前，设定与提交页面相同的编码，则可以使 request.getParameter() 返回正确的字符串。</P>
<P>进行实际测试，对于以下的 JSP 页面： 
<TABLE cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TD><SPAN style="BACKGROUND-COLOR: #ffff00"><%</SPAN><BR>request.setCharacterEncoding(<SPAN><FONT color=#ff00ff>"GB2312"</FONT></SPAN>);<BR>response.setContentType(<SPAN><FONT color=#ff00ff>"text/html; charset=GB2312"</FONT></SPAN>);<BR><BR><SPAN><FONT color=#ff0000>String</FONT></SPAN> aaa = request.getParameter(<SPAN><FONT color=#ff00ff>"aaa"</FONT></SPAN>);<BR><SPAN><BR><FONT color=#0000ff>if</FONT></SPAN>(aaa != <SPAN><FONT color=#0000ff>null</FONT></SPAN>)<BR>&nbsp; &nbsp; out.print(aaa.length() + <SPAN><FONT color=#ff00ff>"<br>"</FONT></SPAN>);<BR><BR>out.print(aaa);<BR><SPAN style="BACKGROUND-COLOR: #ffff00">%></SPAN><BR><FONT color=#800080><SPAN>
<HR>
</SPAN><BR><SPAN>
</SPAN></FONT><SPAN><FONT color=#ff0000>method</FONT></SPAN><SPAN><FONT color=#0000ff>=POST</FONT></SPAN><SPAN><FONT color=#800080> </FONT></SPAN><SPAN><FONT color=#ff0000>action</FONT></SPAN><SPAN><FONT color=#0000ff>="?"</FONT></SPAN><FONT color=#800080><SPAN>&gt;</SPAN><BR></FONT>&nbsp; <SPAN><FONT color=#800080></FONT></SPAN><SPAN><FONT color=#ff0000>type</FONT></SPAN><SPAN><FONT color=#0000ff>=text</FONT></SPAN><SPAN><FONT color=#800080> </FONT></SPAN><SPAN><FONT color=#ff0000>name</FONT></SPAN><SPAN><FONT color=#0000ff>=aaa</FONT></SPAN><SPAN><FONT color=#800080>&gt;</FONT></SPAN><SPAN><FONT color=#ff0000>type</FONT></SPAN><SPAN><FONT color=#0000ff>=submit</FONT></SPAN><SPAN><FONT color=#800080> </FONT></SPAN><SPAN><FONT color=#ff0000>value</FONT></SPAN><SPAN><FONT color=#0000ff>=POST</FONT></SPAN><FONT color=#800080><SPAN>&gt;</SPAN><BR><SPAN></SPAN><BR><SPAN>
</SPAN></FONT><SPAN><FONT color=#ff0000>method</FONT></SPAN><SPAN><FONT color=#0000ff>=GET</FONT></SPAN><FONT color=#800080><SPAN>&gt;</SPAN><BR></FONT>&nbsp; <SPAN><FONT color=#800080></FONT></SPAN><SPAN><FONT color=#ff0000>type</FONT></SPAN><SPAN><FONT color=#0000ff>=text</FONT></SPAN><SPAN><FONT color=#800080> </FONT></SPAN><SPAN><FONT color=#ff0000>name</FONT></SPAN><SPAN><FONT color=#0000ff>=aaa</FONT></SPAN><SPAN><FONT color=#800080>&gt;</FONT></SPAN><SPAN><FONT color=#ff0000>type</FONT></SPAN><SPAN><FONT color=#0000ff>=submit</FONT></SPAN><SPAN><FONT color=#800080> </FONT></SPAN><SPAN><FONT color=#ff0000>value</FONT></SPAN><SPAN><FONT color=#0000ff>=GET</FONT></SPAN><FONT color=#800080><SPAN>&gt;</SPAN><BR><SPAN></SPAN></FONT></FONT></FONT></SPAN></FONT></FONT></SPAN></TD></TR></TBODY></TABLE></P>
<P>输入中文，进行提交，实际测试结果如下： 
<TABLE cellSpacing=0 cellPadding=3 bgColor=#eeeeee border=1>
<TBODY>
<TR>
<TH noWrap>　</TH>
<TH>
<P>Tomcat 3.3.2</P></TH>
<TH>
<P>Tomcat 4.1.31</P></TH>
<TH>
<P>Tomcat 5.0.28</P></TH>
<TH>
<P>Tomcat 5.5.9</P></TH></TR>
<TR>
<TH noWrap>
<P>POST</P></TH>
<TD>
<P><FONT color=#ff0000>显示乱码<SUP>（1）</SUP></FONT></P></TD>
<TD>
<P>正确显示中文</P></TD>
<TD>
<P>正确显示中文</P></TD>
<TD>
<P>正确显示中文</P></TD></TR>
<TR>
<TH noWrap>
<P>GET</P></TH>
<TD>
<P><FONT color=#ff0000>显示乱码</FONT></P></TD>
<TD>
<P>正确显示中文</P></TD>
<TD>
<P><FONT color=#ff0000>显示乱码<SUP>（2）</SUP></FONT></P></TD>
<TD>
<P><FONT color=#ff0000>显示乱码</FONT></P></TD></TR></TBODY></TABLE></P>
<P>
<TABLE cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD vAlign=top>
<P>（1）</P></TD>
<TD>
<P>Tomcat 3.3 以前没有 request.setCharacterEncoding() 方法，因此自然得到乱码。</P></TD></TR>
<TR>
<TD vAlign=top>
<P>（2）</P></TD>
<TD>
<P>不知何故，Tomcat 5 以后的 request.setCharacterEncoding() 方法对 GET 方法提交的数据无效，对 POST 提交的数据处理正确。这样的效果还不如 Tomcat 3.3 那样更好。</P></TD></TR></TBODY></TABLE></P>
<P>大多数浏览器都支持的脚本方法 escape()，可以采用汉字的 UNICODE 序号将汉字转化成 %uXXXX 的格式用来提交到服务器。但 Tomcat 的 request.getParameter() 方法不支持这种格式。</P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><IMG height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></TD></TR>
<TR vAlign=top>
<TD align=right width="100%">
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR align=right>
<TD>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></TD>
<TD vAlign=top align=right>
<P><A href="http://www.regexlab.com/zh/encoding.htm#main">回页首</A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<H5><A></A>4.5 打开电子邮件，标题或者内容不能正常显示</H5>
<P>电子邮件与其它场合不同点就是，除了有“字符编码”外，还有“传输编码”（Content-Transfer-Encoding）。邮件内容中编码的指定方法是：在 MIME 格式的头部分别指定 charset 和 Content-Transfer-Encoding。邮件标题中编码的指定方法是：=?xxx?B?xxxxxxx?= 格式，在一行中简单明了的描述了两种类型的编码以及编码后的标题内容。</P>
<P>如果遇到显示乱码，一种可能是：未指定“字符编码”和“传输编码”，直接将ANSI编码的“字节流”使用在邮件中。另一种可能是：指定了错误的字符编码。</P>
<P>不可避免我们有时会收到一些不规范的电子邮件，解决的办法只能是，选择正确的编码方式来查看。我们在发送邮件的时候，尽可能的按照规范，正确指定“字符编码”和“传输编码”。</P>
<P style="TEXT-INDENT: 2em">&nbsp;</P></div>]]></description>
	    <author><![CDATA[lklkdawei]]></author>
	    <comments>http://lklkdawei.blog.163.com/blog/static/32574109200882492012743</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://lklkdawei.blog.163.com/blog/static/32574109200882492012743</guid>
    <pubDate>Wed, 24 Sep 2008 09:20:12 +0800</pubDate>
    <dcterms:modified>2008-09-24T09:20:12+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[malloc函数的一种简单的原理性实现[转]]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/32574109200881445518891</link>
    <description><![CDATA[<div><P><STRONG><FONT color=#0000ff>malloc（）是C语言中动态存储管理的一组标准库函数之一。其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数，返回值是一个指向所分配的连续存储域的起始地址的指针</FONT></STRONG></P>
<P><STRONG>malloc（）工作机制</STRONG></P>
<P><FONT color=#0000ff><STRONG>　　</STRONG></FONT>malloc函数的实质体现在，它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时，它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后，将该内存块一分为二（一块的大小与用户请求的大小相等，另一块的大小就是剩下的字节）。接下来，将分配给用户的那块内存传给用户，并将剩下的那块（如果有的话）返回到连接表上。调用free函数时，它将用户释放的内存块连接到空闲链上。到最后，空闲链会被切成很多的小内存片段，如果这时用户申请一个大的内存片段，那么空闲链上可能没有可以满足用户要求的片段了。于是，malloc函数请求延时，并开始在空闲链上翻箱倒柜地检查各内存片段，对它们进行整理，将相邻的小空闲块合并成较大的内存块。&nbsp;</P>
<P>malloc（）在操作系统中的实现</P>
<P>　　在 C 程序中，多次使用malloc () 和 free()。不过，您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码，来帮助说明管理内存时都涉及到了哪些事情。<BR>　　在大部分操作系统中，内存分配由以下两个简单的函数来处理：<BR>　　void *malloc (long numbytes)：该函数负责分配 numbytes 大小的内存，并返回指向第一个字节的指针。<BR>　　void free(void *firstbyte)：如果给定一个由先前的 malloc 返回的指针，那么该函数会将分配的空间归还给进程的“空闲空间”。</P>
<P>　　malloc_init 将是初始化内存分配程序的函数。它要完成以下三件事：将分配程序标识为已经初始化，找到系统中最后一个有效内存地址，然后建立起指向我们管理的内存的指针。这三个变量都是全局变量：</P><BR><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top twffan="done"><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">清单&nbsp;1.&nbsp;我们的简单分配程序的全局变量</SPAN><SPAN style="COLOR: #008000"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top twffan="done"></SPAN><SPAN style="COLOR: #000000"><BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top twffan="done">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;has_initialized&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top twffan="done">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">managed_memory_start;<BR><IMG alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align=top twffan="done">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">last_valid_address;</SPAN> 
<P>如前所述，被映射的内存的边界（最后一个有效地址）常被称为系统中断点或者 当前中断点。在很多 UNIX? 系统中，为了指出当前系统中断点，必须使用 sbrk(0) 函数。 sbrk 根据参数中给出的字节数移动当前系统中断点，然后返回新的系统中断点。使用参数 0 只是返回当前中断点。这里是我们的 malloc 初始化代码，它将找到当前中断点并初始化我们的变量：</P><BR><BR><SPAN style="COLOR: #000000">清单&nbsp;</SPAN><SPAN style="COLOR: #000000">2</SPAN><SPAN style="COLOR: #000000">.&nbsp;分配程序初始化函数<BR></SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Include&nbsp;the&nbsp;sbrk&nbsp;function&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;<BR>#include&nbsp;<BR></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;malloc_init()<BR>{<BR></SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;grab&nbsp;the&nbsp;last&nbsp;valid&nbsp;address&nbsp;from&nbsp;the&nbsp;OS&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>last_valid_address&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;sbrk(</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">);<BR></SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;we&nbsp;don''t&nbsp;have&nbsp;any&nbsp;memory&nbsp;to&nbsp;manage&nbsp;yet,&nbsp;so<BR>&nbsp;*just&nbsp;set&nbsp;the&nbsp;beginning&nbsp;to&nbsp;be&nbsp;last_valid_address<BR>&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>managed_memory_start&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;last_valid_address;<BR></SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Okay,&nbsp;we''re&nbsp;initialized&nbsp;and&nbsp;ready&nbsp;to&nbsp;go&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;has_initialized&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">;<BR>}</SPAN> 
<P>现在，为了完全地管理内存，我们需要能够追踪要分配和回收哪些内存。在对内存块进行了 free 调用之后，我们需要做的是诸如将它们标记为未被使用的等事情，并且，在调用 malloc 时，我们要能够定位未被使用的内存块。因此， malloc 返回的每块内存的起始处首先要有这个结构：</P><BR><BR><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">清单&nbsp;3.&nbsp;内存控制块结构定义</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000">&nbsp;mem_control_block&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;is_available;<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;size;<BR>};</SPAN> 
<P>现在，您可能会认为当程序调用 malloc 时这会引发问题 —— 它们如何知道这个结构？答案是它们不必知道；在返回指针之前，我们会将其移动到这个结构之后，把它隐藏起来。这使得返回的指针指向没有用于任何其他用途的内存。那样，从调用程序的角度来看，它们所得到的全部是空闲的、开放的内存。然后，当通过 free() 将该指针传递回来时，我们只需要倒退几个内存字节就可以再次找到这个结构。</P>
<P>　　在讨论分配内存之前，我们将先讨论释放，因为它更简单。为了释放内存，我们必须要做的惟一一件事情就是，获得我们给出的指针，回退 sizeof(struct mem_control_block) 个字节，并将其标记为可用的。这里是对应的代码：</P><BR><BR><SPAN style="COLOR: #000000">清单&nbsp;</SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">.&nbsp;解除分配函数<BR></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;free(</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">firstbyte)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000">&nbsp;mem_control_block&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">mcb;<BR></SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Backup&nbsp;from&nbsp;the&nbsp;given&nbsp;pointer&nbsp;to&nbsp;find&nbsp;the<BR>&nbsp;*&nbsp;mem_control_block<BR>&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;mcb&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;firstbyte&nbsp;</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">sizeof</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000">&nbsp;mem_control_block);<BR></SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Mark&nbsp;the&nbsp;block&nbsp;as&nbsp;being&nbsp;available&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;mcb</SPAN><SPAN style="COLOR: #000000">-&gt;</SPAN><SPAN style="COLOR: #000000">is_available&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;That''s&nbsp;It!&nbsp;&nbsp;We''re&nbsp;done.&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">;<BR>}</SPAN> 
<P>如您所见，在这个分配程序中，内存的释放使用了一个非常简单的机制，在固定时间内完成内存释放。分配内存稍微困难一些。我们主要使用连接的指针遍历内存来寻找开放的内存块。这里是代码：</P><BR><BR><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">清单&nbsp;6.&nbsp;主分配程序</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">malloc(</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">&nbsp;numbytes)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Holds&nbsp;where&nbsp;we&nbsp;are&nbsp;looking&nbsp;in&nbsp;memory&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">current_location;<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;This&nbsp;is&nbsp;the&nbsp;same&nbsp;as&nbsp;current_location,&nbsp;but&nbsp;cast&nbsp;to&nbsp;a<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;memory_control_block<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000">&nbsp;mem_control_block&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">current_location_mcb;<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;This&nbsp;is&nbsp;the&nbsp;memory&nbsp;location&nbsp;we&nbsp;will&nbsp;return.&nbsp;&nbsp;It&nbsp;will<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;be&nbsp;set&nbsp;to&nbsp;0&nbsp;until&nbsp;we&nbsp;find&nbsp;something&nbsp;suitable<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">memory_location;<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Initialize&nbsp;if&nbsp;we&nbsp;haven''t&nbsp;already&nbsp;done&nbsp;so&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">!</SPAN><SPAN style="COLOR: #000000">&nbsp;has_initialized)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;malloc_init();<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;The&nbsp;memory&nbsp;we&nbsp;search&nbsp;for&nbsp;has&nbsp;to&nbsp;include&nbsp;the&nbsp;memory<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;control&nbsp;block,&nbsp;but&nbsp;the&nbsp;users&nbsp;of&nbsp;malloc&nbsp;don''t&nbsp;need<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;to&nbsp;know&nbsp;this,&nbsp;so&nbsp;we''ll&nbsp;just&nbsp;add&nbsp;it&nbsp;in&nbsp;for&nbsp;them.<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;numbytes&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;numbytes&nbsp;</SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">sizeof</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000">&nbsp;mem_control_block);<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Set&nbsp;memory_location&nbsp;to&nbsp;0&nbsp;until&nbsp;we&nbsp;find&nbsp;a&nbsp;suitable<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;location<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;memory_location&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Begin&nbsp;searching&nbsp;at&nbsp;the&nbsp;start&nbsp;of&nbsp;managed&nbsp;memory&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;current_location&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;managed_memory_start;<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Keep&nbsp;going&nbsp;until&nbsp;we&nbsp;have&nbsp;searched&nbsp;all&nbsp;allocated&nbsp;space&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">while</SPAN><SPAN style="COLOR: #000000">(current_location&nbsp;</SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000">&nbsp;last_valid_address)<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;current_location&nbsp;and&nbsp;current_location_mcb&nbsp;point<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;to&nbsp;the&nbsp;same&nbsp;address.&nbsp;&nbsp;However,&nbsp;current_location_mcb<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;is&nbsp;of&nbsp;the&nbsp;correct&nbsp;type,&nbsp;so&nbsp;we&nbsp;can&nbsp;use&nbsp;it&nbsp;as&nbsp;a&nbsp;struct.<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;current_location&nbsp;is&nbsp;a&nbsp;void&nbsp;pointer&nbsp;so&nbsp;we&nbsp;can&nbsp;use&nbsp;it<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;to&nbsp;calculate&nbsp;addresses.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current_location_mcb&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000">&nbsp;mem_control_block&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">)current_location;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(current_location_mcb</SPAN><SPAN style="COLOR: #000000">-&gt;</SPAN><SPAN style="COLOR: #000000">is_available)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(current_location_mcb</SPAN><SPAN style="COLOR: #000000">-&gt;</SPAN><SPAN style="COLOR: #000000">size&nbsp;</SPAN><SPAN style="COLOR: #000000">&gt;=</SPAN><SPAN style="COLOR: #000000">&nbsp;numbytes)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Woohoo!&nbsp;&nbsp;We''ve&nbsp;found&nbsp;an&nbsp;open,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;appropriately-size&nbsp;location.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;It&nbsp;is&nbsp;no&nbsp;longer&nbsp;available&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current_location_mcb</SPAN><SPAN style="COLOR: #000000">-&gt;</SPAN><SPAN style="COLOR: #000000">is_available&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;We&nbsp;own&nbsp;it&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memory_location&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;current_location;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Leave&nbsp;the&nbsp;loop&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">break</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;If&nbsp;we&nbsp;made&nbsp;it&nbsp;here,&nbsp;it''s&nbsp;because&nbsp;the&nbsp;Current&nbsp;memory<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;block&nbsp;not&nbsp;suitable;&nbsp;move&nbsp;to&nbsp;the&nbsp;next&nbsp;one<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current_location&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;current_location&nbsp;</SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current_location_mcb</SPAN><SPAN style="COLOR: #000000">-&gt;</SPAN><SPAN style="COLOR: #000000">size;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;If&nbsp;we&nbsp;still&nbsp;don''t&nbsp;have&nbsp;a&nbsp;valid&nbsp;location,&nbsp;we''ll<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;have&nbsp;to&nbsp;ask&nbsp;the&nbsp;operating&nbsp;system&nbsp;for&nbsp;more&nbsp;memory<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">!</SPAN><SPAN style="COLOR: #000000">&nbsp;memory_location)<BR>&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Move&nbsp;the&nbsp;program&nbsp;break&nbsp;numbytes&nbsp;further&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sbrk(numbytes);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;The&nbsp;new&nbsp;memory&nbsp;will&nbsp;be&nbsp;where&nbsp;the&nbsp;last&nbsp;valid<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;address&nbsp;left&nbsp;off<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memory_location&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;last_valid_address;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;We''ll&nbsp;move&nbsp;the&nbsp;last&nbsp;valid&nbsp;address&nbsp;forward<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;numbytes<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;last_valid_address&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;last_valid_address&nbsp;</SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000">&nbsp;numbytes;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;We&nbsp;need&nbsp;to&nbsp;initialize&nbsp;the&nbsp;mem_control_block&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current_location_mcb&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;memory_location;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current_location_mcb</SPAN><SPAN style="COLOR: #000000">-&gt;</SPAN><SPAN style="COLOR: #000000">is_available&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current_location_mcb</SPAN><SPAN style="COLOR: #000000">-&gt;</SPAN><SPAN style="COLOR: #000000">size&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;numbytes;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Now,&nbsp;no&nbsp;matter&nbsp;what&nbsp;(well,&nbsp;except&nbsp;for&nbsp;error&nbsp;conditions),<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;memory_location&nbsp;has&nbsp;the&nbsp;address&nbsp;of&nbsp;the&nbsp;memory,&nbsp;including<BR>&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;the&nbsp;mem_control_block<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Move&nbsp;the&nbsp;pointer&nbsp;past&nbsp;the&nbsp;mem_control_block&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;memory_location&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;memory_location&nbsp;</SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">sizeof</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #0000ff">struct</SPAN><SPAN style="COLOR: #000000">&nbsp;mem_control_block);<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">/*</SPAN><SPAN style="COLOR: #008000">&nbsp;Return&nbsp;the&nbsp;pointer&nbsp;</SPAN><SPAN style="COLOR: #008000">*/</SPAN><SPAN style="COLOR: #000000"><BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;memory_location;<BR>&nbsp;}</SPAN> 
<P>这就是我们的内存管理器。现在，我们只需要构建它，并在程序中使用它即可.多次调用malloc（）后空闲内存被切成很多的小内存片段，这就使得用户在申请内存使用时，由于找不到足够大的内存空间，malloc（）需要进行内存整理，使得函数的性能越来越低。聪明的程序员通过总是分配大小为2的幂的内存块，而最大限度地降低潜在的malloc性能丧失。也就是说，所分配的内存块大小为4字节、8字节、16字节、18446744073709551616字节，等等。这样做最大限度地减少了进入空闲链的怪异片段（各种尺寸的小片段都有）的数量。尽管看起来这好像浪费了空间，但也容易看出浪费的空间永远不会超过50%。</P>
<P>&nbsp;</P>
<P>---------------------------------------------------------------------------------------------</P>
<P>malloc函数 <BR>函数声明(函数原型)： <BR>void *malloc(int size); <BR>说明：malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定，void* 类型可以强制转换为任何其它类型的指针。 <BR>从函数声明上可以看出。malloc 和 new 至少有两个不同: new 返回指定类型的指针，并且可以自动计算所需要大小。比如： <BR>int *p; <BR>p = new int; //返回类型为int* 类型(整数型指针)，分配大小为 sizeof(int); <BR>或： <BR>int* parr; <BR>parr = new int [100]; //返回类型为 int* 类型(整数型指针)，分配大小为 sizeof(int) * 100; <BR>而 malloc 则必须由我们计算要字节数，并且在返回后强行转换为实际类型的指针。 <BR>int* p; <BR>p = (int *) malloc (sizeof(int)); <BR>第一、malloc 函数返回的是 void * 类型，如果你写成：p = malloc (sizeof(int)); 则程序无法通过编译，报错：“不能将 void* 赋值给 int * 类型变量”。所以必须通过 (int *) 来将强制转换。 <BR>第二、函数的实参为 sizeof(int) ，用于指明一个整型数据需要的大小。如果你写成： <BR>int* p = (int *) malloc (1); <BR>代码也能通过编译，但事实上只分配了1个字节大小的内存空间，当你往里头存入一个整数，就会有3个字节无家可归，而直接“住进邻居家”！造成的结果是后面的内存中原有数据内容全部被清空。 <BR>malloc 也可以达到 new [] 的效果，申请出一段连续的内存，方法无非是指定你所需要内存大小。 <BR>比如想分配100个int类型的空间： <BR>int* p = (int *) malloc ( sizeof(int) * 100 ); //分配可以放得下100个整数的内存空间。 <BR>另外有一点不能直接看出的区别是，malloc 只管分配内存，并不能对所得的内存进行初始化，所以得到的一片新内存中，其值将是随机的。 <BR>除了分配及最后释放的方法不一样以外，通过malloc或new得到指针，在其它操作上保持一致。</CN> </P>
<P>&nbsp;</P>
<P>--------------------------------------------------------------------------------------------</P>
<P>有了malloc/free 为什么还要new/delete ？<BR>malloc 与free 是C++/C 语言的标准库函数，new/delete 是C++的运算符。它们都可<BR>用于申请动态内存和释放内存。<BR>对于非内部数据类型的对象而言，光用maloc/free 无法满足动态对象的要求。对象<BR>在创建的同时要自动执行构造函数， 对象在消亡之前要自动执行析构函数。由于<BR>malloc/free 是库函数而不是运算符，不在编译器控制权限之内，不能够把执行构造函数<BR>和析构函数的任务强加于malloc/free。<BR>因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new，以及一个<BR>能完成清理与释放内存工作的运算符delete。注意new/delete 不是库函数。<BR>我们先看一看malloc/free 和new/delete 如何实现对象的动态内存管理，见示例7-8。<BR>class Obj<BR>{<BR>public :<BR>Obj(void){ cout &lt;&lt; “Initialization” &lt;&lt; endl; }<BR>~Obj(void){ cout &lt;&lt; “Destroy” &lt;&lt; endl; }<BR>void Initialize(void){ cout &lt;&lt; “Initialization” &lt;&lt; endl; }<BR>void Destroy(void){ cout &lt;&lt; “Destroy” &lt;&lt; endl; }<BR>};<BR>void UseMallocFree(void)<BR>{<BR>Obj *a = (obj *)malloc(sizeof(obj)); // 申请动态内存<BR>a-&gt;Initialize(); // 初始化<BR>//…<BR>a-&gt;Destroy(); // 清除工作<BR>free(a); // 释放内存<BR>}<BR>void UseNewDelete(void)<BR>{<BR>Obj *a = new Obj; // 申请动态内存并且初始化<BR>//…<BR>delete a; // 清除并且释放内存<BR>}<BR>示例7-8 用malloc/free 和new/delete 如何实现对象的动态内存管理<BR>类Obj 的函数Initialize 模拟了构造函数的功能，函数Destroy 模拟了析构函数的功<BR>能。函数UseMallocFree 中，由于malloc/free 不能执行构造函数与析构函数，必须调用<BR>成员函数Initialize 和Destroy 来完成初始化与清除工作。函数UseNewDelete 则简单得</P>
<P>多。<BR>所以我们不要企图用malloc/free 来完成动态对象的内存管理，应该用new/delete。<BR>由于内部数据类型的“ 对象”没有构造与析构的过程，对它们而言malloc/free 和<BR>new/delete 是等价的。<BR>既然new/delete 的功能完全覆盖了malloc/free，为什么C++不把malloc/free 淘<BR>汰出局呢？这是因为C++程序经常要调用C 函数，而C 程序只能用malloc/free 管理动<BR>态内存。<BR>如果用free 释放“new 创建的动态对象”，那么该对象因无法执行析构函数而可能<BR>导致程序出错。如果用delete 释放“malloc 申请的动态内存”，理论上讲程序不会出错，<BR>但是该程序的可读性很差。所以new/delete 必须配对使用，malloc/free 也一样。<BR></P></div>]]></description>
	    <author><![CDATA[lklkdawei]]></author>
	    <comments>http://lklkdawei.blog.163.com/blog/static/32574109200881445518891</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://lklkdawei.blog.163.com/blog/static/32574109200881445518891</guid>
    <pubDate>Sun, 14 Sep 2008 16:55:18 +0800</pubDate>
    <dcterms:modified>2008-09-14T16:58:31+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[今天，我种下了一朵小红花]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/3257410920088149544756</link>
    <description><![CDATA[<div>今天，我在网易花园里为々駌鴦戯氺々种了一朵小红花。希望它给我们带来幸福和爱，直到永远...
<div style="text-align: center;">
	<embed src="http://iou.163.com/loveGarden/swf/card.swf" flashVars="url=http://iou.163.com/flowerInBlog/32574109/1737551/" quality="high" bgcolor="#ffffff" width="600" height="400" wmode="transparent"  align="middle"  allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</div>
<div style="text-align: center;">
	<img style="width: 184px; height: 78px;margin-right:10px;" src="http://img.blog.163.com/photo/6gu9J6u0Gyp_5KXSVa3I_w==/1420604207459534393.jpg">
	<a href="http://iou.163.com/?centerId=1737551" target="_blank" style="top: -18px; ; font-size: 12px;">去花园广场看花&gt;&gt;</a>
</div></div>]]></description>
	    <author><![CDATA[lklkdawei]]></author>
	    <comments>http://lklkdawei.blog.163.com/blog/static/3257410920088149544756</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://lklkdawei.blog.163.com/blog/static/3257410920088149544756</guid>
    <pubDate>Sun, 14 Sep 2008 09:54:04 +0800</pubDate>
    <dcterms:modified>2008-09-14T09:54:04+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[把文件存储到数据库【转】]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/32574109200884113566</link>
    <description><![CDATA[<div><P>我们可以把任意类型的文件保存到SQL Server中，在进行例子之前，先建立测试用表格，TestFile.sql：</P>if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[TestFiles]')
  and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[TestFiles]
GO

CREATE TABLE [dbo].[TestFiles] (
 [id] [int] IDENTITY (1, 1) NOT NULL ,
 [MyFileName] [varchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL ,
 [FileType] [varchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL ,
 [MyFile] [image] NOT NULL 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

<P>下面创建上传表单：</P>
<P>一旦提交了表单，我们使用<B>HtmlInputFile</B>类的<B>PostedFile</B>属性来访问我们上载的文件，用<B>HttpPostedFile</B>类的属性和方法来进行读取、保存上载文件和得到上载文件的其它信息。这里我们不使用<B>SaveAs</B>方法，因为它是用来保存文件的。我们要把数据保存到数据库中，我们使用<B>InputStream</B>属性，它用来初始化流来读取我们的数据。同时，我们使用<B>ContentLength</B>来读取文件大小，<B>ContentType</B>读取文件类型。然后创建byte数组，把文件流保存进该数组，然后保存到数据库即可。</P>
<P>&nbsp;</P>
<P>保存-----------------------------</P>
<P>public static Connection conn(){<BR>&nbsp;&nbsp;Connection con = null;<BR>&nbsp;&nbsp;try {<BR>&nbsp;&nbsp;&nbsp;Class.forName("com.mysql.jdbc.Driver");<BR>&nbsp;&nbsp;&nbsp;con = DriverManager.getConnection("jdbc:mysql://localhost:3306/filedb", "root", "root");<BR>&nbsp;&nbsp;&nbsp;return con;<BR>&nbsp;&nbsp;} catch (Exception e) {<BR>&nbsp;&nbsp;&nbsp;e.printStackTrace();<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;return null;<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;public static void storeDB(String strFile)throws Exception{<BR>&nbsp;&nbsp;File file = new File(strFile);<BR>&nbsp;&nbsp;String name = file.getName();<BR>&nbsp;&nbsp;String type = name.substring(name.lastIndexOf("."), name.length());<BR>&nbsp;&nbsp;long size = file.length();<BR>&nbsp;&nbsp;byte[] bye = new byte[new Long(size).intValue()];<BR>&nbsp;&nbsp;FileInputStream fi = new FileInputStream(file);<BR>&nbsp;&nbsp;fi.read(bye, 0, new Long(size).intValue());<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;PreparedStatement pstmt = null;<BR>&nbsp;&nbsp;String strSql = "insert into filetable(name,size,type,data)values(?,?,?,?);";<BR>&nbsp;&nbsp;try{<BR>&nbsp;&nbsp;&nbsp;pstmt = conn().prepareStatement(strSql);<BR>&nbsp;&nbsp;&nbsp;pstmt.setString(1,name);<BR>&nbsp;&nbsp;&nbsp;pstmt.setLong(2, size);<BR>&nbsp;&nbsp;&nbsp;pstmt.setString(3, type);<BR>&nbsp;&nbsp;&nbsp;pstmt.setBytes(4, bye);<BR>&nbsp;&nbsp;&nbsp;System.out.println(pstmt.executeUpdate());<BR>&nbsp;&nbsp;}catch(Exception e){<BR>&nbsp;&nbsp;&nbsp;System.out.println("失败");<BR>&nbsp;&nbsp;&nbsp;e.printStackTrace();<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;System.out.println("插入成功");<BR>&nbsp;}</P>
<P>&nbsp;</P>
<P>&nbsp;</P>
<P>一旦我们上载成功，我们可以对文件进行浏览：只需要设置页面的MIME类型，然后用<B>Response</B>对象的<B>BinaryWrite()</B>进行输出。</P>
<P>&nbsp;</P>
<P>加载：</P>
<P>public static void loadFile(){<BR>&nbsp;&nbsp;PreparedStatement pstmt = null;<BR>&nbsp;&nbsp;ResultSet rs = null;<BR>&nbsp;&nbsp;String strSql = "select id,name,size,type,data from filetable where id = 3;";<BR>&nbsp;&nbsp;String name = "";<BR>&nbsp;&nbsp;String type = "";<BR>&nbsp;&nbsp;long size = 0;<BR>&nbsp;&nbsp;byte [] bye = null;<BR>&nbsp;&nbsp;try{<BR>&nbsp;&nbsp;&nbsp;pstmt = conn().prepareStatement(strSql);<BR>&nbsp;&nbsp;&nbsp;rs = pstmt.executeQuery();<BR>&nbsp;&nbsp;&nbsp;while(rs.next()){<BR>&nbsp;&nbsp;&nbsp;&nbsp;name = rs.getString("name");<BR>&nbsp;&nbsp;&nbsp;&nbsp;type = rs.getString("type");<BR>&nbsp;&nbsp;&nbsp;&nbsp;size = rs.getLong("size");<BR>&nbsp;&nbsp;&nbsp;&nbsp;bye = new byte[new Long(size).intValue()];<BR>&nbsp;&nbsp;&nbsp;&nbsp;bye = rs.getBytes("data");<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;System.out.println("数据操作完毕");<BR>&nbsp;&nbsp;File file = new File("f:\\"+name);<BR>&nbsp;&nbsp;FileOutputStream fo = new FileOutputStream(file);<BR>&nbsp;&nbsp;fo.write(bye, 0, new Long(size).intValue());<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;fo.flush();<BR>&nbsp;&nbsp;fo.close();<BR>&nbsp;&nbsp;}catch(Exception e){<BR>&nbsp;&nbsp;&nbsp;System.out.println("失败");<BR>&nbsp;&nbsp;&nbsp;e.printStackTrace();<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;System.out.println("加载文件成功");<BR>&nbsp;}</P>
<P>&nbsp;</P>
<P>&nbsp;</P></div>]]></description>
	    <author><![CDATA[lklkdawei]]></author>
	    <comments>http://lklkdawei.blog.163.com/blog/static/32574109200884113566</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://lklkdawei.blog.163.com/blog/static/32574109200884113566</guid>
    <pubDate>Thu, 4 Sep 2008 13:01:35 +0800</pubDate>
    <dcterms:modified>2008-09-04T13:01:35+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[HtmlParser初步研究 [转]]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/3257410920088344013838</link>
    <description><![CDATA[<div>这两天准备做一些网站编程的工作，于是对HtmlParse小研究了一下，目的是快速入手，而不是深入研究，做了一下整理，和大家共同讨论一下。
<DIV>&nbsp;</DIV>
<DIV>一，数据组织分析：</DIV>
<P>HtmlParser主要靠Node、AbstractNode和<WBR>Tag来表达Html，因为Remark和Text相对简单<WBR>，此处就将其忽略了。</WBR></WBR></P>
<UL>
<LI>Node是形成树结构表示HTML的基础，所有的数据表示都是接口<WBR>Node的实现，Node定义了与页面树结构所表达的页面Page<WBR>对象，定义了获取父、子、兄弟节点的方法，定义了节点到对应htm<WBR>l文本的方法，定义了该节点对应的起止位置，定义了过滤方法<WBR>，定义了Visitor访问机制。</WBR></WBR></WBR></WBR> 
</LI><LI>AbstractNode是Node的一种具体的类实现<WBR>，起到构成树形结构的作用，除了同具体Node相关的accetp<WBR>方法，toString，toHtml，toPlainTextS<WBR>tring方法以外，AbstractNode实现了大多基本的方<WBR>法，使得它的子类，不用理会具体的树操作。</WBR></WBR></WBR></WBR> 
</LI><LI>Tag是具体分析的主要内容。Tag分成composite的Ta<WBR>g和不能包含其他Tag的简单Tag两类，其中前者的基类是Compo<WBR>siteTag，其子类包含BodyTag,Div<WBR>,FrameSetTag,OptionTag，等27个子类<WBR>；而简单Tag有BaseHrefTag<WBR>、DoctypeTag,FrameTag，ImageTag<WBR>，InputTag，JspTag，MetaTag<WBR>，ProcessingInstructionTag这八类。 </WBR></WBR></WBR></WBR></WBR></WBR></WBR></LI></UL>
<P>Node分成三类：</P>
<UL>
<LI>RemarkNode:代表Html中的注释 
</LI><LI>TagNode：标签节点，是种类最多的节点类型，上述Tag的具体节点类都是TagNode的实现。 
</LI><LI>TextNode：文本节点 </LI></UL>
<DIV>&nbsp;</DIV>
<DIV>二，Visitor方式访问Html：</DIV>
<DIV>&nbsp;</DIV>
<DIV>1，整体解析过程</DIV>
<UL>
<LI>用一个URL或页面String做一个Parser 
</LI><LI>用这个Parser做一个Visitor 
</LI><LI>使用Parser.visitAllNodeWith(Visitor)来遍历节点 
</LI><LI>获取Visitor遍历后得到的数据 </LI></UL>
<DIV>2，Visit过程</DIV>
<UL>
<LI>做解析之前做的事情：visitor.beginParsing<WBR>();</WBR> 
</LI><LI>每次取到一个节点Node，让该Node接受accept该Vis<WBR>itor</WBR> 
</LI><LI>做解析后做的事情：visitor.finishedParsin<WBR>g();</WBR> </LI></UL>
<DIV>3，获取节点的过程：逐步遍历Html，分析出Node<WBR>。此部分较为复杂，且对于我们应用来说无需很多了解，暂跳过。</WBR></DIV>
<DIV>&nbsp;</DIV>
<DIV>4，节点访问</DIV>
<DIV>节点访问采用Visitor模式，Node的accept方法和具<WBR>体Visitor的visit方法是关键。</WBR></DIV>
<DIV>首先三类Node来accept的方式各不相同：</DIV>
<UL>
<LI>对于所有TagNode都使用一个accept方法<WBR>，即TagNode的accept方法。首先判断是否是标签结尾<WBR>，如果是就visitor.visitEndTag (this)；否则visitor.visitTag (this);</WBR></WBR> 
</LI><LI>如果是TextNode，那就visitor.visitStri<WBR>ngNode (this);就可以了。</WBR> 
</LI><LI>如果是RemarkNode，那就visitor<WBR>.visitRemarkNode (this);就可以了。</WBR> </LI></UL>
<P><BR>实际上NodeVisitor里边这四种visit方法都是空的<WBR>，因为在不同的Visitor中对于这三类节点的处理是不同的<WBR>；对于需要处理的节点，只要重载对应的visit方法就行了<WBR>，如果不处理那就不理会就可以了；另外，如果用户用自己的Visi<WBR>tor，那么还可以灵活的处理不同类型的节点了。</WBR></WBR></WBR></WBR></P>
<DIV>系统为我们实现了下面我要介绍的8种Visitor<WBR>，实际上可以看作是系统给我们演示了如何做各种各样的Visito<WBR>r来访问Html，因为实际上我们要真正来用HtmlParser<WBR>的话，还需要特定的Visitor，而通过简单的这些系统提供的V<WBR>isitor组合是难以做成什么事情的。</WBR></WBR></WBR></WBR></DIV>
<DIV>&nbsp;</DIV>
<DIV>三，系统Visitor功能简介：</DIV>
<UL>
<LI>ObjectFindingVisitor：用来找出所有指定类型<WBR>的节点，采用getTags()来获取结果。</WBR> 
</LI><LI>StringBean：用来从一个指定的URL获取移除了<WBR>&lt;SCRIPT&gt;&lt;/SCRIPT&gt;和&lt;PRE&gt;&lt;/PRE<WBR>&gt;之间代码的Html代码，也可以用做Visitor<WBR>，用来移除这两种标签内部的代码，采用StringBean<WBR>.getStrings()来获取结果。</WBR></WBR></WBR></WBR> 
</LI><LI>HtmlPage：提取Title，body中的节点和页面中的T<WBR>ableTag节点。</WBR> 
</LI><LI>LinkFindingVisitor:找出节点中包含某个链接的<WBR>总个数。</WBR> 
</LI><LI>StringFindingVisitor：找出遍历的TextN<WBR>ode中含有指定字符串的个数。</WBR> 
</LI><LI>TagFindingVisitor：找出指定Tag的所有节点<WBR>，可以指定多种类型。</WBR> 
</LI><LI>TextExtractingVisitor：从网页中把所有标签<WBR>去掉来提取文本，这个提取文本的Visitor有时是很实用的<WBR>，只是注意在提取文本时将标签的属性也去掉了，也就是说只剩下标签<WBR>之间的文本，例如&lt;a&gt;中的链接也去掉了。</WBR></WBR></WBR> 
</LI><LI>UrlModifyingVisitor：用来修改网页中的链接。<A></A> </LI></UL>
<DIV>四，Filter</DIV>
<DIV>&nbsp;</DIV>
<DIV>如果说visitor是遍历提取信息，当然这个信息可以包括某些节点或者从节点分析出来的更有效的信息，这都取决于我们的Visitor做成什么样子，那么Filter则目标很明确，就是用来提取节点的。所以说要想用HtmlParser，首先要熟悉上面讲到的数据组织。</DIV>
<DIV>&nbsp;</DIV>
<DIV>
<DIV>系统定义了17种具体的Filter，包括依据节点父子关系的Filter，连接Filter组合的Filter，依据网页内容匹配情况的filter，等等。我们也可以implement Filter来做自己的Filter来提取节点。</DIV>
<DIV>&nbsp;</DIV></DIV>
<DIV>Filter的调用是同Visitor独立的，因为也无需先filter出一些NodeList，再用Visitor来访问。调用Filter的方法是：</DIV>
<DIV>NodeList nodeList = myParser.parse(someFilter);</DIV>
<DIV>解析之后，我们可以采用：</DIV>
<DIV>Node[] nodes = nodeList.toNodeArray();</DIV>
<DIV>来获取节点数组，也可以直接访问：</DIV>
<DIV>Node node = nodeList.elementAt(i)来获取Node。</DIV>
<DIV>&nbsp;</DIV>
<DIV>另外，在Filter后得到NodeList以后，我们仍然可以使用NodeList的extractAllNodesThatMatch(someFilter)来进一步过滤，同时又可以用NodeList的isitAllNodesWith(someVisitor)来做进一步的访问。</DIV>
<DIV>这样，我们可以看到HtmlParser为我们提供了非常方便的Html解析方式，针对不同的应用可以采用visitor来遍历Html节点提取数据，也可以用Filter来过滤节点，提取出我们所关注的节点，再对节点进行处理。通过这样的组合，一定能够找出我们所需要的信息。</DIV>
<DIV>&nbsp;</DIV>
<DIV>参考：</DIV>
<DIV><A href="http://htmlparser.sourceforge.net/">http://htmlparser.sourceforge.net/</A> </DIV>
<DIV><A href="http://www.blogjava.net/rocky/archive/2005/12/21/24997.aspx">http://www.blogjava.net/rocky/archive/2005/12/21/24997.aspx</A> </DIV>
<DIV><A href="http://www.westing.cn/xblog/?p=90">http://www.westing.cn/xblog/?p=90</A> </DIV></div>]]></description>
	    <author><![CDATA[lklkdawei]]></author>
	    <comments>http://lklkdawei.blog.163.com/blog/static/3257410920088344013838</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://lklkdawei.blog.163.com/blog/static/3257410920088344013838</guid>
    <pubDate>Wed, 3 Sep 2008 16:40:13 +0800</pubDate>
    <dcterms:modified>2008-09-03T16:40:13+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[佛学的181条智慧 献给压抑的IT人[转]]]></title>	
    <link>http://lklkdawei.blog.163.com/blog/static/32574109200871932048520</link>
    <description><![CDATA[<div><P style="TEXT-INDENT: 2em">佛学的181条智慧 献给压抑的IT人</P>
<P style="TEXT-INDENT: 2em">&nbsp;</P>
<P style="TEXT-INDENT: 2em">一、人之所以痛苦，在于追求错误的东西。　 </P>
<P style="TEXT-INDENT: 2em">二、与其说是别人让你痛苦，不如说是自己的修养不够。　 </P>
<P style="TEXT-INDENT: 2em">三、如果你不给自己烦恼，别人也永远不可能给你烦恼。因为在你自己的内心，你放不下。 </P>
<P style="TEXT-INDENT: 2em">四、好好的管教你自己，不要管别人。 </P>
<P style="TEXT-INDENT: 2em">五、不宽恕众生，不原谅众生，是苦了你自己。　 </P>
<P style="TEXT-INDENT: 2em">六、别说别人可怜，自己更可怜，自己又懂得人生多少？　 </P>
<P style="TEXT-INDENT: 2em">七、学佛是对自己的良心交待，不是做给别人看的。 </P>
<P style="TEXT-INDENT: 2em">八、福报不够的人，就会常常听到是非；福报够的人，从来就没听到过是非。　 </P>
<P style="TEXT-INDENT: 2em">九、修行是点滴的工夫。　 </P>
<P style="TEXT-INDENT: 2em">十、在顺境中修行，永远不能成佛。 </P>
<P style="TEXT-INDENT: 2em">十一、你永远要感谢给你逆境的众生。 </P>
<P style="TEXT-INDENT: 2em">十二、你随时要认命，因为你是人。 </P>
<P style="TEXT-INDENT: 2em">十三、你永远都要宽恕众生，不论他有多坏，甚至他伤害过你，你一定要放下，才能得到真正的快乐。 </P>
<P style="TEXT-INDENT: 2em">十四、这个世界本来就是痛苦的，没有例外的。　 </P>
<P style="TEXT-INDENT: 2em">十五、当你快乐时，你要想，这快乐不是永恒的。当你痛苦时你要想这痛苦也不是永恒的。 </P>
<P style="TEXT-INDENT: 2em">十六、认识自己，降伏自己，改变自己，才能改变别人。 </P>
<P style="TEXT-INDENT: 2em">十七、今日的执著，会造成明日的后悔