<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[流水不腐 户枢不蠹]]></title>
        <image>
        <title>http://hi.baidu.com</title>
        <link>http://hi.baidu.com</link>
        <url>http://img.baidu.com/img/logo-hi.gif</url>
        </image>
<description><![CDATA[灵根育孕源流出 心性修持大道生]]></description>
<link>http://hi.baidu.com/dongxiang2007</link>
<language>zh-cn</language>
<generator>www.baidu.com</generator>
<ttl>5</ttl>


<item>
        <title><![CDATA[统计一个Byte中的“1”的个数]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/6fb4e664f8115bfaf73654a6.html]]></link>
        <description><![CDATA[
		
		<p>/*<br>
题目描述：对于一个字节(8bit)的无符号整形变量，求二进制表示中&ldquo;1&rdquo;的个数，要求算法执行效率尽可能地高<br>
*/<br>
#include &lt;windows.h&gt;<br>
#include &lt;iostream&gt;<br>
using namespace std;</p>
<p>int Count(BYTE v);<br>
int main()<br>
{<br>
 BYTE v=255;<br>
 cout&lt;&lt;Count(v);<br>
 return 0;<br>
}</p>
<p>方法一：直接的方法就是除以2向右移位， 逐个统计，但是用到取模和相除，这个很耗资源。<br>
int Count(BYTE v)<br>
{<br>
 int num=0;<br>
 while (v) <br>
 {<br>
&nbsp;&nbsp; if (v%2==1)<br>
&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; num++;<br>
&nbsp;&nbsp; }<br>
&nbsp;&nbsp; v=v/2;<br>
 }<br>
 return num;<br>
}<br>
////////////////////////////////////////////////////////////////////</p>
<p>////////////////////////////////////////////////////////////////////<br>
方法二：使用位操作，除以2可以直接用位操作右移一位来实现，而且计算做位移操作的效率比除法高。<br>
int Count(BYTE v)<br>
{<br>
 int num=0;<br>
 while (v)<br>
 {<br>
&nbsp;&nbsp; num+=v &amp; 0x01; //将v与00000001相与如果v的最后一位是1相与的结果是1，反之则是0。<br>
&nbsp;&nbsp; v&gt;&gt;=1;&nbsp;&nbsp;&nbsp; //右移一位。<br>
 }<br>
 return num;<br>
}<br>
////////////////////////////////////////////////////////////////////</p>
<p>////////////////////////////////////////////////////////////////////<br>
方法三：使用位操作，但是只会去统计1的个数，循环的次数是BYTE中1的个数，无需遍历。<br>
<br>
int Count(BYTE v)<br>
{<br>
 int num=0;<br>
 while (v)<br>
 {<br>
&nbsp;&nbsp; v &amp;=(v-1); //v=v&amp;(v-1)这个操作可以直接消除掉v中的最右边的1。<br>
&nbsp;&nbsp; num++;<br>
 }<br>
 return num;<br>
}</p>
<p>//////////////////////////////////////////////////////////////////////<br>
方法四：查表法，这个的效率应该是最高的了，空间换时间。</p>
<p>int countTable[256]=<br>
{ <br>
 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,<br>
 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,<br>
 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,<br>
 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,<br>
 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,<br>
 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,<br>
 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,<br>
 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,<br>
 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,<br>
 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,<br>
 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,<br>
 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,<br>
 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,<br>
 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,<br>
 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,<br>
 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8<br>
};<br>
int Count(BYTE v)<br>
{<br>
 return countTable[v];<br>
}<br>
这个程序要求效率尽可能的高，这四种方法中显然最后一种的时间复杂度最低了O(1).第一个方法最容易想到确不是最好的答案，第二种有些改进，但还是需要遍历Byte里的所有位，第三种方法只需做n次操作(n是实际Byte中的&ldquo;1&rdquo;的个数)。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;  空间换时间在某些情况下是个好的选择，比如需要频繁使用这个算法的时候，但也不是尽然，还是得视情况而定。</p> <a href="http://hi.baidu.com/dongxiang2007/blog/item/6fb4e664f8115bfaf73654a6.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%D1%A7%CF%B0%C0%E0">学习类</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/6fb4e664f8115bfaf73654a6.html#comment">查看评论</a>]]></description>
        <pubDate>2009年09月24日 星期四  下午 04:29</pubDate>
        <category><![CDATA[学习类]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/6fb4e664f8115bfaf73654a6.html</guid>
</item>

<item>
        <title><![CDATA[OpenSSL应用之公钥算法RSA]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/9aad56d5bff030cd50da4b65.html]]></link>
        <description><![CDATA[
		
		<p><font face="宋体" size="2">&nbsp;&nbsp;&nbsp;&nbsp;  OpenSSL一共实现了4种非对称加密算法，包括DH算法、RSA算法、DSA算法和椭圆曲线算法（EC）。DH算法一般用户密钥交换。RSA算法既可以用于密钥交换，也可以用于数字签名，当然，如果你能够忍受其缓慢的速度，那么也可以用于数据加密。DSA算法则一般只用于数字签名。我想用RSA作为例子来描述Openssl公钥算法的实现过程。</font></p>
<p><font face="宋体" size="2">/*****************RSA Code******************/</font></p>
<p><font face="宋体" size="2"> #include &lt;stdio.h&gt;<br>
 #include &lt;string.h&gt;<br>
 #include &lt;openssl/evp.h&gt;<br>
 #include &lt;openssl/rsa.h&gt;<br>
void print(const char *promptStr,unsigned char *data,int len)<br>
{<br>
&nbsp;&nbsp;&nbsp;  int i;<br>
&nbsp;&nbsp;&nbsp;  printf(&quot;\n===%s[长度=%d字节]======\n&quot;,promptStr,len);<br>
&nbsp;&nbsp;&nbsp;  for(i = 0; i &lt; len; i++) printf(&quot;%02x&quot;, data[i]);<br>
&nbsp;&nbsp;&nbsp;  printf(&quot;\n=======================\n&quot;);<br>
}</font></p>
<font face="宋体" size="2">
<p><br>
//作为一条规则，使用静态调用，<br>
static void prime_generate_status(int code, int arg, void *cb_arg)<br>
{<br>
&nbsp;&nbsp;&nbsp;  if( arg&gt;0 &amp;&amp; (arg%10) )<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return;<br>
&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  if (code == 0)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;\n找到潜在素数: %d&quot;, (arg + 1));<br>
&nbsp;&nbsp;&nbsp;  else if (code != 1)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;\n成功获取一个素数!&quot;);<br>
}</p>
<p>//如果成功返回包装了RSA参数的EVP_PKEY，否则返回NULL<br>
EVP_PKEY* getRSA()<br>
{<br>
&nbsp;&nbsp;&nbsp;  EVP_PKEY* pkey=NULL;<br>
&nbsp;&nbsp;&nbsp;  RSA* rsa=RSA_generate_key(1024,//公钥模长<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  RSA_3,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //第三个费尔玛数作为公钥中的e<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  prime_generate_status, //素数产生状态的回调函数<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //传给回调函数的参数<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  );<br>
&nbsp;&nbsp;&nbsp;  if(NULL==rsa)<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;生成RSA密钥对失败\n&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return NULL;<br>
&nbsp;&nbsp;&nbsp;  }<br>
 //隐藏RSA密钥抵御定时攻击<br>
&nbsp;&nbsp;&nbsp;  RSA_blinding_on(rsa,NULL);<br>
 printf(&quot;\n成功生成RSA密钥对\n&quot;);</p>
<p>&nbsp;&nbsp;&nbsp;  pkey=EVP_PKEY_new();<br>
&nbsp;&nbsp;&nbsp;  if(NULL==pkey)<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;EVP_PKEY_new failed\n&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  RSA_free(rsa);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return NULL;<br>
&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  //将rsa对象赋给EVP_PKEY结构<br>
&nbsp;&nbsp;&nbsp;  EVP_PKEY_assign_RSA(pkey,rsa);<br>
&nbsp;&nbsp;&nbsp;  return pkey;<br>
}</p>
<p>void main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp;&nbsp;  RSA* rsa=NULL;<br>
&nbsp;&nbsp;&nbsp;  EVP_PKEY* pkey=NULL;<br>
&nbsp;&nbsp;&nbsp;  int len=-1;<br>
&nbsp;&nbsp;&nbsp;  //要加密的明文<br>
&nbsp;&nbsp;&nbsp;  char plainText[]=&quot;[For test to public/private key encryption/decryption]&quot;; <br>
&nbsp;&nbsp;&nbsp;  char encData[512];//加密后的数据<br>
&nbsp;&nbsp;&nbsp;  char decData[512];//解密后的数据，应该和明文相同</p>
<p>&nbsp;&nbsp;&nbsp;  OpenSSL_add_all_ciphers();</p>
<p>&nbsp;&nbsp;&nbsp;  pkey=getRSA();<br>
&nbsp;&nbsp;&nbsp;  if(pkey==NULL)<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return;<br>
&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;  len=EVP_PKEY_encrypt(<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  encData,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //加密后的数据<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  plainText,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //明文<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  sizeof(plainText),  //明文长度<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  pkey&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //公钥<br>
&nbsp;&nbsp;&nbsp;  );<br>
&nbsp;&nbsp;&nbsp;  if(len==-1)<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;EVP_PKEY_encrypt加密失败\n&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit(-1);<br>
&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;  print(&quot;加密后的数据&quot;,encData,len);</p>
<p> //解密<br>
&nbsp;&nbsp;&nbsp;  len=EVP_PKEY_decrypt(<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  decData,&nbsp;&nbsp;&nbsp;  //解密后的数据<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  encData,&nbsp;&nbsp;&nbsp;  //密文<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  len,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //密文长度<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  pkey&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //私钥(事实上，公私钥都在此数据结构中)<br>
&nbsp;&nbsp;&nbsp;  );<br>
&nbsp;&nbsp;&nbsp;  if(len==-1)<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;EVP_PKEY_decrypt解密失败\n&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return;<br>
&nbsp;&nbsp;&nbsp;  }</p>
<p>&nbsp;&nbsp;&nbsp;  print(&quot;解密后的数据&quot;,decData,len);<br>
&nbsp;&nbsp;&nbsp;  printf(&quot;\n明文是:[长度=%d字节]:%s\n&quot;,len,decData);<br>
 //释放EVP_PKEY对象，其关联的RSA对象也被同时释放。<br>
&nbsp;&nbsp;&nbsp;  EVP_PKEY_free(pkey);<br>
&nbsp;&nbsp;&nbsp;  getchar();<br>
}<br>
 <br>
 RSA 算法的一个重要环节是生成密钥对。</p>
<p>&nbsp;&nbsp;&nbsp;  在运行程序之前你必须做好前期准备，否则无法调试，这里我们要用到Openssl的EVP，我们需要在工程中引入要用到的链接库文件libeay32.lib,(创建好一个工程后Project-&gt;Settings-&gt;Link在Object/Library Moduls：中添加libeay32.lib,并且要保证libeay32.dll已经放在了System32目录下了)，这些都完成后你就可以直接运行程序了。</p>
<p> </p>
</font> <a href="http://hi.baidu.com/dongxiang2007/blog/item/9aad56d5bff030cd50da4b65.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%D1%A7%CF%B0%C0%E0">学习类</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/9aad56d5bff030cd50da4b65.html#comment">查看评论</a>]]></description>
        <pubDate>2009年09月03日 星期四  下午 07:38</pubDate>
        <category><![CDATA[学习类]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/9aad56d5bff030cd50da4b65.html</guid>
</item>

<item>
        <title><![CDATA[OpenSSL应用 对称算法Des]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/9351653849b4042db8998f8c.html]]></link>
        <description><![CDATA[
		
		<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Openssl中有AES、DES、Blowfish、CAST、IDEA、RC2、RC5等对称算法的实现函数，而且有一个统一的编程接口，很方便应用，但难于理解，当然你也可以自己去写Openssl的扩展函数，这样就更加方便了。这里我想用DES 算法来举例说说Openssl编程的一般流程。以下是VC环境里调试成功的程序，可以直接运行。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  在运行程序之前你必须做好前期准备，否则无法调试，这里我们要用到Openssl的EVP，我们需要在工程中引入要用到的链接库文件libeay32.lib,(创建好一个工程后Project-&gt;Settings-&gt;Link在Object/Library Moduls：中添加libeay32.lib,并且要保证libeay32.dll已经放在了System32目录下了)，这些都完成后你就可以直接运行程序了。</p>
<p>/***********************Des Code****************/</p>
<p>#include &lt;stdio.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;openssl/evp.h&gt;<br>
void print(const char *promptStr,unsigned char *data,int len)<br>
{<br>
&nbsp;&nbsp;&nbsp;  int i;<br>
&nbsp;&nbsp;&nbsp;  printf(&quot;%s[长度=%d]\n&quot;,promptStr,len);<br>
&nbsp;&nbsp;&nbsp;  for(i = 0; i &lt; len; i++) printf(&quot;%02x&quot;, data[i]);<br>
&nbsp;&nbsp;&nbsp;  printf(&quot;\n===============\n&quot;);<br>
}<br>
void main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp;&nbsp;  const int ITERATIVE_ROUND_FOR_KEY=3;<br>
&nbsp;&nbsp;&nbsp;  unsigned char key[EVP_MAX_KEY_LENGTH];//密钥<br>
&nbsp;&nbsp;&nbsp;  unsigned char iv[EVP_MAX_IV_LENGTH];//初始向量<br>
&nbsp;&nbsp;&nbsp;  EVP_CIPHER_CTX ctx;//加密上下文对象<br>
&nbsp;&nbsp;&nbsp;  unsigned char out[512+8];<br>
&nbsp;&nbsp;&nbsp;  int outl;<br>
&nbsp;&nbsp;&nbsp;  unsigned char txtAfterDecrypt[512];<br>
&nbsp;&nbsp;&nbsp;  int txtLenAfterDecrypt;</p>
<p>&nbsp;&nbsp;&nbsp;  char simpleText[]=&quot;这是一个Openssl测试程序，采用对称算法：des_ede3_cbc.&quot;;<br>
&nbsp;&nbsp;&nbsp;  //密码<br>
&nbsp;&nbsp;&nbsp;  const char *passwd=&quot;a78b5C&quot;;//用于产生密钥的口令字符串<br>
&nbsp;&nbsp;&nbsp;  const EVP_CIPHER *type;//加密类型对象<br>
&nbsp;&nbsp;&nbsp;  OpenSSL_add_all_ciphers();//加载加密算法<br>
&nbsp;&nbsp;&nbsp;  OpenSSL_add_all_digests();//加载摘要计算算法<br>
&nbsp;&nbsp;&nbsp;  printf(&quot;密码是:%s\n&quot;,passwd);&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;  printf(&quot;原文:%s\n&quot;,simpleText);<br>
&nbsp;&nbsp;&nbsp;  type=EVP_des_ede3_cbc();&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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
//从文本密码中产生 密钥/向量<br>
&nbsp;&nbsp;&nbsp;  //这个例程使用MD5并且采用来自RSA的PCKS#5的标准<br>
&nbsp;&nbsp;&nbsp;  EVP_BytesToKey(type,//密钥类型<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  EVP_md5(),//摘要计算类型<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  NULL,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (const unsigned char *)passwd,//口令串<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (int)strlen(passwd),//口令串长度<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ITERATIVE_ROUND_FOR_KEY,//迭代轮数<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  key,//输出的密钥<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  iv //输出的初始向量<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  );<br>
&nbsp;&nbsp;&nbsp;  //加密初始化，ctx是加密上下文对象<br>
&nbsp;&nbsp;&nbsp;  EVP_EncryptInit(&amp;ctx,type,key,iv);</p>
<p>&nbsp;&nbsp;&nbsp;  int tmp=(int)strlen(simpleText);<br>
&nbsp;&nbsp;&nbsp;  //由于数据量少，不用循环加入数据<br>
EVP_EncryptUpdate(&amp;ctx,//加密上下文对象<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  out,//加密后的内容<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &amp;outl, //加密后的内容长度<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (const unsigned char*)simpleText, //要加密的内容<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (int)strlen(simpleText) //要加密的内容长度<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  );<br>
&nbsp;&nbsp;&nbsp;  tmp=outl;<br>
&nbsp;&nbsp;&nbsp;  //结束加密<br>
&nbsp;&nbsp;&nbsp;  EVP_EncryptFinal(&amp;ctx,out+outl,&amp;outl);<br>
&nbsp;&nbsp;&nbsp;  outl+=tmp;<br>
&nbsp;&nbsp;&nbsp;  //清除加密上下文，因为下文还要重用<br>
&nbsp;&nbsp;&nbsp;  EVP_CIPHER_CTX_cleanup(&amp;ctx);</p>
<p>&nbsp;&nbsp;&nbsp;  print(&quot;加密之后的结果：&quot;,out,outl);<br>
//解密初始化，解密类型，密钥，初始向量必需和加密时相同，否则解密不能成功<br>
&nbsp;&nbsp;&nbsp;  EVP_DecryptInit(&amp;ctx,type,key,iv);</p>
<p>EVP_DecryptUpdate(&amp;ctx,//解密上下文对象<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  txtAfterDecrypt,&nbsp;&nbsp;  //解密后的内容<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &amp;txtLenAfterDecrypt,//解密后的内容长度<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  out,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //要解密的内容<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  outl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //要解密的内容长度<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  );<br>
&nbsp;&nbsp;&nbsp;  tmp=txtLenAfterDecrypt;<br>
&nbsp;&nbsp;&nbsp;  //结束解密<br>
&nbsp;&nbsp;&nbsp;  EVP_DecryptFinal(&amp;ctx,txtAfterDecrypt+txtLenAfterDecrypt,&amp;txtLenAfterDecrypt);<br>
&nbsp;&nbsp;&nbsp;  txtLenAfterDecrypt+=tmp;<br>
&nbsp;&nbsp;&nbsp;  EVP_CIPHER_CTX_cleanup(&amp;ctx);<br>
&nbsp;&nbsp;&nbsp;  txtAfterDecrypt[txtLenAfterDecrypt]=0;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;解密之后(长度=%d):\n%s\n&quot;,txtLenAfterDecrypt,txtAfterDecrypt);&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;  getchar();<br>
}</p>
<p>代码有点乱，但条理很清晰，从上面的代码中我们很容易就可以知道它的基本流程了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;  首先得有个初始化的过程OpenSSL_add_all_ciphers()；OpenSSL_add_all_digests();加载加密算法，加载摘要计算算法，这个程序中我们其实运用了两个算法，加密和摘要。在生成密钥的时候用到了MD5，所以我们要事先声明下，BytesToKey（）函数将我们的口令转换成程序可以识别的密钥。然后就要初始化加密上下文对象CTX, 加解密初始化功能 EVP_EncryptInit(&amp;ctx,type,key,iv);&nbsp;&nbsp;  加解密更新函数EVP_EncryptUpdate（）结束加解密函数 EVP_EncryptFinal(&amp;ctx,out+outl,&amp;outl);然后解密的过程是一样的就是把Encrypt换成Decrypt。<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  当然这个程序只是简单的测试而已。有兴趣的同仁可以讨论一下，我现在在学习Openssl</p> <a href="http://hi.baidu.com/dongxiang2007/blog/item/9351653849b4042db8998f8c.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%D1%A7%CF%B0%C0%E0">学习类</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/9351653849b4042db8998f8c.html#comment">查看评论</a>]]></description>
        <pubDate>2009年09月03日 星期四  下午 06:46</pubDate>
        <category><![CDATA[学习类]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/9351653849b4042db8998f8c.html</guid>
</item>

<item>
        <title><![CDATA[OpenSSL 应用]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/1f8dfe1cc8694c8287d6b6a8.html]]></link>
        <description><![CDATA[
		
		<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Openssl，一个强大的开放源代码的SSL协议实现。作为一个基于密码学的安全开发包，OpenSSL提供的功能相当强大和全面，囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议，并提供了丰富的应用程序供测试或其它目的使用。</p>
<p>1.对称加密算法 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  OpenSSL一共提供了8种对称加密算法，其中7种是分组加密算法，仅有的一种流加密算法是RC4。这7种分组加密算法分别是AES、DES、Blowfish、CAST、IDEA、RC2、RC5，都支持电子密码本模式（ECB）、加密分组链接模式（CBC）、加密反馈模式（CFB）和输出反馈模式（OFB）四种常用的分组密码加密模式。其中，AES使用的加密反馈模式（CFB）和输出反馈模式（OFB）分组长度是128位，其它算法使用的则是64位。事实上，DES算法里面不仅仅是常用的DES算法，还支持三个密钥和两个密钥3DES算法。</p>
<p>2.非对称加密算法 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  OpenSSL一共实现了4种非对称加密算法，包括DH算法、RSA算法、DSA算法和椭圆曲线算法（EC）。DH算法一般用户密钥交换。RSA算法既可以用于密钥交换，也可以用于数字签名，当然，如果你能够忍受其缓慢的速度，那么也可以用于数据加密。DSA算法则一般只用于数字签名。 <br>
<br>
3.信息摘要算法 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  OpenSSL实现了5种信息摘要算法，分别是MD2、MD5、MDC2、SHA（SHA1）和RIPEMD。SHA算法事实上包括了SHA和SHA1两种信息摘要算法，此外，OpenSSL还实现了DSS标准中规定的两种信息摘要算法DSS和DSS1。</p>
<p>等等。。</p>
<p>暑假里看了一下Openssl，觉得蛮有用的。</p>
<p>&nbsp;&nbsp;&nbsp;  首先需要配置Openssl的使用环境，我用的是XP系统，VC++6.0下编译和调试。</p>
<p>将Openssl源文件编译过后，会生成libeay32.lib,ssleay32.lib两个静态链接库文件和对应的两个动态链接库文件libeay32.dll,ssleay32.dll,还有一个放了N多头文件的文件夹Include.这是我们想要的。&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;</p>
<p>你可以将两个静态链接库文件路径添加到VC的环境里，在Tools-&gt;Options-&gt;Directories 在showdirectories里选择Include files将头文件文件夹的路径添加进，然后选择Library files将Lib文件夹路径添加进去确定即可。最后将libeay32.dll,ssleay32.dll拷贝都System32目录下，这样就完成了基本的配置了。</p> <a href="http://hi.baidu.com/dongxiang2007/blog/item/1f8dfe1cc8694c8287d6b6a8.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%D1%A7%CF%B0%C0%E0">学习类</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/1f8dfe1cc8694c8287d6b6a8.html#comment">查看评论</a>]]></description>
        <pubDate>2009年09月03日 星期四  下午 05:52</pubDate>
        <category><![CDATA[学习类]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/1f8dfe1cc8694c8287d6b6a8.html</guid>
</item>

<item>
        <title><![CDATA[欧几里德算法、扩展欧几里德算法、乘法逆元]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/db9b98626ce722d5e6113a51.html]]></link>
        <description><![CDATA[
		
		<p><font size="2">最近看了一本书《程序员》里面说的一个面试题：</font></p>
<p><font size="2">求两个数的最大公约数：</font></p>
<p><font size="2">SoEasy的题目看过C 的人都知道怎么写这个程序</font></p>
<p><font size="2">1.传统方法：穷举</font></p>
<p>#include &lt;math.h&gt;<br>
int main()<br>
{<br>
  int m=1970,n=1066,p=0;<br>
  p=m&lt;n?m:n;<br>
  for(;p&gt;=1;p--)<br>
  {<br>
&nbsp;&nbsp;  Count++;<br>
&nbsp;&nbsp;&nbsp;  if(m%p==0&amp;&amp;n%p==0)<br>
&nbsp;&nbsp; break;<br>
  }<br>
  printf(&quot;最大公约数是:%d  \n&quot;,p);<br>
  printf(&quot;循环了:%d  \n&quot;,Count);<br>
  <br>
return 0;<br>
}</p>
<p>最大公约数是：2</p>
<p>循环了：1065次</p>
<p>2.辗转相除</p>
<p>#include&lt;stdio.h&gt;<br>
int main()<br>
{<br>
 int m=1970,n=1066,p=0;<br>
 while(m%n != 0)<br>
 {<br>
&nbsp;&nbsp; p = m%n;<br>
&nbsp;&nbsp; m = n;<br>
&nbsp;&nbsp; n = p;<br>
&nbsp;&nbsp; Count++;<br>
 }<br>
 printf(&quot;最大公约数是%d\n&quot;,n);<br>
 printf(&quot;循环了%d\n&quot;,Count);<br>
 return 0;<br>
}</p>
<p>最大公约数是：2</p>
<p>循环了：10</p>
<p>对于求1970和1066的最大公约数辗转相除法明显优秀很多。</p>
<p>我们可以将辗转相除法做一个变形。p=m%n 然后将p赋给n实际上就是一个交换 可以写成一个递归的形式如下：</p>
<p>int gcd(int m,int n)</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if(n==0)//递归出口</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return m;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  else</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return gcd(n,m%n);</p>
<p>}</p>
<p>这个函数就是传说中的欧几里德算法的描述了。</p>
<p>3.欧几里德算法</p>
<p>#include&lt;stdio.h&gt;</p>
<p>int gcd(int m,int n);<br>
int main(int argc, char* argv[])<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int m=1970,n=1066;<br>
&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;最大公约数是：%d\n&quot;,gcd(m,n));<br>
&nbsp;&nbsp;&nbsp;&nbsp;  return 0;<br>
}<br>
int gcd(int m,int n)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;  if(n==0)<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return m;<br>
&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;  else<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return gcd(n,m%n);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
}</p>
<p>最大公约数是：2</p>
<p>递归了：10</p>
<p>这个算法基本原理就是辗转相除，效率很高。</p>
<p>在面试的人中大部分都是采用第一种传统的方法。显然面试官想要的是第二种人了。其实从实现的过程来看后者要显得简单一些，递归很好理解。可能是我们都习惯于停用一种算法就解决问题。</p>
<p>4.扩展欧几里德算法</p>
<p>这个算法的并不是为了求最大公约数而设计的，但是它同样可以实现求最大公约数，原理就是Euclid。</p>
<p>扩展欧几里德算主要是解决乘法逆元的问题：A*BModC=1可以将B描述为：A模C的<a target="_blank" href="http://baike.baidu.com/view/1850916.htm">乘法逆元</a>。好了看看算法吧：</p>
<p>int ExGcd(int a, int b, int &amp;x, int &amp;y);</p>
<p>int main(int argc, char* argv[])<br>
{<br>
int m=550,n=1769;<br>
int x=0,y=0;<br>
int k;<br>
k=ExGcd(m,n,x,y);<br>
printf(&quot;550 和 1769的最大公约数是：%d\n550模1769的乘法逆元是：%d\n1769模550的乘法逆元是：%d\n&quot;,k,x,y);<br>
return 0;<br>
}<br>
/***************************************<br>
函数：ExGcd <br>
功能：求两个数的最大公约数和模P的乘法逆元。<br>
输入：a,b 输入参数，求这两个数的最大公约数<br>
&nbsp;&nbsp;  和a模b的逆元 或 b模a的逆元。<br>
输出：x,y 分别表示a模b的逆元和b模a的逆元。<br>
返回：r 表示a b 的最大公约数。<br>
*************************************/<br>
int ExGcd(int a, int b, int &amp;x, int &amp;y)<br>
{<br>
if(b == 0)<br>
{<br>
&nbsp;&nbsp;  x = 1;<br>
&nbsp;&nbsp;  y = 0;<br>
&nbsp;&nbsp;  return a;<br>
}<br>
int r = ExGcd(b, a % b, x, y);<br>
int t = x;<br>
x = y;<br>
y = t - a / b * y;<br>
return r;<br>
}</p>
<p>程序中有详细的解释。</p>
<p>总结：积累高效算法很重要！</p> <a href="http://hi.baidu.com/dongxiang2007/blog/item/db9b98626ce722d5e6113a51.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%D1%A7%CF%B0%C0%E0">学习类</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/db9b98626ce722d5e6113a51.html#comment">查看评论</a>]]></description>
        <pubDate>2009年05月22日 星期五  下午 12:15</pubDate>
        <category><![CDATA[学习类]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/db9b98626ce722d5e6113a51.html</guid>
</item>

<item>
        <title><![CDATA[正则表达式学习（下）]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/1f8dfe1c15000b8387d6b600.html]]></link>
        <description><![CDATA[
		
		<h2>分组</h2>
<p>我们已经提到了怎么重复单个字符（直接在字符后面加上限定符就行了）；但如果想要重复多个字符又该怎么办？你可以用小括号来指定<span class="name"><strong>子表达式</strong></span>(也叫做<span class="name"><strong>分组</strong></span>)，然后你就可以指定这个子表达式的重复次数了，你也可以对子表达式进行其它一些操作(后面会有介绍)。</p>
<p><span class="regex"><font color="#ff0000">(\d{1,3}\.){3}\d{1,3}</font></span>是一个<span class="desc"><u>简单的IP地址匹配</u></span>表达式。要理解这个表达式，请按下列顺序分析它：<span class="part"><font color="#008000">\d{1,3}</font></span>匹配<span class="desc"><u>1到3位的数字</u></span>，<span class="part"><font color="#008000">(\d{1,3}\.){3}</font></span>匹配<span class="desc"><u>三位数字加上一个英文句号(这个整体也就是这个<span class="name"><strong>分组</strong></span>)重复3次</u></span>，最后再加上<span class="desc"><u>一个一到三位的数字</u></span>(<span class="part"><font color="#008000">\d{1,3}</font></span>)。</p>
<p class="note">IP地址中每个数字都不能大于255，大家千万不要被《24》第三季的编剧给忽悠了……</p>
<p>不幸的是，它也将匹配<span class="string"><em>256.300.888.999</em></span>这种不可能存在的IP地址。如果能使用算术比较的话，或许能简单地解决这个问题，但是正则表达式中并不提供关于数学的任何功能，所以只能使用冗长的分组，选择，字符类来描述一个正确的IP地址：<span class="regex"><font color="#ff0000">((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)</font></span>。</p>
<p>理解这个表达式的关键是理解<span class="part"><font color="#008000">2[0-4]\d|25[0-5]|[01]?\d\d?</font></span>，这里我就不细说了，你自己应该能分析得出来它的意义。</p>
<h2>反义</h2>
<p>有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外，其它任意字符都行的情况，这时需要用到<span class="name"><strong>反义</strong></span>：</p>
<table cellspacing="0">
    <caption>表3.常用的反义代码</caption>
    <thead>
        <tr>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code"><font color="#0000ff">\W</font></span></td>
            <td><span class="desc"><u>匹配任意不是字母，数字，下划线，汉字的字符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\S</font></span></td>
            <td><span class="desc"><u>匹配任意不是空白符的字符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\D</font></span></td>
            <td><span class="desc"><u>匹配任意非数字的字符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\B</font></span></td>
            <td><span class="desc"><u>匹配不是单词开头或结束的位置</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">[^x]</font></span></td>
            <td><span class="desc"><u>匹配除了x以外的任意字符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">[^aeiou]</font></span></td>
            <td><span class="desc"><u>匹配除了aeiou这几个字母以外的任意字符</u></span></td>
        </tr>
    </tbody>
</table>
<p>例子：<span class="regex"><font color="#ff0000">\S+</font></span>匹配<span class="desc"><u>不包含空白符的字符串</u></span>。</p>
<p><span class="regex"><font color="#ff0000">&lt;a[^&gt;]+&gt;</font></span>匹配<span class="desc"><u>用尖括号括起来的以a开头的字符串</u></span>。</p>
<h2>后向引用</h2>
<p>使用小括号指定一个子表达式后，<strong>匹配这个子表达式的文本</strong>(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下，每个分组会自动拥有一个<span class="name"><strong>组号</strong></span>，规则是：从左向右，以分组的左括号为标志，第一个出现的分组的组号为1，第二个为2，以此类推。</p>
<div class="note">
<p>呃……其实,组号分配还不像我刚说得那么简单：</p>
<ul>
    <li>分组0对应整个正则表达式</li>
    <li>实际上组号分配过程是要从左向右扫描两遍的：第一遍只给未命名组分配，第二遍只给命名组分配－－因此所有命名组的组号都大于未命名的组号</li>
    <li>你可以使用<span class="code"><font color="#0000ff">(?:exp)</font></span>这样的语法来剥夺一个分组对组号分配的参与权．</li>
</ul>
</div>
<p><span class="name"><strong>后向引用</strong></span>用于重复搜索前面某个分组匹配的文本。例如，<span class="part"><font color="#008000">\1</font></span>代表<span class="desc"><u>分组1匹配的文本</u></span>。难以理解？请看示例：</p>
<p><span class="regex"><font color="#ff0000">\b(\w+)\b\s+\1\b</font></span>可以用来匹配<span class="desc"><u>重复的单词</u></span>，像<span class="string"><em>go go</em></span>, 或者<span class="string"><em>kitty kitty</em></span>。这个表达式首先是<span class="desc"><u>一个单词</u></span>，也就是<span class="desc"><u>单词开始处和结束处之间的多于一个的字母或数字</u></span>(<span class="part"><font color="#008000">\b(\w+)\b</font></span>)，这个单词会被捕获到编号为1的分组中，然后是<span class="desc"><u>1个或几个空白符</u></span>(<span class="part"><font color="#008000">\s+</font></span>)，最后是<span class="desc"><u>分组1中捕获的内容（也就是前面匹配的那个单词）</u></span>(<span class="part"><font color="#008000">\1</font></span>)。</p>
<p>你也可以自己指定子表达式的<span class="name"><strong>组名</strong></span>。要指定一个子表达式的组名，请使用这样的语法：<span class="code"><font color="#0000ff">(?&lt;Word&gt;\w+)</font></span>(或者把尖括号换成<span class="code"><font color="#0000ff">'</font></span>也行：<span class="code"><font color="#0000ff">(?'Word'\w+)</font></span>),这样就把<span class="part"><font color="#008000">\w+</font></span>的组名指定为<span class="part"><font color="#008000">Word</font></span>了。要反向引用这个分组<span class="name"><strong>捕获</strong></span>的内容，你可以使用<span class="code"><font color="#0000ff">\k&lt;Word&gt;</font></span>,所以上一个例子也可以写成这样：<span class="regex"><font color="#ff0000">\b(?&lt;Word&gt;\w+)\b\s+\k&lt;Word&gt;\b</font></span>。</p>
<p>使用小括号的时候，还有很多特定用途的语法。下面列出了最常用的一些：</p>
<table cellspacing="0">
    <caption>表4.常用分组语法</caption>
    <tbody>
        <tr>
            <th scope="col">分类</th>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
        <tr>
            <th rowspan="3">捕获</th>
            <td><span class="code"><font color="#0000ff">(exp)</font></span></td>
            <td><span class="desc"><u>匹配exp,并捕获文本到自动命名的组里</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?&lt;name&gt;exp)</font></span></td>
            <td><span class="desc"><u>匹配exp,并捕获文本到名称为name的组里，也可以写成(?'name'exp)</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?:exp)</font></span></td>
            <td><span class="desc"><u>匹配exp,不捕获匹配的文本，也不给此分组分配组号</u></span></td>
        </tr>
        <tr>
            <th rowspan="4">零宽断言</th>
            <td><span class="code"><font color="#0000ff">(?=exp)</font></span></td>
            <td><span class="desc"><u>匹配exp前面的位置</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?&lt;=exp)</font></span></td>
            <td><span class="desc"><u>匹配exp后面的位置</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?!exp)</font></span></td>
            <td><span class="desc"><u>匹配后面跟的不是exp的位置</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?&lt;!exp)</font></span></td>
            <td><span class="desc"><u>匹配前面不是exp的位置</u></span></td>
        </tr>
        <tr>
            <th>注释</th>
            <td><span class="code"><font color="#0000ff">(?#comment)</font></span></td>
            <td><span class="desc"><u>这种类型的分组不对正则表达式的处理产生任何影响，用于提供注释让人阅读</u></span></td>
        </tr>
    </tbody>
</table>
<p>我们已经讨论了前两种语法。第三个<span class="code"><font color="#0000ff">(?:exp)</font></span>不会改变正则表达式的处理方式，只是这样的组匹配的内容<span class="desc"><u>不会像前两种那样被捕获到某个组里面，也不会拥有组号</u></span>。&ldquo;我为什么会想要这样做？&rdquo;&mdash;&mdash;好问题，你觉得为什么呢？</p>
<h2>零宽断言</h2>
<p class="note">地球人，是不是觉得这些术语名称太复杂，太难记了？我也有同感。知道有这么一种东西就行了，它叫什么，随它去吧！人若无名，便可专心练剑；物若无名，便可随意取舍……</p>
<p>接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西，也就是说它们像<span class="code"><font color="#0000ff">\b</font></span>,<span class="code"><font color="#0000ff">^</font></span>,<span class="code"><font color="#0000ff">$</font></span>那样用于指定一个位置，这个位置应该满足一定的条件(即断言)，因此它们也被称为<span class="name"><strong>零宽断言</strong></span>。最好还是拿例子来说明吧：</p>
<p class="note">断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。</p>
<p><span class="code"><font color="#0000ff">(?=exp)</font></span>也叫<span class="name"><strong>零宽度正预测先行断言</strong></span>，它<span class="desc"><u>断言自身出现的位置的后面能匹配表达式exp</u></span>。比如<span class="regex"><font color="#ff0000">\b\w+(?=ing\b)</font></span>，匹配<span class="desc"><u>以ing结尾的单词的前面部分(除了ing以外的部分)</u></span>，如查找<span class="string"><em>I'm singing while you're dancing.</em></span>时，它会匹配<span class="desc"><u>sing</u></span>和<span class="desc"><u>danc</u></span>。</p>
<p><span class="code"><font color="#0000ff">(?&lt;=exp)</font></span>也叫<span class="name"><strong>零宽度正回顾后发断言</strong></span>，它<span class="desc"><u>断言自身出现的位置的前面能匹配表达式exp</u></span>。比如<span class="regex"><font color="#ff0000">(?&lt;=\bre)\w+\b</font></span>会匹配<span class="desc"><u>以re开头的单词的后半部分(除了re以外的部分)</u></span>，例如在查找<span class="string"><em>reading a book</em></span>时，它匹配<span class="desc"><u>ading</u></span>。</p>
<p>假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了)，你可以这样查找需要在前面和里面添加逗号的部分：<span class="regex"><font color="#ff0000">((?&lt;=\d)\d{3})+\b</font></span>，用它对<span class="string"><em>1234567890</em></span>进行查找时结果是<span class="desc"><u>234567890</u></span>。</p>
<p>下面这个例子同时使用了这两种断言：<span class="regex"><font color="#ff0000">(?&lt;=\s)\d+(?=\s)</font></span>匹配<span class="desc"><u>以空白符间隔的数字(再次强调，不包括这些空白符)</u></span>。</p>
<h2>负向零宽断言</h2>
<p>前面我们提到过怎么查找<strong>不是某个字符或不在某个字符类里</strong>的字符的方法(反义)。但是如果我们只是想要<strong>确保某个字符没有出现，但并不想去匹配它</strong>时怎么办？例如，如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样：</p>
<p><span class="regex"><font color="#ff0000">\b\w*q[^u]\w*\b</font></span>匹配<span class="desc"><u>包含<strong>后面不是字母u的字母q</strong>的单词</u></span>。但是如果多做测试(或者你思维足够敏锐，直接就观察出来了)，你会发现，如果q出现在单词的结尾的话，像<strong>Iraq</strong>,<strong>Benq</strong>，这个表达式就会出错。这是因为<span class="part"><font color="#008000">[^u]</font></span>总要匹配一个字符，所以如果q是单词的最后一个字符的话，后面的<span class="part"><font color="#008000">[^u]</font></span>将会匹配q后面的单词分隔符(可能是空格，或者是句号或其它的什么)，后面的<span class="part"><font color="#008000">\w*\b</font></span>将会匹配下一个单词，于是<span class="regex"><font color="#ff0000">\b\w*q[^u]\w*\b</font></span>就能匹配整个<span class="string"><em>Iraq fighting</em></span>。<span class="name"><strong>负向零宽断言</strong></span>能解决这样的问题，因为它只匹配一个位置，并不<strong>消费</strong>任何字符。现在，我们可以这样来解决这个问题：<span class="regex"><font color="#ff0000">\b\w*q(?!u)\w*\b</font></span>。</p>
<p><span class="name"><strong>零宽度负预测先行断言</strong></span><span class="code"><font color="#0000ff">(?!exp)</font></span>，<span class="desc"><u>断言此位置的后面不能匹配表达式exp</u></span>。例如：<span class="regex"><font color="#ff0000">\d{3}(?!\d)</font></span>匹配<span class="desc"><u>三位数字，而且这三位数字的后面不能是数字</u></span>；<span class="regex"><font color="#ff0000">\b((?!abc)\w)+\b</font></span>匹配<span class="desc"><u>不包含连续字符串abc的单词</u></span>。</p>
<p>同理，我们可以用<span class="code"><font color="#0000ff">(?&lt;!exp)</font></span>,<span class="name"><strong>零宽度负回顾后发断言</strong></span>来<span class="desc"><u>断言此位置的前面不能匹配表达式exp</u></span>：<span class="regex"><font color="#ff0000">(?&lt;![a-z])\d{7}</font></span>匹配<span class="desc"><u>前面不是小写字母的七位数字</u></span>。</p>
<p class="note">请详细分析表达式<span class="regex"><font color="#ff0000">(?&lt;=&lt;(\w+)&gt;).*(?=&lt;\/\1&gt;)</font></span>，这个表达式最能表现零宽断言的真正用途。</p>
<p>一个更复杂的例子：<span class="regex"><font color="#ff0000">(?&lt;=&lt;(\w+)&gt;).*(?=&lt;\/\1&gt;)</font></span>匹配<span class="desc"><u>不包含属性的简单HTML标签内里的内容</u></span>。<span class="code"><font color="#0000ff">(&lt;?(\w+)&gt;)</font></span>指定了这样的<span class="name"><strong>前缀</strong></span>：<span class="desc"><u>被尖括号括起来的单词</u></span>(比如可能是&lt;b&gt;)，然后是<span class="part"><font color="#008000">.*</font></span>(任意的字符串),最后是一个<span class="name"><strong>后缀</strong></span><span class="part"><font color="#008000">(?=&lt;\/\1&gt;)</font></span>。注意后缀里的<span class="part"><font color="#008000">\/</font></span>，它用到了前面提过的字符转义；<span class="part"><font color="#008000">\1</font></span>则是一个反向引用，引用的正是<span class="desc"><u>捕获的第一组</u></span>，前面的<span class="part"><font color="#008000">(\w+)</font></span>匹配的内容，这样如果前缀实际上是&lt;b&gt;的话，后缀就是&lt;/b&gt;了。整个表达式匹配的是&lt;b&gt;和&lt;/b&gt;之间的内容(再次提醒，不包括前缀和后缀本身)。</p>
<h2>注释</h2>
<p>小括号的另一种用途是通过语法<span class="code"><font color="#0000ff">(?#comment)</font></span>来包含注释。例如：<span class="regex"><font color="#ff0000">2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)</font></span>。</p>
<p>要包含注释的话，最好是启用&ldquo;忽略模式里的空白符&rdquo;选项，这样在编写表达式时能任意的添加空格，Tab，换行，而实际使用时这些都将被忽略。启用这个选项后，在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如，我们可以前面的一个表达式写成这样：</p>
<pre class="regex">(?&lt;=    # 断言要匹配的文本的前缀
      &lt;(\w+)&gt; # 查找尖括号括起来的字母或数字(即HTML/XML标签)
      )       # 前缀结束
      .*      # 匹配任意文本
      (?=     # 断言要匹配的文本的后缀
      &lt;\/\1&gt;  # 查找尖括号括起来的内容：前面是一个&quot;/&quot;，后面是先前捕获的标签
      )       # 后缀结束</pre>
<h2>贪婪与懒惰</h2>
<p>当正则表达式中包含能接受重复的限定符时，通常的行为是（在使整个表达式能得到匹配的前提下）匹配<strong>尽可能多</strong>的字符。以这个表达式为例：<span class="regex"><font color="#ff0000">a.*b</font></span>，它将会匹配<span class="desc"><u>最长的以a开始，以b结束的字符串</u></span>。如果用它来搜索<span class="string"><em>aabab</em></span>的话，它会匹配整个字符串<span class="desc"><u>aabab</u></span>。这被称为<span class="name"><strong>贪婪</strong></span>匹配。</p>
<p>有时，我们更需要<span class="name"><strong>懒惰</strong></span>匹配，也就是匹配<strong>尽可能少</strong>的字符。前面给出的限定符都可以被转化为懒惰匹配模式，只要在它后面加上一个问号<span class="code"><font color="#0000ff">?</font></span>。这样<span class="regex"><font color="#ff0000">.*?</font></span>就意味着<span class="desc"><u>匹配任意数量的重复，但是在能使整个匹配成功的前提下使用最少的重复</u></span>。现在看看懒惰版的例子吧：</p>
<p><span class="regex"><font color="#ff0000">a.*?b</font></span>匹配<span class="desc"><u>最短的，以a开始，以b结束的字符串</u></span>。如果把它应用于<span class="string"><em>aabab</em></span>的话，它会匹配<span class="desc"><u>aab（第一到第三个字符）</u></span>和<span class="desc"><u>ab（第四到第五个字符）</u></span>。</p>
<p class="note">为什么第一个匹配是aab（第一到第三个字符）而不是ab（第二到第三个字符）？简单地说，因为正则表达式有另一条规则，比懒惰／贪婪规则的优先级更高：最先开始的匹配拥有最高的优先权&mdash;&mdash;The match that begins earliest wins。</p>
<table cellspacing="0">
    <caption>表5.懒惰限定符</caption>
    <thead>
        <tr>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code"><font color="#0000ff">*?</font></span></td>
            <td><span class="desc"><u>重复任意次，但尽可能少重复</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">+?</font></span></td>
            <td><span class="desc"><u>重复1次或更多次，但尽可能少重复</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">??</font></span></td>
            <td><span class="desc"><u>重复0次或1次，但尽可能少重复</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">{n,m}?</font></span></td>
            <td><span class="desc"><u>重复n到m次，但尽可能少重复</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">{n,}?</font></span></td>
            <td><span class="desc"><u>重复n次以上，但尽可能少重复</u></span></td>
        </tr>
    </tbody>
</table>
<h2>处理选项</h2>
<p class="note">在C#中，你可以使用<a title="MSDN 相关文档" href="http://msdn2.microsoft.com/zh-cn/library/h5845fdz.aspx">Regex(String, RegexOptions)构造函数</a>来设置正则表达式的处理选项。如：Regex regex = new Regex(@&quot;\ba\w{6}\b&quot;, RegexOptions.IgnoreCase);</p>
<p>上面介绍了几个选项如忽略大小写，处理多行等，这些选项能用来改变处理正则表达式的方式。下面是.Net中常用的正则表达式选项：</p>
<table cellspacing="0">
    <caption>表6.常用的处理选项</caption>
    <thead>
        <tr>
            <th scope="col">名称</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>IgnoreCase(忽略大小写)</td>
            <td>匹配时不区分大小写。</td>
        </tr>
        <tr>
            <td>Multiline(多行模式)</td>
            <td>更改<span class="code"><font color="#0000ff">^</font></span>和<span class="code"><font color="#0000ff">$</font></span>的含义，使它们分别在任意一行的行首和行尾匹配，而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,<span class="code"><font color="#0000ff">$</font></span>的精确含意是:匹配\n之前的位置以及字符串结束前的位置.)</td>
        </tr>
        <tr>
            <td>Singleline(单行模式)</td>
            <td>更改<span class="code"><font color="#0000ff">.</font></span>的含义，使它与每一个字符匹配（包括换行符\n）。</td>
        </tr>
        <tr>
            <td>IgnorePatternWhitespace(忽略空白)</td>
            <td>忽略表达式中的非转义空白并启用由<span class="code"><font color="#0000ff">#</font></span>标记的注释。</td>
        </tr>
        <tr>
            <td>ExplicitCapture(显式捕获)</td>
            <td>仅捕获已被显式命名的组。</td>
        </tr>
    </tbody>
</table>
<p>一个经常被问到的问题是：是不是只能同时使用多行模式和单行模式中的一种？答案是：不是。这两个选项之间没有任何关系，除了它们的名字比较相似（以至于让人感到疑惑）以外。</p>
<h2>平衡组/递归匹配</h2>
<p class="important note">这里介绍的平衡组语法是由.Net Framework支持的；其它语言／库不一定支持这种功能，或者支持此功能但需要使用不同的语法。</p>
<p>有时我们需要匹配像<span class="desc"><u>( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构</u></span>，这时简单地使用<span class="code"><font color="#0000ff">\(.+\)</font></span>则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式，懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等，比如<span class="string"><em>( 5 / ( 3 + 2 ) ) )</em></span>，那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的，配对的括号之间的内容呢？</p>
<p>为了避免<span class="code"><font color="#0000ff">(</font></span>和<span class="code"><font color="#0000ff">\(</font></span>把你的大脑彻底搞糊涂，我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把<span class="string"><em>xx &lt;aa &lt;bbb&gt; &lt;bbb&gt; aa&gt; yy</em></span>这样的字符串里，最长的配对的尖括号内的内容捕获出来？</p>
<p>这里需要用到以下的语法构造：</p>
<ul>
    <li><span class="code"><font color="#0000ff">(?'group')</font></span> 把捕获的内容命名为group,并压入<span class="name"><strong>堆栈(Stack)</strong></span></li>
    <li><span class="code"><font color="#0000ff">(?'-group')</font></span> 从堆栈上弹出最后压入堆栈的名为group的捕获内容，如果堆栈本来为空，则本分组的匹配失败</li>
    <li><span class="code"><font color="#0000ff">(?(group)yes|no)</font></span> 如果堆栈上存在以名为group的捕获内容的话，继续匹配yes部分的表达式，否则继续匹配no部分</li>
    <li><span class="code"><font color="#0000ff">(?!)</font></span> 零宽负向先行断言，由于没有后缀表达式，试图匹配总是失败</li>
</ul>
<p class="note">如果你不是一个程序员（或者你自称程序员但是不知道堆栈是什么东西），你就这样理解上面的三种语法吧：第一个就是在黑板上写一个&quot;group&quot;，第二个就是从黑板上擦掉一个&quot;group&quot;，第三个就是看黑板上写的还有没有&quot;group&quot;，如果有就继续匹配yes部分，否则就匹配no部分。</p>
<p>我们需要做的是每碰到了左括号，就在压入一个&quot;Open&quot;,每碰到一个右括号，就弹出一个，到了最后就看看堆栈是否为空－－如果不为空那就证明左括号比右括号多，那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符)，尽量使整个表达式得到匹配。</p>
<pre class="regex">&lt;                         #最外层的左括号
    [^&lt;&gt;]*                #最外层的左括号后面的不是括号的内容
    (
        (
            (?'Open'&lt;)    #碰到了左括号，在黑板上写一个&quot;Open&quot;
            [^&lt;&gt;]*       #匹配左括号后面的不是括号的内容
        )+
        (
            (?'-Open'&gt;)   #碰到了右括号，擦掉一个&quot;Open&quot;
            [^&lt;&gt;]*        #匹配右括号后面不是括号的内容
        )+
    )*
    (?(Open)(?!))         #在遇到最外层的右括号前面，判断黑板上还有没有没擦掉的&quot;Open&quot;；如果还有，则匹配失败

&gt;                         #最外层的右括号</pre>
<p>平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配<span class="desc"><u>嵌套的&lt;div&gt;标签</u></span>：<span class="regex"><font color="#ff0000">&lt;div[^&gt;]*&gt;[^&lt;&gt;]*(((?'Open'&lt;div[^&gt;]*&gt;)[^&lt;&gt;]*)+((?'-Open'&lt;/div&gt;)[^&lt;&gt;]*)+)*(?(Open)(?!))&lt;/div&gt;</font></span>.</p>
<h2>还有些什么东西没提到</h2>
<p>上边已经描述了构造正则表达式的大量元素，但是还有很多没有提到的东西。下面是一些未提到的元素的列表，包含语法和简单的说明。你可以在网上找到更详细的参考资料来学习它们--当你需要用到它们的时候。如果你安装了MSDN Library,你也可以在里面找到.net下正则表达式详细的文档。</p>
<p class="note">这里的介绍很简略，如果你需要更详细的信息，而又没有在电脑上安装MSDN Library,可以查看<a href="http://msdn.microsoft.com/zh-cn/library/az24scfc.aspx">关于正则表达式语言元素的MSDN在线文档</a>。</p>
<table cellspacing="0">
    <caption>表7.尚未详细讨论的语法</caption>
    <thead>
        <tr>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code"><font color="#0000ff">\a</font></span></td>
            <td><span class="desc"><u>报警字符(打印它的效果是电脑嘀一声)</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\b</font></span></td>
            <td><span class="desc"><u>通常是单词分界位置，但如果在字符类里使用代表退格</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\t</font></span></td>
            <td><span class="desc"><u>制表符，Tab</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\r</font></span></td>
            <td><span class="desc"><u>回车</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\v</font></span></td>
            <td><span class="desc"><u>竖向制表符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\f</font></span></td>
            <td><span class="desc"><u>换页符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\n</font></span></td>
            <td><span class="desc"><u>换行符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\e</font></span></td>
            <td><span class="desc"><u>Escape</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\0nn</font></span></td>
            <td><span class="desc"><u>ASCII代码中八进制代码为nn的字符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\xnn</font></span></td>
            <td><span class="desc"><u>ASCII代码中十六进制代码为nn的字符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\unnnn</font></span></td>
            <td><span class="desc"><u>Unicode代码中十六进制代码为nnnn的字符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\cN</font></span></td>
            <td><span class="desc"><u>ASCII控制字符。比如\cC代表Ctrl+C</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\A</font></span></td>
            <td><span class="desc"><u>字符串开头(类似^，但不受处理多行选项的影响)</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\Z</font></span></td>
            <td><span class="desc"><u>字符串结尾或行尾(不受处理多行选项的影响)</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\z</font></span></td>
            <td><span class="desc"><u>字符串结尾(类似$，但不受处理多行选项的影响)</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\G</font></span></td>
            <td><span class="desc"><u>当前搜索的开头</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\p{name}</font></span></td>
            <td><span class="desc"><u>Unicode中命名为name的字符类，例如\p{IsGreek}</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?&gt;exp)</font></span></td>
            <td><span class="desc"><u>贪婪子表达式</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?&lt;x&gt;-&lt;y&gt;exp)</font></span></td>
            <td><span class="desc"><u>平衡组</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?im-nsx:exp)</font></span></td>
            <td><span class="desc"><u>在子表达式exp中改变处理选项</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?im-nsx)</font></span></td>
            <td><span class="desc"><u>为表达式后面的部分改变处理选项</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?(exp)yes|no)</font></span></td>
            <td><span class="desc"><u>把exp当作零宽正向先行断言，如果在这个位置能匹配，使用yes作为此组的表达式；否则使用no</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?(exp)yes)</font></span></td>
            <td><span class="desc"><u>同上，只是使用空表达式作为no</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?(name)yes|no)</font></span></td>
            <td><span class="desc"><u>如果命名为name的组捕获到了内容，使用yes作为表达式；否则使用no</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">(?(name)yes)</font></span></td>
            <td><span class="desc"><u>同上，只是使用空表达式作为no</u></span></td>
        </tr>
    </tbody>
</table>
<h2>联系作者</h2>
<p>好吧,我承认,我骗了你,读到这里你肯定花了不止30分钟.相信我,这是我的错,而不是因为你太笨.我之所以说&quot;30分钟&quot;,是为了让你有信心,有耐心继续下去.既然你看到了这里,那证明我的阴谋成功了.被忽悠的感觉很爽吧？</p>
<p>要投诉我,或者觉得我其实可以忽悠得更高明,或者有任何其它问题,欢迎来<a href="http://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaocheng.html">我的博客</a>让我知道.</p>
<h2>最后,来点广告……</h2>
<div class="ad"> </div>
<h2>网上的资源及本文参考文献</h2>
<ul>
    <li><a href="http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/jscript7/html/jsreconintroductiontoregularexpressions.asp">微软的正则表达式教程</a></li>
    <li><a href="http://msdn2.microsoft.com/zh-cn/library/system.text.regularexpressions.regex.aspx">System.Text.RegularExpressions.Regex类(MSDN)</a></li>
    <li><a href="http://www.regular-expressions.info/">专业的正则表达式教学网站(英文)</a></li>
    <li><a href="http://weblogs.asp.net/whaggard/archive/2005/02/20/377025.aspx">关于.Net下的平衡组的详细讨论（英文）</a></li>
    <li><a href="http://www.oreilly.com/catalog/regex2/">Mastering Regular Expressions (Second Edition)</a></li>
</ul>
<h2>更新纪录</h2>
<ol>
    <li>2006-3-27 第一版</li>
    <li>2006-10-12 第二版
    <ul>
        <li>修正了几个细节上的错误和不准确的地方</li>
        <li>增加了对处理中文时的一些说明</li>
        <li>更改了几个术语的翻译（采用了MSDN的翻译方式）</li>
        <li>增加了平衡组的介绍</li>
        <li>放弃了对The Regulator的介绍，改用Regex Tester</li>
    </ul>
    </li>
    <li>2007-3-12 V2.1
    <ul>
        <li>修正了几个小的错误</li>
        <li>增加了对处理选项(RegexOptions)的介绍</li>
    </ul>
    </li>
    <li>2007-5-28 V2.2
    <ul>
        <li>重新组织了对零宽断言的介绍</li>
        <li>删除了几个不太合适的示例，添加了几个实用的示例</li>
        <li>其它一些微小的更改</li>
    </ul>
    </li>
    <li>2007-8-3 V2.21
    <ul>
        <li>修改了几处文字错误</li>
        <li>修改/添加了对$,\b的精确说明</li>
        <li>承认了作者是个骗子</li>
        <li>给RegexTester添加了Singleline选项的相关功能</li>
    </ul>
    </li>
    <li>2008-4-13 v2.3
    <ul>
        <li>调整了部分章节的次序</li>
        <li>修改了页面布局，删除了专门的参考节</li>
        <li>针对读者的反馈，调整了部分内容</li>
    </ul>
    </li>
    <li>2009-4-11 v2.31</li>
    <ul>
        <li>修改了几处文字错误</li>
        <li>添加了一些注释说明</li>
        <li>调整了一些措词</li>
    </ul>
</ol>
<p><span ><font size="2">本文转载自：</font><a href="http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm"><font size="1">http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm</font></a></span></p> <a href="http://hi.baidu.com/dongxiang2007/blog/item/1f8dfe1c15000b8387d6b600.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%D1%A7%CF%B0%C0%E0">学习类</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/1f8dfe1c15000b8387d6b600.html#comment">查看评论</a>]]></description>
        <pubDate>2009年05月10日 星期日  下午 02:17</pubDate>
        <category><![CDATA[学习类]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/1f8dfe1c15000b8387d6b600.html</guid>
</item>

<item>
        <title><![CDATA[正则表达式学习(上)]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/9e882fd9542dfe2410df9b05.html]]></link>
        <description><![CDATA[
		
		<h1>正则表达式</h1>
<h1><font size="2">本文转载自：<a href="http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm"><font size="1">http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm</font></a></font></h1>
<ol>
    <li>如何使用本教程</li>
    <li>正则表达式到底是什么东西？</li>
    <li>入门</li>
    <li>测试正则表达式</li>
    <li>元字符</li>
    <li>字符转义</li>
    <li>重复</li>
    <li>字符类</li>
    <li>分枝条件</li>
    <li>反义</li>
    <li>分组</li>
    <li>后向引用</li>
    <li>零宽断言</li>
    <li>负向零宽断言</li>
    <li>注释</li>
    <li>贪婪与懒惰</li>
    <li>处理选项</li>
    <li>平衡组/递归匹配</li>
    <li>还有些什么东西没提到</li>
    <li>联系作者</li>
    <li>最后,来点广告……</li>
    <li>网上的资源及本文参考文献</li>
    <li>更新纪录</li>
</ol>
<h2>本文目标</h2>
<p>30分钟内让你明白正则表达式是什么，并对它有一些基本的了解，让你可以在自己的程序或网页里使用它。</p>
<h2>如何使用本教程</h2>
<p class="important note">最重要的是&mdash;&mdash;请给我<strong>30分钟</strong>，如果你没有使用正则表达式的经验，请不要试图在30<strong>秒</strong>内入门&mdash;&mdash;除非你是超人 :)</p>
<p>别被下面那些复杂的表达式吓倒，只要跟着我一步一步来，你会发现正则表达式其实并<span>没有</span>你想像中的那么困难。当然，如果你看完了这篇教程之后，发现自己明白了很多，却又几乎什么都记不得，那也是很正常的&mdash;&mdash;我认为，没接触过正则表达式的人在看完这篇教程后，能把提到过的语法记住80%以上的可能性为零。这里只是让你明白基本的原理，以后你还需要多练习，多使用，才能熟练掌握正则表达式。</p>
<p>除了作为入门教程之外，本文还试图成为可以在日常工作中使用的正则表达式语法参考手册。就作者本人的经历来说，这个目标还是完成得不错的&mdash;&mdash;你看，我自己也没能把所有的东西记下来，不是吗？</p>
<p><a href="http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm"><font style="background-color: #eeeeee">清除格式</font></a> 文本格式约定：<span class="name"><strong>专业术语</strong></span> <span class="code"><font color="#0000ff">元字符/语法格式</font></span> <span class="regex"><font color="#ff0000">正则表达式</font></span> <span class="part"><font color="#008000">正则表达式中的一部分(用于分析)</font></span> <span class="string"><em>对其进行匹配的源字符串</em></span> <span class="desc"><u>对正则表达式或其中一部分的说明</u></span></p>
<p><a href="http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm"><font style="background-color: #eeeeee">隐藏边注</font></a> 本文右边有一些注释，主要是用来提供一些相关信息，或者给没有程序员背景的读者解释一些基本概念，通常可以忽略。</p>
<h2>正则表达式到底是什么东西？</h2>
<p class="note"><span class="name"><strong>字符</strong></span>是计算机软件处理文字时最基本的单位，可能是字母，数字，标点符号，空格，换行符，汉字等等。<span class="name"><strong>字符串</strong></span>是0个或更多个字符的序列。<span class="name"><strong>文本</strong></span>也就是文字，字符串。说某个字符串<span class="name"><strong>匹配</strong></span>某个正则表达式，通常是指这个字符串里有一部分（或几部分分别）能满足表达式给出的条件。</p>
<p>在编写处理字符串的程序或网页时，经常会有查找符合某些复杂规则的字符串的需要。<span class="name"><strong>正则表达式</strong></span>就是用于描述这些规则的工具。换句话说，正则表达式就是记录文本规则的代码。</p>
<p>很可能你使用过Windows/Dos下用于文件查找的<span class="name"><strong>通配符(wildcard)</strong></span>，也就是<span class="code"><font color="#0000ff">*</font></span>和<span class="code"><font color="#0000ff">?</font></span>。如果你想查找某个目录下的所有的Word文档的话，你会搜索<span style="color: red">*.doc</span>。在这里，<span class="code"><font color="#0000ff">*</font></span>会被解释成任意的字符串。和通配符类似，正则表达式也是用来进行文本匹配的工具，只不过比起通配符，它能更精确地描述你的需求&mdash;&mdash;当然，代价就是更复杂&mdash;&mdash;比如你可以编写一个正则表达式，用来查找<span class="desc"><u>所有以0开头，后面跟着2-3个数字，然后是一个连字号&ldquo;-&rdquo;，最后是7或8位数字的字符串</u></span>(像<span class="string"><em>010-12345678</em></span>或<span class="string"><em>0376-7654321</em></span>)。</p>
<h2>入门</h2>
<p>学习正则表达式的最好方法是从例子开始，理解例子之后再自己对例子进行修改，实验。下面给出了不少简单的例子，并对它们作了详细的说明。</p>
<p>假设你在一篇英文小说里查找<span class="desc"><u>hi</u></span>，你可以使用正则表达式<span class="regex"><font color="#ff0000">hi</font></span>。</p>
<p>这几乎是最简单的正则表达式了，它可以精确匹配这样的字符串：<span class="desc"><u>由两个字符组成，前一个字符是h,后一个是i</u></span>。通常，处理正则表达式的工具会提供一个忽略大小写的选项，如果选中了这个选项，它可以匹配<span class="string"><em>hi</em></span>,<span class="string"><em>HI</em></span>,<span class="string"><em>Hi</em></span>,<span class="string"><em>hI</em></span>这四种情况中的任意一种。</p>
<p>不幸的是，很多单词里包含<span class="string"><em>hi</em></span>这两个连续的字符，比如<span class="string"><em>him</em></span>,<span class="string"><em>history</em></span>,<span class="string"><em>high</em></span>等等。用<span class="regex"><font color="#ff0000">hi</font></span>来查找的话，这里边的<span class="string"><em>hi</em></span>也会被找出来。如果要<span class="desc"><u>精确地查找hi这个单词</u></span>的话，我们应该使用<span class="regex"><font color="#ff0000">\bhi\b</font></span>。</p>
<p><span class="part"><font color="#008000">\b</font></span>是正则表达式规定的一个特殊代码（好吧，某些人叫它<span class="name"><strong>元字符，metacharacter</strong></span>），代表着<span class="desc"><u>单词的开头或结尾，也就是单词的分界处</u></span>。虽然通常英文的单词是由空格，标点符号或者换行来分隔的，但是<span class="code"><font color="#0000ff">\b</font></span>并不匹配这些单词分隔字符中的任何一个，它<strong>只匹配一个位置</strong>。</p>
<p class="note">如果需要更精确的说法，<span class="code"><font color="#0000ff">\b</font></span>匹配这样的位置：它的前一个字符和后一个字符不全是(一个是,一个不是或不存在)<span class="code"><font color="#0000ff">\w</font></span>。</p>
<p>假如你要找的是<span class="desc"><u>hi后面不远处跟着一个Lucy</u></span>，你应该用<span class="regex"><font color="#ff0000">\bhi\b.*\bLucy\b</font></span>。</p>
<p>这里，<span class="part"><font color="#008000">.</font></span>是另一个元字符，匹配<span class="desc"><u>除了换行符以外的任意字符</u></span>。<span class="part"><font color="#008000">*</font></span>同样是元字符，不过它代表的不是字符，也不是位置，而是数量&mdash;&mdash;它指定*<span class="desc"><u>前边的内容可以连续重复使用任意次以使整个表达式得到匹配</u></span>。因此，<span class="part"><font color="#008000">.*</font></span>连在一起就意味着<span class="desc"><u>任意数量的不包含换行的字符</u></span>。现在<span class="regex"><font color="#ff0000">\bhi\b.*\bLucy\b</font></span>的意思就很明显了：<span class="desc"><u>先是一个单词hi,然后是任意个任意字符(但不能是换行)，最后是Lucy这个单词</u></span>。</p>
<p class="note">换行符就是'\n',ASCII编码为10(十六进制0x0A)的字符。</p>
<p>如果同时使用其它元字符，我们就能构造出功能更强大的正则表达式。比如下面这个例子：</p>
<p><span class="regex"><font color="#ff0000">0\d\d-\d\d\d\d\d\d\d\d</font></span>匹配这样的字符串：<span class="desc"><u>以0开头，然后是两个数字，然后是一个连字号&ldquo;-&rdquo;，最后是8个数字</u></span>(也就是中国的电话号码。当然，这个例子只能匹配区号为3位的情形)。</p>
<p>这里的<span class="part"><font color="#008000">\d</font></span>是个新的元字符，匹配<span class="desc"><u>一位数字(0，或1，或2，或……)</u></span>。<span class="part"><font color="#008000">-</font></span>不是元字符，只匹配它本身&mdash;&mdash;连字符(或者减号，或者中横线，或者随你怎么称呼它)。</p>
<p>为了避免那么多烦人的重复，我们也可以这样写这个表达式：<span class="regex"><font color="#ff0000">0\d{2}-\d{8}</font></span>。 这里<span class="part"><font color="#008000">\d</font></span>后面的<span class="part"><font color="#008000">{2}</font></span>(<span class="part"><font color="#008000">{8}</font></span>)的意思是前面<span class="part"><font color="#008000">\d</font></span><span class="desc"><u>必须连续重复匹配2次(8次)</u></span>。</p>
<h2>测试正则表达式</h2>
<div class="note">
<p>其它可用的测试工具:</p>
<ul>
    <li><a href="http://www.regexbuddy.com/">RegexBuddy</a></li>
    <li><a href="http://regexpal.com/">Javascript正则表达式在线测试工具</a></li>
</ul>
</div>
<p>如果你不觉得正则表达式很难读写的话，要么你是一个天才，要么，你不是地球人。正则表达式的语法很令人头疼，即使对经常使用它的人来说也是如此。由于难于读写，容易出错，所以找一种工具对正则表达式进行测试是很有必要的。</p>
<p>不同的环境下正则表达式的一些细节是不相同的，本教程介绍的是微软 .Net Framework 2.0下正则表达式的行为，所以，我向你介绍一个.Net下的工具<a title="转到RegexTester的官方网站(英文)" href="http://www.dotnet2themax.com/blogs/fbalena/PermaLink,guid,13bce26d-7755-441e-92b3-1eb5f9e859f9.aspx">Regex Tester</a>。首先你确保已经安装了<a title="转到下载.Net Framework 2.0的页面" href="http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&amp;FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5">.Net Framework 2.0</a>，然后<a title="从www.unibetter.com下载Regex Tester, 75KB" href="http://www.unibetter.com/deerchao/downloads/RegexTester.zip">下载Regex Tester</a>。这是个绿色软件，下载完后打开压缩包,直接运行RegexTester.exe就可以了。</p>
<p>下面是Regex Tester运行时的截图：</p>
<p><img alt="Regex Tester运行时的截图" src="http://www.unibetter.com/deerchao/images/RegexTester.jpg"></p>
<h2>元字符</h2>
<p>现在你已经知道几个很有用的元字符了，如<span class="code"><font color="#0000ff">\b</font></span>,<span class="code"><font color="#0000ff">.</font></span>,<span class="code"><font color="#0000ff">*</font></span>，还有<span class="code"><font color="#0000ff">\d</font></span>.正则表达式里还有更多的元字符，比如<span class="code"><font color="#0000ff">\s</font></span>匹配<span class="desc"><u>任意的空白符，包括空格，制表符(Tab)，换行符，中文全角空格等</u></span>。<span class="code"><font color="#0000ff">\w</font></span>匹配<span class="desc"><u>字母或数字或下划线或汉字等</u></span>。</p>
<p class="note important">对中文/汉字的特殊处理是由.Net提供的正则表达式引擎支持的，其它环境下的具体情况请查看相关文档。</p>
<p>下面来看看更多的例子：</p>
<p><span class="regex"><font color="#ff0000">\ba\w*\b</font></span>匹配<span class="desc"><u>以字母<span class="part"><font color="#008000">a</font></span>开头的单词&mdash;&mdash;先是某个单词开始处(<span class="part"><font color="#008000">\b</font></span>)，然后是字母<span class="part"><font color="#008000">a</font></span>,然后是任意数量的字母或数字(<span class="part"><font color="#008000">\w*</font></span>)，最后是单词结束处(<span class="part"><font color="#008000">\b</font></span>)</u></span>。</p>
<p class="note">好吧，现在我们说说正则表达式里的单词是什么意思吧：就是不少于一个的连续的<span class="code"><font color="#0000ff">\w</font></span>。不错，这与学习英文时要背的成千上万个同名的东西的确关系不大 :)</p>
<p><span class="regex"><font color="#ff0000">\d+</font></span>匹配<span class="desc"><u>1个或更多连续的数字</u></span>。这里的<span class="part"><font color="#008000">+</font></span>是和<span class="code"><font color="#0000ff">*</font></span>类似的元字符，不同的是<span class="code"><font color="#0000ff">*</font></span>匹配<span class="desc"><u>重复任意次(可能是0次)</u></span>，而<span class="code"><font color="#0000ff">+</font></span>则匹配<span class="desc"><u>重复1次或更多次</u></span>。</p>
<p><span class="regex"><font color="#ff0000">\b\w{6}\b</font></span> 匹配<span class="desc"><u>刚好6个字符的单词</u></span>。</p>
<table cellspacing="0">
    <caption>表1.常用的元字符</caption>
    <thead>
        <tr>
            <th scope="col">代码</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code"><font color="#0000ff">.</font></span></td>
            <td><span class="desc"><u>匹配除换行符以外的任意字符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\w</font></span></td>
            <td><span class="desc"><u>匹配字母或数字或下划线或汉字</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\s</font></span></td>
            <td><span class="desc"><u>匹配任意的空白符</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\d</font></span></td>
            <td><span class="desc"><u>匹配数字</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">\b</font></span></td>
            <td><span class="desc"><u>匹配单词的开始或结束</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">^</font></span></td>
            <td><span class="desc"><u>匹配字符串的开始</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">$</font></span></td>
            <td><span class="desc"><u>匹配字符串的结束</u></span></td>
        </tr>
    </tbody>
</table>
<p class="note">正则表达式引擎通常会提供一个&ldquo;测试指定的字符串是否匹配一个正则表达式&rdquo;的方法，如JavaScript里的RegExp.test()方法或.NET里的Regex.IsMatch()方法。这里的匹配是指是字符串里有没有符合表达式规则的部分。如果不使用<span class="code"><font color="#0000ff">^</font></span>和<span class="code"><font color="#0000ff">$</font></span>的话，对于<span class="regex"><font color="#ff0000">\d{5,12}</font></span>而言，使用这样的方法就只能保证字符串里<span class="desc"><u>包含5到12连续位数字</u></span>，而不是整个字符串就是5到12位数字。</p>
<p>元字符<span class="code"><font color="#0000ff">^</font></span>（和数字6在同一个键位上的符号）和<span class="code"><font color="#0000ff">$</font></span>都匹配一个位置，这和<span class="code"><font color="#0000ff">\b</font></span>有点类似。<span class="code"><font color="#0000ff">^</font></span>匹配你要用来查找的字符串的开头，<span class="code"><font color="#0000ff">$</font></span>匹配结尾。这两个代码在验证输入的内容时非常有用，比如一个网站如果要求你填写的QQ号必须为5位到12位数字时，可以使用：<span class="regex"><font color="#ff0000">^\d{5,12}$</font></span>。</p>
<p>这里的<span class="part"><font color="#008000">{5,12}</font></span>和前面介绍过的<span class="part"><font color="#008000">{2}</font></span>是类似的，只不过<span class="part"><font color="#008000">{2}</font></span>匹配<span class="desc"><u>只能不多不少重复2次</u></span>，<span class="part"><font color="#008000">{5,12}</font></span>则是<span class="desc"><u>重复的次数不能少于5次，不能多于12次</u></span>，否则都不匹配。</p>
<p>因为使用了<span class="part"><font color="#008000">^</font></span>和<span class="part"><font color="#008000">$</font></span>，所以输入的整个字符串都要用来和<span class="part"><font color="#008000">\d{5,12}</font></span>来匹配，也就是说整个输入<span class="desc"><u>必须是5到12个数字</u></span>，因此如果输入的QQ号能匹配这个正则表达式的话，那就符合要求了。</p>
<p>和忽略大小写的选项类似，有些正则表达式处理工具还有一个处理多行的选项。如果选中了这个选项，<span class="code"><font color="#0000ff">^</font></span>和<span class="code"><font color="#0000ff">$</font></span>的意义就变成了<span class="desc"><u>匹配行的开始处和结束处</u></span>。</p>
<h2>字符转义</h2>
<p>如果你想查找元字符本身的话，比如你查找<span class="desc"><u>.</u></span>,或者<span class="desc"><u>*</u></span>,就出现了问题：你没办法指定它们，因为它们会被解释成别的意思。这时你就得使用<span class="code"><font color="#0000ff">\</font></span>来取消这些字符的特殊意义。因此，你应该使用<span class="regex"><font color="#ff0000">\.</font></span>和<span class="regex"><font color="#ff0000">\*</font></span>。当然，要查找<span class="desc"><u>\</u></span>本身，你也得用<span class="regex"><font color="#ff0000">\\</font></span>.</p>
<p>例如：<span class="regex"><font color="#ff0000">unibetter\.com</font></span>匹配<span class="desc"><u>unibetter.com</u></span>，<span class="regex"><font color="#ff0000">C:\\Windows</font></span>匹配<span class="desc"><u>C:\Windows</u></span>。</p>
<h2>重复</h2>
<p>你已经看过了前面的<span class="code"><font color="#0000ff">*</font></span>,<span class="code"><font color="#0000ff">+</font></span>,<span class="code"><font color="#0000ff">{2}</font></span>,<span class="code"><font color="#0000ff">{5,12}</font></span>这几个匹配重复的方式了。下面是正则表达式中所有的限定符(指定数量的代码，例如*,{5,12}等)：</p>
<table cellspacing="0">
    <caption>表2.常用的限定符</caption>
    <thead>
        <tr>
            <th scope="col">代码/语法</th>
            <th scope="col">说明</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><span class="code"><font color="#0000ff">*</font></span></td>
            <td><span class="desc"><u>重复零次或更多次</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">+</font></span></td>
            <td><span class="desc"><u>重复一次或更多次</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">?</font></span></td>
            <td><span class="desc"><u>重复零次或一次</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">{n}</font></span></td>
            <td><span class="desc"><u>重复n次</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">{n,}</font></span></td>
            <td><span class="desc"><u>重复n次或更多次</u></span></td>
        </tr>
        <tr>
            <td><span class="code"><font color="#0000ff">{n,m}</font></span></td>
            <td><span class="desc"><u>重复n到m次</u></span></td>
        </tr>
    </tbody>
</table>
<p>下面是一些使用重复的例子：</p>
<p><span class="regex"><font color="#ff0000">Windows\d+</font></span>匹配<span class="desc"><u>Windows后面跟1个或更多数字</u></span></p>
<p><span class="regex"><font color="#ff0000">^\w+</font></span>匹配<span class="desc"><u>一行的第一个单词(或整个字符串的第一个单词，具体匹配哪个意思得看选项设置)</u></span></p>
<h2>字符类</h2>
<p>要想查找数字，字母或数字，空白是很简单的，因为已经有了对应这些字符集合的元字符，但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办？</p>
<p>很简单，你只需要在方括号里列出它们就行了，像<span class="regex"><font color="#ff0000">[aeiou]</font></span>就匹配<span class="desc"><u>任何一个英文元音字母</u></span>，<span class="regex"><font color="#ff0000">[.?!]</font></span>匹配<span class="desc"><u>标点符号(.或?或!)</u></span>。</p>
<p>我们也可以轻松地指定一个字符<span class="name"><strong>范围</strong></span>，像<span class="regex"><font color="#ff0000">[0-9]</font></span>代表的含意与<span class="regex"><font color="#ff0000">\d</font></span>就是完全一致的：<span class="desc"><u>一位数字</u></span>；同理<span class="regex"><font color="#ff0000">[a-z0-9A-Z_]</font></span>也完全等同于<span class="code"><font color="#0000ff">\w</font></span>（如果只考虑英文的话）。</p>
<p>下面是一个更复杂的表达式：<span class="regex"><font color="#ff0000">\(?0\d{2}[) -]?\d{8}</font></span>。</p>
<p class="note">&ldquo;(&rdquo;和&ldquo;)&rdquo;也是元字符，后面的<a href="http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#grouping">分组节</a>里会提到，所以在这里需要使用<a href="http://www.unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm#escape">转义</a>。</p>
<p>这个表达式可以匹配<span class="desc"><u>几种格式的电话号码</u></span>，像<span class="string"><em>(010)88886666</em></span>，或<span class="string"><em>022-22334455</em></span>，或<span class="string"><em>02912345678</em></span>等。我们对它进行一些分析吧：首先是一个转义字符<span class="part"><font color="#008000">\(</font></span>,它能出现0次或1次(<span class="part"><font color="#008000">?</font></span>),然后是一个<span class="part"><font color="#008000">0</font></span>，后面跟着2个数字(<span class="part"><font color="#008000">\d{2}</font></span>)，然后是<span class="part"><font color="#008000">)</font></span>或<span class="part"><font color="#008000">-</font></span>或<span class="part"><font color="#008000">空格</font></span>中的一个，它出现1次或不出现(<span class="part"><font color="#008000">?</font></span>)，最后是8个数字(<span class="part"><font color="#008000">\d{8}</font></span>)。</p>
<h2>分枝条件</h2>
<p>不幸的是，刚才那个表达式也能匹配<span class="string"><em>010)12345678</em></span>或<span class="string"><em>(022-87654321</em></span>这样的&ldquo;不正确&rdquo;的格式。要解决这个问题，我们需要用到<span class="name"><strong>分枝条件</strong></span>。正则表达式里的<span class="name"><strong>分枝条件</strong></span>指的是有几种规则，如果满足其中任意一种规则都应该当成匹配，具体方法是用<span class="code"><font color="#0000ff">|</font></span>把不同的规则分隔开。听不明白？没关系，看例子：</p>
<p><span class="regex"><font color="#ff0000">0\d{2}-\d{8}|0\d{3}-\d{7}</font></span>这个表达式能<span class="desc"><u>匹配两种以连字号分隔的电话号码：一种是三位区号，8位本地号(如010-12345678)，一种是4位区号，7位本地号(0376-2233445)</u></span>。</p>
<p><span class="regex"><font color="#ff0000">\(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}</font></span>这个表达式<span class="desc"><u>匹配3位区号的电话号码，其中区号可以用小括号括起来，也可以不用，区号与本地号间可以用连字号或空格间隔，也可以没有间隔</u></span>。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。</p>
<p><span class="regex"><font color="#ff0000">\d{5}-\d{4}|\d{5}</font></span>这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字，或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题：<strong>使用分枝条件时，要注意各个条件的顺序</strong>。如果你把它改成<span class="regex"><font color="#ff0000">\d{5}|\d{5}-\d{4}</font></span>的话，那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时，将会从左到右地测试每个条件，如果满足了某个分枝的话，就不会去再管其它的条件了。</p> <a href="http://hi.baidu.com/dongxiang2007/blog/item/9e882fd9542dfe2410df9b05.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%D1%A7%CF%B0%C0%E0">学习类</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/9e882fd9542dfe2410df9b05.html#comment">查看评论</a>]]></description>
        <pubDate>2009年05月10日 星期日  下午 02:13</pubDate>
        <category><![CDATA[学习类]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/9e882fd9542dfe2410df9b05.html</guid>
</item>

<item>
        <title><![CDATA[仓库管理系统 VC++ 和数据库编程]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/668a1a2c784041eb8b139965.html]]></link>
        <description><![CDATA[
		
		<p><font face="宋体" size="3">大三上学期的课程设计，做得比较简单主要是为了熟悉一下数据库编程的一些方法。</font></p>
<font face="宋体">
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span>程序运行环境：</span><span><font face="Calibri">SQL Server 2000<span style="mso-spacerun: yes"> </span>Windows XP</font></span><span>。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span>配置数据源：将&ldquo;仓库管理系统</span><span><font face="Calibri">_Data.MDF</font></span><span>&rdquo;文件添加进</span><span><font face="Calibri">ODBC</font></span><span>数据源</span><font face="Calibri"> </font><span>数据源和数据库名</span><span>都叫</span><font face="Calibri"> <span>&ldquo;</span></font><span>仓库管理系统</span><span><font face="Calibri">&rdquo;</font></span><span>。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; mso-list: l0 level1 lfo1"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-list: Ignore"><font face="Calibri">一、</font></span></span><span style="mso-ascii-: 10.5pt">登录界面</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style="mso-ascii-: 10.5pt">用户登录分两种权限，管理员和普通用户。管理员用户登录到系统后，拥有对数据的增加、删除、修改和添加新的普通用户的权限。普通用户只具有查看、录入、提出物资的权限，没有增加、删除、修改等权限。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style="mso-ascii-: 10.5pt">管理员用户的登录界面如下图： </span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><font size="3"><font face="Calibri"><span style="mso-tab-count: 3">&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <a target="_blank" href="http://hiphotos.baidu.com/dongxiang2007/pic/item/061c9b886bb4beb4a5c27261.jpg"><img class="blogimg" border="0" small="1" src="http://hiphotos.baidu.com/dongxiang2007/abpic/item/5ca58ece787ec52392457e99.jpg"></a></span></font></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 3"><font face="Calibri" size="3">&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;  </font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"> </p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">程序中涉及到的密码都与用户名相同。</span><span style="mso-bidi-font-size: 10.5pt"><font face="Calibri"> </font></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"> </p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; mso-list: l0 level1 lfo1"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-list: Ignore"><font face="Calibri">二、</font></span></span><span style="mso-ascii-: 10.5pt">仓库管理系统主界面 </span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; mso-list: l0 level1 lfo1"><font size="3"><span style="mso-ascii-: 10.5pt">&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;  <img class="blogimg" border="0" small="1" src="http://hiphotos.baidu.com/dongxiang2007/abpic/item/061c9b886bb4beb4a5c27261.jpg"></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style="mso-ascii-: 10.5pt">以管理员用户登录后，进入主界面，在主界面中有操作菜单，可以添加、修改、删除供应商和销售商的基本信息，可以执行入库和出库操作，可以指定普通用户和管理员用户，可以查看和删除日志信息。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style="mso-ascii-: 10.5pt">以普通用户登录后，进入主界面，上面相应的添加、修改、删除和添加用户权限将被禁用，普通用户只允许执行入库和出库操作，其他的就是查询浏览了。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"> </p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"> </p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">管理员用户操作：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 3"><font face="Calibri" size="3">&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;  </font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">入库操作：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">出库操作：</span><span style="mso-bidi-font-size: 10.5pt"><font face="Calibri">`</font></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">供应商信息：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">供应商信息添加：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">供应商信息删除：选定后点击删除即可</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">供应商信息修改：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style="mso-ascii-: 10.5pt">对信息进行了改动只后点击&ldquo;保存&rdquo;即可写入数据表中。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style="mso-ascii-: 10.5pt">添加销售商的信息过程类似，这里不累述了。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">添加用户操作：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">查看日志信息：</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-bidi-font-size: 10.5pt"><span style="mso-tab-count: 1"><font face="Calibri">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  </font></span></span><span style="mso-ascii-: 10.5pt">管理员可以选择删除一些没用的日志。选择要删除的日志，点击删除即可。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">到这里介绍完了本软件的所有功能。</span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt"><font size="3"><span style="mso-ascii-: 10.5pt">注意：运行系统是必须先要在</span><span style="mso-bidi-font-size: 10.5pt"><font face="Calibri">ODBC</font></span><span style="mso-ascii-: 10.5pt">中添加数据源，运行本软件的计算机必须装有</span><span style="mso-bidi-font-size: 10.5pt"><font face="Calibri">SQL server2000</font></span><span style="mso-ascii-: 10.5pt">。</span></font></p>
<p>要讨论的请发邮件：<a href="mailto:dongxiang_2007@163.com">dongxiang_2007@163.com</a></p>
<p> </p>
<p> </p>
<div forimg="1" align="center"> </div>
<div forimg="1" align="center"> </div>
</font> <a href="http://hi.baidu.com/dongxiang2007/blog/item/668a1a2c784041eb8b139965.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%BF%CE%B3%CC%C9%E8%BC%C6">课程设计</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/668a1a2c784041eb8b139965.html#comment">查看评论</a>]]></description>
        <pubDate>2009年02月17日 星期二  下午 01:23</pubDate>
        <category><![CDATA[课程设计]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/668a1a2c784041eb8b139965.html</guid>
</item>

<item>
        <title><![CDATA[排列组合 递归]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/a1738b5cfcb0cd45fbf2c08d.html]]></link>
        <description><![CDATA[
		
		<p>#include&quot;iostream.h&quot;<br>
void Swap(int &amp;a,int &amp;b)<br>
{<br>
 int temp=a;<br>
 a=b;<br>
 b=temp;<br>
}<br>
void Perm(int list[],int k,int m)<br>
{<br>
 if(k==m)<br>
 {<br>
&nbsp;&nbsp; for(int i=0;i&lt;=m;i++)<br>
&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; cout &lt;&lt;list[i];<br>
&nbsp;&nbsp; }<br>
&nbsp;&nbsp; cout &lt;&lt;endl;<br>
 }<br>
 else<br>
 {<br>
&nbsp;&nbsp; for(int i=k;i&lt;=m;i++)<br>
&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; Swap(list[k],list[i]);<br>
&nbsp;&nbsp;&nbsp; Perm(list,k+1,m);<br>
&nbsp;&nbsp;&nbsp; Swap(list[k],list[i]);<br>
&nbsp;&nbsp; }<br>
 }<br>
}</p>
<p>int main()<br>
{<br>
 int list[6]={1,2,3,4,5,6};<br>
 Perm(list,0,4);<br>
 return 0;<br>
}</p> <a href="http://hi.baidu.com/dongxiang2007/blog/item/a1738b5cfcb0cd45fbf2c08d.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%D1%A7%CF%B0%C0%E0">学习类</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/a1738b5cfcb0cd45fbf2c08d.html#comment">查看评论</a>]]></description>
        <pubDate>2008年09月14日 星期日  下午 05:42</pubDate>
        <category><![CDATA[学习类]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/a1738b5cfcb0cd45fbf2c08d.html</guid>
</item>

<item>
        <title><![CDATA[C文件操作]]></title>
        <link><![CDATA[http://hi.baidu.com/dongxiang2007/blog/item/1edbf40112872306738da513.html]]></link>
        <description><![CDATA[
		
		<h2 class="diaryTitle"> </h2>
<h2 class="diaryTitle"><font size="2">1.2  文件的输入输出函数<br>
<br>
&nbsp;&nbsp;&nbsp;  键盘、显示器、打印机、磁盘驱动器等逻辑设备, 其输入输出都可以通过文件管理的方法来完成。而在编程时使用最多的要算<br>
是磁盘文件, 因此本节主要以磁盘文件为主, 详细介绍Turbo C2.0提供的文件操作函数, 当然这些对文件的操作函数也适合于非磁<br>
盘文件的情况。<br>
&nbsp;&nbsp;&nbsp;  另外, Turbo C2.0提供了两类关于文件的函数。一类称做标准文件函数也称缓冲型文件函数, 这是ANSI标准定义的函数; 另一<br>
类叫非标准文件函数, 也称非缓冲型文件函数。这类函数最早公用于UNIX操作系统, 但现在MS-DOS3.0 以上版本的操作系统也可以<br>
使用。下面分别进行介绍。<br>
<br>
&nbsp;&nbsp;&nbsp;  1.2.1  标准文件函数<br>
&nbsp;&nbsp;&nbsp;  标准文件函数主要包括文件的打开、关闭、读和写等函数。不象BASIC 、FORTRAN语方有顺序文件和随机文件之分, 在打开时<br>
就应按不同的方式确定。Turbo C2.0并不区分这两种文件, 但提供了两组函数, 即顺序读写函数和随机读写函数。<br>
<br>
&nbsp;&nbsp;&nbsp;  一、文件的打开和关闭<br>
&nbsp;&nbsp;&nbsp;  任何一个文件在使用之前和使用之后, 必须要进行打开和关闭, 这是因为操作系统对于同时打开的文件数目是有限制的, DOS<br>
操作系统中, 可以在DEVICE.SYS中定义允许同时打开的文件数n(用files=n定义)。其中n 为可同时打开的文件数, 一般n&lt;=20。因<br>
此在使用文件前应打开文件, 才可对其中的信息进行存取。 用完之后需要关闭, 否则将会出现一些意想不到的错误。Turbo C2.0<br>
提供了打开和关闭文件的函数。<br>
<br>
&nbsp;&nbsp;&nbsp;  1. fopen()函数<br>
&nbsp;&nbsp;&nbsp;  fopen函数用于打开文件, 其调用格式为:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  FILE *fopen(char *filename, *type);<br>
<br>
&nbsp;&nbsp;&nbsp;  在介绍这个函数之前, 先了解一下下面的知识。<br>
<br>
&nbsp;&nbsp;&nbsp;  (1) 流(stream)和文件(file)<br>
&nbsp;&nbsp;&nbsp;  流和文件在Turbo C2.0中是有区别的, Turbo C2.0 为编程者和被访问的设备之间提供了一层抽象的东西, 称之为&quot;流&quot;, 而将<br>
具体的实际设备叫做文件。流是一个逻辑设备, 具有相同的行为。因此,用来进行磁盘文件写的函数也同样可以用来进行打印机的<br>
写入。在Turbo C2.0中有两种性质的流: 文字流(text stream)和二进制(binary stream)。 对磁盘来说就是文本文件和二进制文<br>
件。本软件为了便于让读者易理解Turbo C2.0语言而没有对流和文件作特别区分。<br>
<br>
&nbsp;&nbsp;&nbsp;  (2) 文件指针FILE<br>
&nbsp;&nbsp;&nbsp;  实际上FILE是一个新的数据类型。它是Turbo C2.0的基本数据类型的集合, 称之为结构指针。有关结构的概念将在第四节中详<br>
细介绍, 这里只要将FILE理解为一个包括了文件管理有关信息的数据结构, 即在打开文件时必须先定义一个文件指针。<br>
<br>
&nbsp;&nbsp;&nbsp;  (3) 以后介绍的函数调用格式将直接写出形式参数的数据类型和函数返回值的数据类型。例如: 上面打开文件的函数, 返回一<br>
个文件指针, 其中形式参数有两个, 均为字符型变量(字符串数组或字符串指针)。本软件不再对函数的调用格式作详细说明。<br>
<br>
&nbsp;&nbsp;&nbsp;  现在再来看打开文件函数的用法。<br>
&nbsp;&nbsp;&nbsp;  fopen()函数中第一个形式参数表示文件名, 可以包含路径和文件名两部分。<br>
如:<br>
&nbsp;&nbsp;&nbsp;&nbsp;  &quot;B:TEST.DAT&quot;<br>
&nbsp;&nbsp;&nbsp;&nbsp;  &quot;C:\\TC\\TEST.DAT&quot;<br>
&nbsp;&nbsp;&nbsp;  如果将路径写成&quot;C:\TC\TEST.DAT&quot;是不正确的, 这一点要特别注意。<br>
&nbsp;&nbsp;&nbsp;  第二个形式参数表示打开文件的类型。关于文件类型的规定参见下表。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  表  文件操作类型<br>
&nbsp;&nbsp;&nbsp;  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  字符&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  含义<br>
&nbsp;&nbsp;&nbsp;  ────────────────────────────<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &quot;r&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  打开文字文件只读<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &quot;w&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  创建文字文件只写<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &quot;a&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  增补, 如果文件不存在则创建一个<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &quot;r+&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  打开一个文字文件读/写<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &quot;w+&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  创建一个文字文件读/写<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &quot;a+&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  打开或创建一个文件增补<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &quot;b&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  二进制文件(可以和上面每一项合用)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &quot;t&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  文这文件(默认项)<br>
&nbsp;&nbsp;&nbsp;  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━<br>
&nbsp;&nbsp;&nbsp;  如果要打开一个CCDOS子目录中, 文件名为CLIB的二进制文件, 可写成:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  fopen(&quot;c:\\ccdos\\clib&quot;, &quot;rb&quot;);<br>
<br>
&nbsp;&nbsp;&nbsp;  如果成功的打开一个文件, fopen()函数返回文件指针, 否则返回空指针(NULL)。由此可判断文件打开是否成功。<br>
<br>
&nbsp;&nbsp;&nbsp;  2. fclose()函数<br>
&nbsp;&nbsp;&nbsp;  fclose()函数用来关闭一个由fopen()函数打开的文件 , 其调用格式为:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  int fclose(FILE *stream);<br>
<br>
&nbsp;&nbsp;&nbsp;  该函数返回一个整型数。当文件关闭成功时, 返回0,　否则返回一个非零值。可以根据函数的返回值判断文件是否关闭成功。<br>
<br>
&nbsp;&nbsp;&nbsp;  例10:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  #iclude<stdio.h></stdio.h><br>
&nbsp;&nbsp;&nbsp;&nbsp;  main()<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  FILE *fp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*定义一个文件指针*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  int i;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fp=fopen(&quot;CLIB&quot;, &quot;rb&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*打开当前目录名为CLIB的文件只读*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if(fp==NULL)&nbsp;&nbsp;&nbsp;&nbsp;&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;  puts(&quot;File open error&quot;);  /*提示打开不成功*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  i=fclose(fp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*关闭打开的文件*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if(i==0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*判断文件是否关闭成功*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;O,K&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*提示关闭成功*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  puts(&quot;File close error&quot;);  /*提示关闭不成功*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
<br>
&nbsp;&nbsp;&nbsp;  二、有关文件操作的函数<br>
&nbsp;&nbsp;&nbsp;  本节所讲的文件读写函数均是指顺序读写, 即读写了一条信息后, 指针自动加1。下面分别介绍写操作函数和读操作函数。<br>
<br>
&nbsp;&nbsp;&nbsp;  1. 文件的顺序写函数<br>
&nbsp;&nbsp;&nbsp;  fprintf()、fputs()和fputc()函数<br>
<br>
&nbsp;&nbsp;&nbsp;  函数fprintf()、fputs()和fputc()均为文件的顺序写操作函数, 其调用格式如下:<br>
<br>
&nbsp;&nbsp;&nbsp;  int fprintf(FILE *stream, char *format, <variable-list></variable-list>);<br>
&nbsp;&nbsp;&nbsp;  int fputs(char *string, FILE *steam);<br>
&nbsp;&nbsp;&nbsp;  int fputc(int ch, FILE *steam);<br>
<br>
&nbsp;&nbsp;&nbsp;  上述三个函数的返回值均为整型量。fprintf() 函数的返回值为实际写入文件中的字罕个数(字节数)。如果写错误, 则返回一<br>
个负数, fputs()函数返回0时表明将string指针所指的字符串写入文件中的操作成功, 返回非0时, 表明写操作失败。fputc()函数<br>
返回一个向文件所写字符的值, 此时写操作成功, 否则返回EOF(文件结束结束其值为-1, 在stdio.h中定义)表示写操作错误。<br>
&nbsp;&nbsp;&nbsp;&nbsp;  fprintf( ) 函数中格式化的规定与printf( ) 函数相同, 所不同的只是fprintf()函数是向文件中写入。而printf()是向屏<br>
幕输出。<br>
&nbsp;&nbsp;&nbsp;  下面介绍一个例子, 运行后产后一个test.dat的文件。<br>
<br>
&nbsp;&nbsp;&nbsp;  例11:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  #include<stdio.h></stdio.h><br>
&nbsp;&nbsp;&nbsp;&nbsp;  main()<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  char *s=(&quot;That's good news&quot;); /*定义字符串指针并初始化*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  int i=617;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*定义整型变量并初始化*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  FILE *fp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*定义文件指针*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fp=fopne(&quot;test.dat&quot;, &quot;w&quot;);&nbsp;&nbsp;&nbsp;  /*建立一个文字文件只写*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fputs(&quot;Your score of TOEFLis&quot;, fp);/*向所建文件写入一串字符*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fputc(':', fp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*向所建文件写冒号:*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fprintf(fp, &quot;%d\n&quot;, i);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*向所建文件写一整型数*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fprintf(fp, &quot;%s&quot;, s);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*向所建文件写一字符串*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fclose(fp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*关闭文件*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
<br>
&nbsp;&nbsp;&nbsp;  用DOS的TYPE命令显示TEST.DAT的内容如下所示:<br>
&nbsp;&nbsp;&nbsp;  屏幕显示<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Your score of TOEFL is: 617<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  That's good news<br>
<br>
&nbsp;&nbsp;&nbsp;  2. 文件的顺序读操作函数<br>
&nbsp;&nbsp;&nbsp;  fscanf()、fgets()和fgetc()函数<br>
<br>
&nbsp;&nbsp;&nbsp;  函数fscanf()、fgets()和fgetc()均为文件的顺序读操作函数, 其调用格式如下:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int fscanf(FILE *stream, char *format,
<address-list></address-list>
);<br>
&nbsp;&nbsp;&nbsp;&nbsp;  char fgets(char *string, int n, FILE *steam);<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int fgetc(FILE *steam);<br>
<br>
&nbsp;&nbsp;&nbsp;  fscanf()函数的用法与scanf()函数相似, 只是它是从文件中读到信息。fscanf()函数的返回值为EOF(即-1), 表明读错误, 否<br>
则读数据成功。fgets()函数从文件中读取至多n-1个字符(n用来指定字符数), 并把它们放入string指向的字符串中, 在读入之后<br>
自动向字符串未尾加一个空字符, 读成功返回string指针, 失败返回一个空指针。fgetc()函数返回文件当前位置的一个字符, 读<br>
错误时返回EOF。<br>
&nbsp;&nbsp;&nbsp;  下面程序读取例11产生的test.dat文件, 并将读出的结果显示在屏幕上。<br>
<br>
&nbsp;&nbsp;&nbsp;  例12<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  #include<stdio.h></stdio.h><br>
&nbsp;&nbsp;&nbsp;&nbsp;  main()<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  char *s, m[20];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  int i;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  FILE  *fp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fp=fopen(&quot;test.dat&quot;, &quot;r&quot;);&nbsp;&nbsp;&nbsp;  /*打开文字文件只读*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fgets(s, 24, fp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*从文件中读取23个字符*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;%s&quot;, s);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*输出所读的字符串*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fscanf(fp, &quot;%d&quot;, &amp;i);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*读取整型数*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;%d&quot;, i);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*输出所读整型数*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  putchar(fgetc(fp));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*读取一个字符同时输出*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fgets(m, 17, fp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*读取16个字符*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  puts(m);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*输出所读字符串*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fclose(fp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*关闭文件*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  getch();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*等待任一键*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
<br>
&nbsp;&nbsp;&nbsp;  运行后屏幕显示:<br>
<br>
&nbsp;&nbsp;&nbsp;  Your score of TOEFL is: 617<br>
&nbsp;&nbsp;&nbsp;  That's good news<br>
<br>
&nbsp;&nbsp;&nbsp;  如果将上例中fscanf(fp, &quot;%d&quot;, &amp;i)改为fscanf(fp, &quot;%s&quot;, m), 再将其后的输出语句改为printf(&quot;%s&quot;, m), 则可得出同样的<br>
结果。由此可见Turbo C2. 0 中只要是读文字文件, 则不论是字符还是数字都将按其ASCII值处理。 另外还要说明的一点就是<br>
fscanf()函数读到空白符时, 便自动结束,在使用时要特别注意。<br>
<br>
&nbsp;&nbsp;&nbsp;  3. 文件的随机读写<br>
&nbsp;&nbsp;&nbsp;  有时用户想直接读取文件中间某处的信息, 若用文件的顺序读写必须从文件头开始直到要求的文件位置再读, 这显然不方便。<br>
Turbo C2.0提供了一组文件的随机读写函数, 即可以将文件位置指针定位在所要求读写的地方直接读写。<br>
&nbsp;&nbsp;&nbsp;  文件的随机读写函数如下:<br>
<br>
&nbsp;&nbsp;&nbsp;  int fseek (FILE *stream, long offset, int fromwhere);<br>
&nbsp;&nbsp;&nbsp;  int fread(void *buf, int size, int count, FILE *stream);<br>
&nbsp;&nbsp;&nbsp;  int fwrite(void *buf, int size, int count, FILE *stream);<br>
&nbsp;&nbsp;&nbsp;  long ftell(FILE *stream);<br>
<br>
&nbsp;&nbsp;&nbsp;  fseek()函数的作用是将文件的位置指针设置到从fromwhere开始的第offset字节的位置上, 其中fromwhere是下列几个宏定义<br>
之一:<br>
&nbsp;&nbsp;&nbsp;  文件位置指针起始计算位置fromwhere<br>
━━━━━━━━━━━━━━━━━━━━━━━━━━━<br>
&nbsp;&nbsp;&nbsp;  符号常数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  数值&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  含义<br>
───────────────────────────<br>
&nbsp;&nbsp;&nbsp;  SEEK_SET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  从文件开头<br>
&nbsp;&nbsp;&nbsp;  SEEK_CUR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  从文件指针的现行位置<br>
&nbsp;&nbsp;&nbsp;  SEEK_END&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  从文件末尾<br>
━━━━━━━━━━━━━━━━━━━━━━━━━━━<br>
&nbsp;&nbsp;&nbsp;  offset是指文件位置指针从指定开始位置(fromwhere指出的位置)跳过的字节数。它是一个长整型量, 以支持大于64K字节的<br>
文件。fseek()函数一般用于对二进制文件进行操作。<br>
&nbsp;&nbsp;&nbsp;  当fseek()函数返回0时表明操作成功, 返回非0表示失败。<br>
&nbsp;&nbsp;&nbsp;  下面程序从二进制文件test_b.dat中读取第8个字节。<br>
<br>
&nbsp;&nbsp;&nbsp;  例13:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  #include<stdio.h></stdio.h><br>
&nbsp;&nbsp;&nbsp;&nbsp;  main()<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  FILE *fp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if((fp=fopen(&quot;test_b.dat&quot;, &quot;rb&quot;))==NULL)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;Can't open file&quot;);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit(1);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fseek(fp, 8. 1, SEEK_SET);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fgetc(fp);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fclose(fp);<br>
&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
<br>
&nbsp;&nbsp;&nbsp;  fread()函数是从文件中读count个字段, 每个字段长度为size个字节, 并把它们存放到buf指针所指的缓冲器中。<br>
&nbsp;&nbsp;&nbsp;  fwrite()函数是把buf指针所指的缓冲器中, 长度为size个字节的count个字段写到stream指向的文件中去。<br>
&nbsp;&nbsp;&nbsp;  随着读和写字节数的增大, 文件位置指示器也增大, 读多少个字节, 文件位置指示器相应也跳过多少个字节。读写完毕函数返<br>
回所读和所写的字段个数。<br>
&nbsp;&nbsp;&nbsp;  ftell()函数返回文件位置指示器的当前值,  这个值是指示器从文件头开始算起的字节数, 返回的数为长整型数, 当返回-1<br>
时, 表明出现错误。<br>
&nbsp;&nbsp;&nbsp;  下面程序把一个浮点数组以二进制方式写入文件test_b.dat中。<br>
<br>
&nbsp;&nbsp;&nbsp;  例14:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  #include <stdio.h></stdio.h><br>
&nbsp;&nbsp;&nbsp;&nbsp;  main()<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  float f[6]={3.2, -4.34, 25.04, 0.1, 50.56, 80.5}; /*定义浮点数组并初始化*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  int i;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  FILE *fp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fp=fopen(&quot;test_b.dat&quot;, &quot;wb&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*创建一个二进制文件只写*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fwrite(f, sizeof(float), 6, fp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*将6个浮点数写入文件中*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fclose(fp);&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*关闭文件*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
<br>
&nbsp;&nbsp;&nbsp;  下面例子从test_b.dat文件中读100个整型数, 并把它们放到dat数组中。<br>
<br>
&nbsp;&nbsp;&nbsp;  例15:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  #include <stdio.h></stdio.h><br>
&nbsp;&nbsp;&nbsp;&nbsp;  main()<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  FILE *fp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  int dat[100];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fp=fopen(&quot;test_b.dat&quot;, &quot;rb&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*打开一个二进制文件只读*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if(fread(dat, sizeof(int), 100, fp)!=100)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*判断是否读了100个数*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if(feof(fp))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;End of file&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*不到100个数文件结束*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf(&quot;Read error&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*读数错误*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fclose(fp);&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  /*关闭文件*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
<br>
&nbsp;&nbsp;&nbsp;  注意:<br>
&nbsp;&nbsp;&nbsp;  当用标准文件函数对文件进行读写操作时, 首先将所读写的内容放进缓冲区, 即写函数只对输出缓冲区进行操作, 读函数只对<br>
输入缓冲区进行操作。例如向一个文件写入内容, 所写的内容将首先放在输出缓冲区中, 直到输出缓冲区存满或使用fclose()函数<br>
关闭文件时, 缓冲区的内容才会写入文件中。 若无fclose() 函数, 则不会向文件中存入所写的内容或写入的文件内容不全。有一<br>
个对缓冲区进行刷新的函数, 即fflush(), 其调用格式为:<br>
<br>
&nbsp;&nbsp;&nbsp;  int fflush(FILE *stream);<br>
<br>
&nbsp;&nbsp;&nbsp;  该函数将输出缓冲区的内容实际写入文件中, 而将输入缓冲区的内容清除掉。<br>
<br>
&nbsp;&nbsp;&nbsp;  4. feof()和rewind()函数<br>
&nbsp;&nbsp;&nbsp;  这两个函数的调用格式为:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int feof(FILE *stream);<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int rewind(FILE *stream);<br>
<br>
&nbsp;&nbsp;&nbsp;  feof()函数检测文件位置指示器是否到达了文件结尾,  若是则返回一个非0值, 否则返回0。这个函数对二进制文件操作特别<br>
有用, 因为二进制文件中, 文件结尾标志EOF也是一个合法的二进制数, 只简单的检查读入字符的值来判断文件是否结束是不行的。<br>
如果那样的话, 可能会造成文件未结尾而被认为结尾, 所以就必须有feof()函数。<br>
&nbsp;&nbsp;&nbsp;  下面的这条语句是常用的判断文件是否结束的方法。<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  while(!feof(fp))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  fgetc(fp);<br>
<br>
&nbsp;&nbsp;&nbsp;  while为循环语句, 将在下面介绍。<br>
&nbsp;&nbsp;&nbsp;  rewind()函数用于把文件位置指示器移到文件的起点处, 成功时返回0, 否则, 返回非0值。<br>
<br>
&nbsp;&nbsp;&nbsp;  1.2.2  非标准文件函数<br>
&nbsp;&nbsp;&nbsp;  这类函数最早用于UNIX操作系统, ANSI标准未定义, 但有时也经常用到, DOS 3.0以上版本支持这些函数。它们的头文件为<br>
io.h。<br>
<br>
&nbsp;&nbsp;&nbsp;  一、文件的打开和关闭<br>
<br>
&nbsp;&nbsp;&nbsp;  1. open()函数<br>
&nbsp;&nbsp;&nbsp;  open()函数的作用是打开文件, 其调用格式为:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int open(char *filename, int access);<br>
<br>
&nbsp;&nbsp;&nbsp;  该函数表示按access的要求打开名为filename的文件, 返回值为文件描述字, 其中access有两部分内容: 基本模式和修饰符,<br>
两者用&quot; &quot;(&quot;或&quot;)方式连接。修饰符可以有多个, 但基本模式只能有一个。access的规定如表3-2。<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  表3-2  access的规定<br>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━<br>
基本模式&nbsp;&nbsp;&nbsp;  含义&nbsp;&nbsp;&nbsp;  修饰符&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  含  义<br>
────────────────────────────<br>
O_RDONLY&nbsp;&nbsp;&nbsp;  只读&nbsp;&nbsp;  O_APPEND&nbsp;&nbsp;  文件指针指向末尾<br>
O_WRONLY&nbsp;&nbsp;&nbsp;  只写&nbsp;&nbsp;  O_CREAT&nbsp;&nbsp;&nbsp;  文件不存在时创建文件,<br>
&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;&nbsp;  属性按基本模式属性<br>
O_RDWR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  读写&nbsp;&nbsp;  O_TRUNC&nbsp;&nbsp;&nbsp;  若文件存在, 将其长度<br>
&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;&nbsp;  缩为0, 属性不变<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  O_BINARY&nbsp;&nbsp;  打开一个二进制文件<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  O_TEXT&nbsp;&nbsp;&nbsp;&nbsp;  打开一个文字文件<br>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━<br>
&nbsp;&nbsp;&nbsp;  open()函数打开成功, 返回值就是文件描述字的值(非负值), 否则返回-1。<br>
<br>
&nbsp;&nbsp;&nbsp;  2. close()函数<br>
&nbsp;&nbsp;&nbsp;  close()函数的作用是关闭由open()函数打开的文件, 其调用格式为:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int close(int handle);<br>
<br>
&nbsp;&nbsp;&nbsp;  该函数关闭文件描述字handle相连的文件。<br>
<br>
&nbsp;&nbsp;&nbsp;  二、读写函数<br>
<br>
&nbsp;&nbsp;&nbsp;  1. read()函数<br>
&nbsp;&nbsp;&nbsp;  read()函数的调用格式为:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int read(int handle, void *buf, int count);<br>
<br>
&nbsp;&nbsp;&nbsp;  read()函数从handle(文件描述字)相连的文件中, 读取count个字节放到buf所指的缓冲区中, 返回值为实际所读字节数, 返回<br>
-1表示出错。返回0 表示文件结束。<br>
<br>
&nbsp;&nbsp;&nbsp;  2. write()函数<br>
&nbsp;&nbsp;&nbsp;  write()函数的调用格式为:<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int write(int handle, void *buf, int count);<br>
&nbsp;&nbsp;&nbsp;  write()函数把count个字节从buf指向的缓冲区写入与handle相连的文件中, 返回值为实际写入的字节数。<br>
<br>
&nbsp;&nbsp;&nbsp;  三、随机定位函数<br>
<br>
&nbsp;&nbsp;&nbsp;  1. lseek()函数<br>
&nbsp;&nbsp;&nbsp;  lseek()函数的调用格式为:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  int lseek(int handle, long offset, int fromwhere);<br>
<br>
&nbsp;&nbsp;&nbsp;  该函数对与handle相连的文件位置指针进行定位, 功能和用法与fseek() 函数相同。<br>
<br>
&nbsp;&nbsp;&nbsp;  2. tell()函数<br>
&nbsp;&nbsp;&nbsp;  tell()函数的调用格式为:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;  long tell(int handle);<br>
<br>
&nbsp;&nbsp;&nbsp;  该函数返回与handle相连的文件现生位置指针, 功能和用法与ftell()相同。</font></h2> <a href="http://hi.baidu.com/dongxiang2007/blog/item/1edbf40112872306738da513.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/dongxiang2007/blog/category/%D1%A7%CF%B0%C0%E0">学习类</a>&nbsp;<a href="http://hi.baidu.com/dongxiang2007/blog/item/1edbf40112872306738da513.html#comment">查看评论</a>]]></description>
        <pubDate>2008年06月29日 星期日  下午 08:01</pubDate>
        <category><![CDATA[学习类]]></category>
        <author><![CDATA[英语一级]]></author>
		<guid>http://hi.baidu.com/dongxiang2007/blog/item/1edbf40112872306738da513.html</guid>
</item>


</channel>
</rss>