Mysql按给定ID顺序排序查询结果

虽然我们很少情况下这样查询,但有时候却会遇到这样的需要:

SELECT * FROM `mytable` WHERE `id` IN(10,3,2)

这样出来的结果一般默认就是ASC显示如下图:


可是,怎么才能按照10,3,2这样的顺序出来呢?

下面就是方法啦!

SELECT * FROM `mytable` WHERE `id` IN(10,3,2) ORDER BY FIND_IN_SET(`id`, '10,3,2')

Javascript的两个IE下错误解决方法分享

今天把做好的项目放IE下测试,发现一大堆问题,全是“SCRIPT1010: 缺少标识符”,“SCRIPT1028: 缺少标识符、字符串或数字”这样的错误,倍感郁闷!,后来谷歌了一下,原来IE问题真不少,下面分享一下解决方案:

这就是IE和Firefox不兼容的地方.属性之间是要用”,”分隔的,但最后一个属性的后面在IE中是不能有的,firefox可有可无. 至于最后的”;”是另外一回事了.这是Javascript的语法问题.如果后面没有其它js语句时”;”可以省略.

例如:我们写json格式时可以这样

{'hello','world','test',}

这在其它浏览器没有问题,但是IE就报这个错误了,最后一个“,”删除就OK了!

简单的PHP邮件发送类

把自己框架里的邮件发送类分享出来,希望对大家有帮助,同时做了一个小例子,方便大家使用。

SMTP类:Smtp.class.php

<?php
/**
 * SMTP类
 * @package         DolrPHP
 * @author          Joy chao <joy@joychao.cc>
 * @version         v2.0
 * @copyright       Copyright (c) 2012. DolrPHP.com
 * @modifier        Joy chao <joy@joychao.cc>
 * @lastmodified    Joy chao    2012-4-30
 */
class Smtp {
	public $smtp_host; 	//SMTP主机,如: smtp.qq.com
	public $smtp_port = 25;	//SMTP端口
	public $auth = TRUE;	//是否需要帐户认证
	public $user;		//帐户名
	public $pass;		//帐户密码
	public $debug = FALSE;	//开启调试
	public $time_out;
	public $host_name;
	public $log_file;
	public $sock;

	/**
	 * 构造函数,连接smtp服务器
	 * @param string 	smtp服务器
	 * @param int 		smtp服务器端口
	 * @param bool 		smtp服务器是否需要认证
	 * @param string 	smtp服务器邮件帐号
	 * @param string 	smtp服务器邮件密码
	 */
	function smtp($smtp_host, $smtp_port = 25, $auth = TRUE, $user = '', $pass = '') {
		$this->debug     = FALSE;
		$this->smtp_port = trim ( $smtp_port );
		$this->smtp_host = trim ( $smtp_host );
		$this->time_out  = 30; // is used in fsockopen()
		$this->auth      = trim ( $auth ); // auth
		$this->user      = trim ( $user );
		$this->pass      = trim ( $pass );
		$this->host_name = "localhost"; // is used in HELO command
		$this->log_file  = '';
		$this->sock      = FALSE;
	}

	/**
	 * 发送邮件主方法
	 * @param  string $to                 收件人
	 * @param  string $mail_from          发件人
	 * @param  string $subject            主题
	 * @param  string $body               内容
	 * @param  string $mailtype           邮件类型(HTML/TXT)
	 * @param  string $cc                 抄送
	 * @param  string $bcc                密送
	 * @param  string $additional_headers 额外头信息
	 * @return boolean                    成功或者失败
	 */
	function sendmail($to, $mail_from, $subject = '', $body = '', $mailtype = "HTML", $cc = '', $bcc = '', $additional_headers = '') {
		$to           = trim ( $to );
		$stringEncode = mb_detect_encoding($body, array('UTF-8','GBK','ASCII','GB2312')); 
		$subject      = iconv($stringEncode,'UTF-8',$subject);
		$body         = iconv($stringEncode,'UTF-8',$body);
		$body         = preg_replace ( "/(^|(\r\n))(\.)/", "\\1.\\3", base64_encode($body));
		$header       = "MIME-Version:1.0\r\n";
		if (strtoupper ( $mailtype ) == "HTML") {
			$header .= "Content-Type:text/html;charset=utf-8\r\n";
		}
		$header .= "Content-Transfer-Encoding: base64\n";
		$header .= "To: " . $to . "\r\n";
		if ($cc != '') {
			$header .= "Cc: " . $cc . "\r\n";
		}
		$header .= "From: " . $this->get_mailfrom ( $this->user, $mail_from ) . "\r\n";
		$header .= "Subject: " . $subject . "\r\n";
		$header .= $additional_headers;
		$header .= "Date: " . date ( "r" ) . "\r\n";
		$header .= "X-Mailer:By Apache (PHP/" . phpversion() . ")\r\n";
		list ( $msec, $sec ) = explode ( ' ', microtime() );
		$header .= "Message-ID: <" . date ( 'YmdHis', $sec ) . "." . ($msec * 1000000) . "." . substr ( $mail_from, strpos ( $mail_from, '@' ) ) . ">\r\n";
		$TO = explode ( ',', $this->strip_comment ( $to ) );
		if ($cc != '') {
			$TO = array_merge ( $TO, explode( ',', $this->strip_comment ( $cc ) ) );
		}
		if ($bcc != '') {
			$TO = array_merge ( $TO, explode ( ',', $this->strip_comment ( $bcc ) ) );
		}
		$sent = TRUE;
		foreach ( $TO as $rcpt_to ) {
			$rcpt_to = $this->get_address ( $rcpt_to );
			if (! $this->smtp_sockopen ( $rcpt_to )) {
				$this->log_write ( "Error: Cannot send email to " . $rcpt_to . "\n" );
				$sent = FALSE;
				continue;
			}
			if ($this->smtp_send ( $this->host_name, $this->user, $rcpt_to, $header, $body )) {
				$this->log_write ( "E-mail has been sent to <" . $rcpt_to . ">\n" );
			} else {
				$this->log_write ( "Error: Cannot send email to <" . $rcpt_to . ">\n" );
				$sent = FALSE;
			}
			fclose ( $this->sock );
			$this->log_write ( "Disconnected from remote host\n" );
		}
		return $sent;
	}

	/**
	 * 发送邮件
	 * @access public
	 */
	function smtp_send($helo, $from, $to, $header, $body = '') {
		if (! $this->smtp_putcmd ( "HELO", $helo )) {
			return $this->smtp_error ( "sending HELO command" );
		}
		// auth
		if ($this->auth) {
			if (! $this->smtp_putcmd ( "AUTH LOGIN", base64_encode ( $this->user ) )) {
				return $this->smtp_error ( "sending HELO command" );
			}
			if (! $this->smtp_putcmd ( '', base64_encode ( $this->pass ) )) {
				return $this->smtp_error ( "sending HELO command" );
			}
		}
		if (! $this->smtp_putcmd ( "MAIL", "FROM:<" . $from . ">" )) {
			return $this->smtp_error ( "sending MAIL FROM command" );
		}
		if (! $this->smtp_putcmd ( "RCPT", "TO:<" . $to . ">" )) {
			return $this->smtp_error ( "sending RCPT TO command" );
		}
		if (! $this->smtp_putcmd ( "DATA" )) {
			return $this->smtp_error ( "sending DATA command" );
		}
		if (! $this->smtp_message ( $header, $body )) {
			return $this->smtp_error ( "sending message" );
		}
		if (! $this->smtp_eom ()) {
			return $this->smtp_error ( "sending <CR><LF>.<CR><LF> [EOM]" );
		}
		if (! $this->smtp_putcmd ( "QUIT" )) {
			return $this->smtp_error ( "sending QUIT command" );
		}
		return TRUE;
	}

	function smtp_sockopen($address) {
		if ($this->smtp_host == '') {
			return $this->smtp_sockopen_mx ( $address );
		} else {
			return $this->smtp_sockopen_relay ();
		}
	}

	function smtp_sockopen_relay() {
		$this->log_write ( "Trying to " . $this->smtp_host . ":" . $this->smtp_port . "\n" );
		$this->sock = @fsockopen ( $this->smtp_host, $this->smtp_port, $errno, $errstr, $this->time_out );
		if (! ($this->sock && $this->smtp_ok ())) {
			$this->log_write ( "Error: Cannot connenct to relay host " . $this->smtp_host . "\n" );
			$this->log_write ( "Error: " . $errstr . " (" . $errno . ")\n" );
			return FALSE;
		}
		$this->log_write ( "Connected to relay host " . $this->smtp_host . "\n" );
		return TRUE;
	}

	function smtp_sockopen_mx($address) {
		$domain = ereg_replace ( "^.+@([^@]+)$", "\1", $address );
		if (! @getmxrr ( $domain, $MXHOSTS )) {
			$this->log_write ( "Error: Cannot resolve MX \"" . $domain . "\"\n" );
			return FALSE;
		}
		foreach ( $MXHOSTS as $host ) {
			$this->log_write ( "Trying to " . $host . ":" . $this->smtp_port . "\n" );
			$this->sock = @fsockopen ( $host, $this->smtp_port, $errno, $errstr, $this->time_out );
			if (! ($this->sock && $this->smtp_ok ())) {
				$this->log_write ( "Warning: Cannot connect to mx host " . $host . "\n" );
				$this->log_write ( "Error: " . $errstr . " (" . $errno . ")\n" );
				continue;
			}
			$this->log_write ( "Connected to mx host " . $host . "\n" );
			return TRUE;
		}
		$this->log_write ( "Error: Cannot connect to any mx hosts (" . implode ( ", ", $MXHOSTS ) . ")\n" );
		return FALSE;
	}

	function smtp_message($header, $body) {
		fputs ( $this->sock, $header . "\r\n" . $body );
		$this->smtp_debug ( "> " . str_replace ( "\r\n", "\n" . "> ", $header . "\n> " . $body . "\n> " ) );
		return TRUE;
	}

	function smtp_eom() {
		fputs ( $this->sock, "\r\n.\r\n" );
		$this->smtp_debug ( ". [EOM]\n" );
		return $this->smtp_ok ();
	}

	function smtp_ok() {
		$response = str_replace ( "\r\n", '', fgets ( $this->sock, 512 ) );
		$this->smtp_debug ( $response . "\n" );
		if (! preg_match("/^[23]/", $response )) {
			fputs ( $this->sock, "QUIT\r\n" );
			fgets ( $this->sock, 512 );
			$this->log_write ( "Error: Remote host returned \"" . $response . "\"\n" );
			return FALSE;
		}
		return TRUE;
	}

	function smtp_putcmd($cmd, $arg = '') {
		if ($arg != '') {
			if ($cmd == '')
				$cmd = $arg;
			else
				$cmd = $cmd . " " . $arg;
		}
		fputs ( $this->sock, $cmd . "\r\n" );
		$this->smtp_debug ( "> " . $cmd . "\n" );
		return $this->smtp_ok ();
	}

	function smtp_error($string) {
		$this->log_write ( "Error: Error occurred while " . $string . ".\n" );
		return FALSE;
	}

	function log_write($message) {
		$this->smtp_debug ( $message );
		if ($this->log_file == '') {
			return TRUE;
		}
		$message = date ( "M d H:i:s " ) . get_current_user () . "[" . getmypid () . "]: " . $message;
		if (! @file_exists ( $this->log_file ) || ! ($fp = @fopen ( $this->log_file, "a" ))) {
			$this->smtp_debug ( "Warning: Cannot open log file \"" . $this->log_file . "\"\n" );
			return FALSE;
		}
		flock ( $fp, LOCK_EX );
		fputs ( $fp, $message );
		fclose ( $fp );
		return TRUE;
	}

	function strip_comment($address) {
		$comment = "/\([^()]*\)/";
		while ( preg_match( $comment, $address ) ) {
			$address = preg_replace ( $comment, '', $address );
		}
		return $address;
	}

	function get_address($address) {
		return trim ( preg_replace ( "/(.*[<])?([^<>]+)[>]?/i", "$2", $address ) );
	}

	function get_mailfrom($address,$mail_from) {
		return $mail_from . "<{$address}>";
	}

	function smtp_debug($message) {
		if ($this->debug) {
			return $message;
		}
	}
}//CLASS SMTP END-----

使用范例: mail.php

<?php
/**
 * SMTP邮件发送演示
 *
 * @author  Joychao <Joy@Joychao.cc>
 **/
//包含SMTP类文件
include './Smtp.class.php';

$smtpserver   = "smtp.exmail.qq.com";	//SMTP服务器 
$smtpport     = 25;						//SMTP服务器端口 
$smtpusermail = "admin@joychao.cc";		//SMTP服务器的用户邮箱 
$smtpuser     = "admin@joychao.cc";		//SMTP服务器的用户帐号 
$smtppass     = "123456";				//SMTP服务器的用户密码 

$mailfrom     =	"Joychao'Blog";			//发送者名称
$mailto       = '44294631@qq.com';		//发送给谁(QQ邮箱情况下不能和上面的登录帐户一样,否则发不出去)
$mailsubject  = "Hello world!这是一封测试邮件的标题";	//邮件主题 
$mailbody     = '您好!<br>这是一封测试邮件<br>来自<a href="http://www.joychao.cc">Joychao\'Blog</a>';//邮件内容,支持HTML
$mailtype     = "HTML";					//邮件格式(HTML/TXT),TXT为文本邮件 
########################################## 
//这里面的一个true是表示使用身份验证,否则不使用身份验证. 
$smtp = new Smtp($smtpserver,$smtpport,true,$smtpuser,$smtppass);//实例化SMTP类
//是否显示调试信息 
$smtp->debug = 1;
//发送邮件
$res=$smtp->sendmail($mailto, $mailfrom, $mailsubject, $mailbody, $mailtype);
if($res){
	echo '发送成功';
}else{
	echo '发送失败';
}

这里补充一点:QQ邮箱不让自己SMTP发给自己,所以测试时请留意这个问题。

代码呢 百度网盘:http://pan.baidu.com/share/link?shareid=78838&uk=453059967

Sublime Text 2的破解方法(64位通用)

Sublime Text 有多好用,我很早很早以前就有过介绍推荐,目前最新版的注册方法如下。

适用于最新版官网下载

http://www.sublimetext.com/2

1. sublime_text.exe 复制一份改名为 sublime_text_cracked.exe
2. 用sublime text2 打开这个文件,搜索

 3342 3032

全部替换为

3242 3032

保存
Sublime Text 2 破解 sublime text2 500x410

Continue reading

UTF-8 and Unicode FAQ

by Markus Kuhn

中国LINUX论坛翻译小组 xLoneStar[译] 2000年2月

这篇文章说明了在 POSIX 系统 (Linux,Unix) 上使用 Unicode/UTF-8 所需要的信息. 在将来不远的几年里, Unicode 已经很接近于取代 ASCII 与 Latin-1 编码的位置了. 它不仅允许你处理处理事实上存在于地球上的任何语言文字, 而且提供了一个全面的数学与技术符号集, 因此可以简化科学信息交换.

UTF-8 编码提供了一种简便而向后兼容的方法, 使得那种完全围绕 ASCII 设计的操作系统, 比如 Unix, 也可以使用 Unicode. UTF-8 就是 Unix, Linux 已经类似的系统使用 Unicode 的方式. 现在是你了解它的时候了.

什么是 UCS 和 ISO 10646?

国际标准 ISO 10646 定义了 通用字符集 (Universal Character Set, UCS). UCS 是所有其他字符集标准的一个超集. 它保证与其他字符集是双向兼容的. 就是说, 如果你将任何文本字符串翻译到 UCS格式, 然后再翻译回原编码, 你不会丢失任何信息.

UCS 包含了用于表达所有已知语言的字符. 不仅包括拉丁语,希腊语, 斯拉夫语,希伯来语,阿拉伯语,亚美尼亚语和乔治亚语的描述, 还包括中文, 日文和韩文这样的象形文字, 以及 平假名, 片假名, 孟加拉语, 旁遮普语果鲁穆奇字符(Gurmukhi), 泰米尔语, 印.埃纳德语(Kannada), Malayalam, 泰国语, 老挝语, 汉语拼音(Bopomofo), Hangul, Devangari, Gujarati, Oriya, Telugu 以及其他数也数不清的语. 对于还没有加入的语言, 由于正在研究怎样在计算机中最好地编码它们, 因而最终它们都将被加入. 这些语言包括 Tibetian, 高棉语, Runic(古代北欧文字), 埃塞俄比亚语, 其他象形文字, 以及各种各样的印-欧语系的语言, 还包括挑选出来的艺术语言比如 Tengwar, Cirth 和 克林贡语(Klingon). UCS 还包括大量的图形的, 印刷用的, 数学用的和科学用的符号, 包括所有由 TeX, Postscript, MS-DOS,MS-Windows, Macintosh, OCR 字体, 以及许多其他字处理和出版系统提供的字符.

ISO 10646 定义了一个 31 位的字符集. 然而, 在这巨大的编码空间中, 迄今为止只分配了前 65534 个码位 (0×0000 到 0xFFFD). 这个 UCS 的 16位子集称为 基本多语言面 (Basic Multilingual Plane, BMP). 将被编码在 16 位 BMP 以外的字符都属于非常特殊的字符(比如象形文字), 且只有专家在历史和科学领域里才会用到它们. 按当前的计划, 将来也许再也不会有字符被分配到从 0×000000 到 0x10FFFF 这个覆盖了超过 100 万个潜在的未来字符的 21 位的编码空间以外去了. ISO 10646-1 标准第一次发表于 1993 年, 定义了字符集与 BMP 中内容的架构. 定义 BMP 以外的字符编码的第二部分 ISO 10646-2 正在准备中, 但也许要过好几年才能完成. 新的字符仍源源不断地加入到 BMP 中, 但已经存在的字符是稳定的且不会再改变了.

UCS 不仅给每个字符分配一个代码, 而且赋予了一个正式的名字. 表示一个 UCS 或 Unicode 值的十六进制数, 通常在前面加上 “U+”, 就象 U+0041 代表字符”拉丁大写字母A”. UCS 字符 U+0000 到 U+007F 与 US-ASCII(ISO 646) 是一致的, U+0000 到 U+00FF 与 ISO 8859-1(Latin-1) 也是一致的. 从 U+E000 到 U+F8FF, 已经 BMP 以外的大范围的编码是为私用保留的.

什么是组合字符?

UCS里有些编码点分配给了 组合字符.它们类似于打字机上的无间隔重音键. 单个的组合字符不是一个完整的字符. 它是一个类似于重音符或其他指示标记, 加在前一个字符后面. 因而, 重音符可以加在任何字符后面. 那些最重要的被加重的字符, 就象普通语言的正字法(orthographies of common languages)里用到的那种, 在 UCS 里都有自己的位置, 以确保同老的字符集的向后兼容性. 既有自己的编码位置, 又可以表示为一个普通字符跟随一个组合字符的被加重字符, 被称为 预作字符(precomposed characters). UCS 里的预作字符是为了同没有预作字符的旧编码, 比如 ISO 8859, 保持向后兼容性而设的. 组合字符机制允许在任何字符后加上重音符或其他指示标记, 这在科学符号中特别有用, 比如数学方程式和国际音标字母, 可能会需要在一个基本字符后组合上一个或多个指示标记.

组合字符跟随着被修饰的字符. 比如, 德语中的元音变音字符 (“拉丁大写字母A 加上分音符”), 既可以表示为 UCS 码 U+00C4 的预作字符, 也可以表示成一个普通 “拉丁大写字母A” 跟着一个”组合分音符”:U+0041 U+0308 这样的组合. 当需要堆叠多个重音符, 或在一个基本字符的上面和下面都要加上组合标记时, 可以使用多个组合字符. 比如在泰国文中, 一个基本字符最多可加上两个组合字符.

什么是 UCS 实现级别?

不是所有的系统都需要支持象组合字符这样的 UCS 里所有的先进机制. 因此 ISO 10646 指定了下列三种实现级别:

级别1
不支持组合字符和 Hangul Jamo 字符 (一种特别的, 更加复杂的韩国文的编码, 使用两个或三个子字符来编码一个韩文音节)
级别2
类似于级别1, 但在某些文字中, 允许一列固定的组合字符 (例如, 希伯来文, 阿拉伯文, Devangari, 孟加拉语, 果鲁穆奇语, Gujarati, Oriya, 泰米尔语, Telugo, 印.埃纳德语, Malayalam, 泰国语和老挝语). 如果没有这最起码的几个组合字符, UCS 就不能完整地表达这些语言.
级别3
支持所有的 UCS 字符, 例如数学家可以在任意一个字符上加上一个 tilde(颚化符号,西班牙语字母上面的~)或一个箭头(或两者都加).

什么是 Unicode?

历史上, 有两个独立的, 创立单一字符集的尝试. 一个是国际标准化组织(ISO)的 ISO 10646 项目, 另一个是由(一开始大多是美国的)多语言软件制造商组成的协会组织的 Unicode 项目. 幸运的是, 1991年前后, 两个项目的参与者都认识到, 世界不需要两个不同的单一字符集. 它们合并双方的工作成果, 并为创立一个单一编码表而协同工作. 两个项目仍都存在并独立地公布各自的标准, 但 Unicode 协会和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 标准的码表兼容, 并紧密地共同调整任何未来的扩展.

那么 Unicode 和 ISO 10646 不同在什么地方?

Unicode 协会公布的 Unicode 标准 严密地包含了 ISO 10646-1 实现级别3的基本多语言面. 在两个标准里所有的字符都在相同的位置并且有相同的名字.

Unicode 标准额外定义了许多与字符有关的语义符号学, 一般而言是对于实现高质量的印刷出版系统的更好的参考. Unicode 详细说明了绘制某些语言(比如阿拉伯语)表达形式的算法, 处理双向文字(比如拉丁与希伯来文混合文字)的算法和 排序与字符串比较 所需的算法, 以及其他许多东西.

另一方面, ISO 10646 标准, 就象广为人知的 ISO 8859 标准一样, 只不过是一个简单的字符集表. 它指定了一些与标准有关的术语, 定义了一些编码的别名, 并包括了规范说明, 指定了怎样使用 UCS 连接其他 ISO 标准的实现, 比如 ISO 6429 和 ISO 2022. 还有一些与 ISO 紧密相关的, 比如 ISO 14651 是关于 UCS 字符串排序的.

考虑到 Unicode 标准有一个易记的名字, 且在任何好的书店里的 Addison-Wesley 里有, 只花费 ISO 版本的一小部分, 且包括更多的辅助信息, 因而它成为使用广泛得多的参考也就不足为奇了. 然而, 一般认为, 用于打印 ISO 10646-1 标准的字体在某些方面的质量要高于用于打印 Unicode 2.0的. 专业字体设计者总是被建议说要两个标准都实现, 但一些提供的样例字形有显著的区别. ISO 10646-1 标准同样使用四种不同的风格变体来显示表意文字如中文, 日文和韩文 (CJK), 而 Unicode 2.0 的表里只有中文的变体. 这导致了普遍的认为 Unicode 对日本用户来说是不可接收的传说, 尽管是错误的.

什么是 UTF-8?

首先 UCS 和 Unicode 只是分配整数给字符的编码表. 现在存在好几种将一串字符表示为一串字节的方法. 最显而易见的两种方法是将 Unicode 文本存储为 2 个 或 4 个字节序列的串. 这两种方法的正式名称分别为 UCS-2 和 UCS-4. 除非另外指定, 否则大多数的字节都是这样的(Bigendian convention). 将一个 ASCII 或 Latin-1 的文件转换成 UCS-2 只需简单地在每个 ASCII 字节前插入 0×00. 如果要转换成 UCS-4, 则必须在每个 ASCII 字节前插入三个 0×00.

在 Unix 下使用 UCS-2 (或 UCS-4) 会导致非常严重的问题. 用这些编码的字符串会包含一些特殊的字符, 比如 ‘\0′ 或 ‘/’, 它们在 文件名和其他 C 库函数参数里都有特别的含义. 另外, 大多数使用 ASCII 文件的 UNIX 下的工具, 如果不进行重大修改是无法读取 16 位的字符的. 基于这些原因, 在文件名, 文本文件, 环境变量等地方, UCS-2 不适合作为 Unicode 的外部编码.

在 ISO 10646-1 Annex R 和 RFC 2279 里定义的 UTF-8 编码没有这些问题. 它是在 Unix 风格的操作系统下使用 Unicode 的明显的方法.

UTF-8 有一下特性:

  • UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0×00 到 0x7F (ASCII 兼容). 这意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的.
  • 所有 >U+007F 的 UCS 字符被编码为一个多个字节的串, 每个字节都有标记位集. 因此, ASCII 字节 (0×00-0x7F) 不可能作为任何其他字符的一部分.
  • 表示非 ASCII 字符的多字节串的第一个字节总是在 0xC0 到 0xFD 的范围里, 并指出这个字符包含多少个字节. 多字节串的其余字节都在 0×80 到 0xBF 范围里. 这使得重新同步非常容易, 并使编码无国界, 且很少受丢失字节的影响.
  • 可以编入所有可能的 231个 UCS 代码
  • UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长.
  • Bigendian UCS-4 字节串的排列顺序是预定的.
  • 字节 0xFE 和 0xFF 在 UTF-8 编码中从未用到.

下列字节串用来表示一个字符. 用到哪个串取决于该字符在 Unicode 中的序号.

U-00000000 – U-0000007F: 0xxxxxxx
U-00000080 – U-000007FF: 110xxxxx 10xxxxxx
U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 – U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 – U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 – U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

 

xxx 的位置由字符编码数的二进制表示的位填入. 越靠右的 x 具有越少的特殊意义. 只用最短的那个足够表达一个字符编码数的多字节串. 注意在多字节串中, 第一个字节的开头”1″的数目就是整个串中字节的数目.

例如: Unicode 字符 U+00A9 = 1010 1001 (版权符号) 在 UTF-8 里的编码为:

11000010 10101001 = 0xC2 0xA9

而字符 U+2260 = 0010 0010 0110 0000 (不等于) 编码为:

11100010 10001001 10100000 = 0xE2 0×89 0xA0

这种编码的官方名字拼写为 UTF-8, 其中 UTF 代表 UCS Transformation Format. 请勿在任何文档中用其他名字 (比如 utf8 或 UTF_8) 来表示 UTF-8, 当然除非你指的是一个变量名而不是这种编码本身.

什么编程语言支持 Unicode?

在大约 1993 年之后开发的大多数现代编程语言都有一个特别的数据类型, 叫做 Unicode/ISO 10646-1 字符. 在 Ada95 中叫 Wide_Character, 在 Java 中叫 char.

ISO C 也详细说明了处理多字节编码和宽字符 (wide characters) 的机制, 1994 年 9 月 Amendment 1 to ISO C 发表时又加入了更多. 这些机制主要是为各类东亚编码而设计的, 它们比处理 UCS 所需的要健壮得多. UTF-8 是 ISO C 标准调用多字节字符串的编码的一个例子, wchar_t 类型可以用来存放 Unicode 字符.

在 Linux 下该如何使用 Unicode?

在 UTF-8 之前, 不同地区的 Linux 用户使用各种各样的 ASCII 扩展. 最普遍的欧洲编码是 ISO 8859-1 和 ISO 8859-2, 希腊编码 ISO 8859-7, 俄国编码 KOI-8, 日本编码 EUC 和 Shift-JIS, 等等. 这使得 文件的交换非常困难, 且应用软件必须特别关心这些编码的不同之处.

最终, Unicode 将取代所有这些编码, 主要通过 UTF-8 的形式. UTF-8 将应用在

  • 文本文件 (源代码, HTML 文件, email 消息, 等等)
  • 文件名
  • 标准输入与标准输出, 管道
  • 环境变量
  • 剪切与粘贴选择缓冲区
  • telnet, modem 和到终端模拟器的串口连接
  • 以及其他地方以前用ASCII来表示的字节串

在 UTF-8 模式下, 终端模拟器, 比如 xterm 或 Linux console driver, 将每次按键转换成相应的 UTF-8 串, 然后发送到前台进程的 stdin 里. 类似的, 任何进程在 stdout 上的输出都将发送到终端模拟器, 在那里用一个 UTF-8 解码器进行处理, 之后再用一种 16 位的字体显示出来.

只有在功能完善的多语言字处理器包里才可能有完全的 Unicode 功能支持. 而广泛用在 Linux 里用于取代 ASCII 和其他 8 位字符集的方案则要简单得多. 第一步, Linux 终端模拟器和命令行工具将只是转变到 UTF-8. 这意味着只用到 级别1 的 ISO 10646-1 实现 (没有组合字符), 且只支持那些不需要更多处理的语言象 拉丁, 希腊, 斯拉夫 和许多科学用符号. 在这个级别上, UCS 支持与 ISO 8859 支持类似, 唯一显著的区别是现在我们有几千种字符可以用了, 其中的字符可以用多字节串来表示.

总有一天 Linux 会当然地支持组合字符, 但即便如此, 对于组合字符串, 预作字符(如何可用的话)仍将是首选的. 更正式地, 在 Linux 下用 Unicode 对文本编码的首选的方法应该是定义在 Unicode Technical Report #15 里的 Normalization Form C.

在今后的一个阶段, 人们可以考虑增加在日文和中文里用到的双字节字符的支持 (他们相对比较简单), 组合字符支持, 甚至也许对从右至左书写的语言如希伯来文 (他们可不是那么简单的) 的支持. 但对这些高级功能的支持不应该阻碍简单的平板 UTF-8 在 拉丁, 希腊, 斯拉夫和科学用符号方面的快速应用, 以取代大量的欧洲 8 位编码, 并提供一个象样的科学用符号集.

我该怎样修改我的软件?

有两种途径可以支持 UTF-8, 我称之为软转换与硬转换. 软转换时, 各处的数据均保存为 UTF-8 形式, 因而需要修改的软件很少. 在硬转换时, 程序将读入的 UTF-8 数据转换成宽字符数组, 以在应用程序内部处理. 在输出时, 再把字符串转换回 UTF-8 形式.

大多数应用程序只用软转换就可以工作得很好了. 这使得将 UTF-8 引入 Unix 成为切实可行的. 例如, 象 cat 和 echo 这样的程序根本不需要修改. 他们仍然可以对输入输出的是 ISO 8859-2 还是 UTF-8 一无所知, 因为它们只是搬运字节流而没有处理它们. 它们只能识别 ASCII 字符和象 ‘\n’ 这样的控制码, 而这在 UTF-8 下也没有任何改变. 因此, 这些应用程序的 UTF-8 编码与解码将完全在终端模拟器里完成.

而那些通过数字节数来获知字符数量的程序则需要一些小修改. 在 UTF-8 模式下, 它们必须不数入 0×80 到 0xBF 范围内的字节, 因为这些只是跟随字节, 它们本身并不是字符. 例如, ls 程序就必须要修改, 因为它通过数文件名中字符数来排放给用户的目录表格布局. 类似地, 所有的假定其输出为定宽字体, 并因此而格式化它们的程序, 必须学会怎样数 UTF-8 文本中的字符数. 编辑器的功能, 如删除单个字符, 必须要作轻微的修改, 以删除可能属于该字符的所有字节. 受影响有编辑器 (vi,emacs, 等等)以及使用 ncurses 库的程序.

Linux 核心使用软转换也可以工作得很好, 只需要非常微小的修改以支持 UTF-8. 大多数处理字符串的核心功能 (例如: 文件名, 环境变量, 等等) 都不受影响. 下列地方也许必须修改:

  • 控制台显示与键盘驱动程序 (另一个 VT100 模拟器) 必须能编码和解码 UTF-8, 必须要起码支持 Unicode 字符集的几个子集. 从 Linux 1.2 起这些功能已经有了.
  • 外部文件系统驱动程序, 例如 VFAT 和 WinNT 必须转换文件名字符编码. UTF-8 已经加入可用的转换选项的列表里了, 因此 mount 命令必须告诉核心驱动程序用户进程希望看到 UTF-8 文件名. 既然 VFAT 和 WinNT 无论如何至少已经用了 Unicode了, 那么 UTF-8 在这里就可以发挥其优势, 以保证转换中无信息损失.
  • POSIX 系统的 tty 驱动程序支持一种 “cooked” 模式, 有一些原始的行编辑功能. 为了让字符删除功能工作正常, stty 必须在 tty 驱动程序里设置 UTF-8 模式, 因此它就不会把 0×80 到 0xBF 范围内的跟随字符也数进去了. Bruno Haible 那里已经有了一些 stty 和核心 tty 驱动 程序的 Linux 补丁 了.

C 对 Unicode 和 UTF-8 的支持

从 GNU glibc 2.1 开始, wchar_t 类型已经正式定为只存放独立于当前 locale 的, 32位的 ISO 10646 值. glibc 2.2 开始将完全支持 ISO C 中的多字节转换函数 (wprintf(),mbstowcs(),等等), 这些函数可以用于在 wchar_t 和包括 UTF-8 在内的任何依赖于 locale 的多字节编码间进行转换.

例如, 你可以写

  wprintf(L"Sch鰊e Gre!\n");

然后, 你的软件将按照你的用户在环境变量 LC_CTYPE (例如, en_US.UTF-8 或 de_DE.ISO_8859-1) 中选择的 locale 所指定的编码来打印这段文字. 你的编译器必须运行在与该 C 源文件所用编码相应的 locale 中, 在目标文件中以上的宽字符串将改为 wchar_t 字符串存储. 在输出时, 运行时库将把 wchar_t 字符串转换回与程序执行时的 locale 相应的编码.

注意, 类似这样的操作:

  char c = L"a";

只允许从 U+0000 到 U+007F (7 位 ASCII) 范围里的字符. 对于非 ASCII 字符, 不能直接从 wchar_t 到 char 转换.

现在, 象 readline() 这样的函数在 UTF-8 locale 下也能工作了.

怎样激活 UTF-8 模式?

如果你的应用程序既支持 8 位字符集 (ISO 8859-*,KOI-8,等等), 也支持 UTF-8, 那么它必须通过某种方法以得知是否应使用 UTF-8 模式. 幸运的是, 在未来的几年里, 人们将只使用 UTF-8, 因此你可以将它作为默认, 但即使如此, 你还是得既支持传统 8 位字符集, 也支持 UTF-8.

当前的应用程序使用许许多多的不同的命令行开关来激活它们各自的 UTF-8 模式, 例如:

  • xterm 命令行选项 “-u8″ 和 X resource “XTerm*utf8:1″
  • gnat/gcc 命令行选项 “-gnatW8″
  • stty 命令行选项 “iutf8″
  • mined 命令行选项 “-U”
  • xemacs elisp 包裹 以在 UTF-8 和内部使用的 MULE 编码间转换
  • vim ‘fileencoding’ 选项
  • less 环境变量 LESSCHARSET=utf-8

记住每一个应用程序的命令行选项或其他配置方法是非常单调乏味的, 因此急需某种标准方法.

如果你在你的应用程序里使用硬转换, 并使用某种特定的 C 库函数来处理外部字符编码和内部使用的 wchar_t 编码的转换工作, 那么 C 库会帮你处理模式切换的问题. 你只需将环境变量 LC_CTYPE 设为正确的 locale, 例如, 如果你使用 UTF-8, 那就是en.UTF-8, 而如果是 Latin-1, 并需要英语的转换, 则设为 en.ISO_8859-1.

然而, 大多数现存软件的维护者选择用软转换来代替, 而不使用 libc 的宽字符函数, 不仅因为它们还未得到广泛应用, 还因为这会使得软件进行大规模修改. 在这种情况下, 你的应用程序必须自己来获知何时使用 UTF-8 模式. 一种方式是做以下工作:

按照环境变量 LC_ALL, LC_CTYPE, LANG 的顺序, 寻找第一个有值的变量. 如果该值包含 UTF-8 子串 (也许是小写或没有”-”) 则默认为 UTF-8 模式 (仍然可以用命令行开关来重设), 因为这个值可靠又恰当地指示了 C 库应该使用一种 UTF-8 locale.

提供一个命令行选项 (或者如果是 X 客户程序则用 X resource 的值) 将仍然是有用的, 可以用来重设由 LC_CTYPE 等环境变量指定的默认值.

我怎样才能得到 UTF-8 版本的 xterm?

在 XFree86 里带的 xterm 版本最近已经由 Thomas E. Dickey 加入了支持 UTF-8 的扩展. 使用方法是, 获取 xterm patch #119 (1999-10-16) 或更新版本, 用 “./configure –enable-wide-chars ; make” 来编译, 然后用命令行选项 -u8 来调用 xterm, 使它将输入输出转换为 UTF-8. 在 UTF-8 模式里使用一个 *-ISO10646-1 字体. 当你在 ISO 8859-1 模式里时也可以使用 *-ISO10646-1 字体, 因为 ISO 10646-1 字体与 ISO 8859-1 字体是完全向后兼容的.

新的支持 UTF-8 的 xterm 版本, 以及一些 ISO 10646-1 字体, 将被收录入 XFree86 4.0 版里.

xterm 支持组合字符吗?

Xterm 当前只支持级别1的 ISO 10646-1, 就是说, 不提供组合字符的支持. 当前, 组合字符将被当作空格字符对待. xterm 将来的修订版很有可能加入某些简单的组合字符支持, 就是仅仅将那个有一个或多个组合字符的基字符加粗 (logical OR-ing). 对于在基线以下的和在小字符上方的重音符来说, 这样处理的结果还是可以接受的. 对于象泰国文字体那样使用特别设计的加粗字符的文字, 这样处理也能工作的很好. 然而, 对于某些字体里, 在较高的字符上方组合上的重音符, 特别是对于 “fixed” 字体族, 产生的结果就不完全令人满意了. 因此, 在可用的地方, 应该继续优先使用预作字符.

xterm 支持半宽与全宽 CJK 字体吗?

Xterm 当前只支持那种所有字形都等宽的 cell-spaced 的字体. 将来的修订版很有可能为 CJK 语言加入半宽与全宽字符支持, 类似于 kterm 提供的那种. 如果选择的普通字体是 X×Y 象素大小, 且宽字符模式是打开的, 那么 xterm 会试图装入另外的一个 2X×Y 象素大小的字体 (同样的 XLFD, 只是 AVERAGE_WIDTH 属性的值翻倍). 它会用这个字体来显示所有在 Unicode Technical Report #11里被分配了East Asian Wide (W) 或 East Asian FullWidth (F) 宽度属性的 Unicode 字符. 下面这个 C 函数用来测试一个 Unicode 字符是否是宽字符并需要用覆盖两个字符单元的字形来显示:

  /* This function tests, whether the ISO 10646/Unicode character code
   * ucs belongs into the East Asian Wide (W) or East Asian FullWidth
   * (F) category as defined in Unicode Technical Report #11. In this
   * case, the terminal emulator should represent the character using a
   * a glyph from a double-wide font that covers two normal (Latin)
   * character cells. */

  int iswide(int ucs)
  {
    if (ucs < 0x1100)
      return 0;

    return
      (ucs >= 0x1100 && ucs <= 0x115f) || /* Hangul Jamo */
      (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
       ucs != 0x303f) ||                     /* CJK ... Yi */
      (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
      (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
      (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
      (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
      (ucs >= 0xffe0 && ucs <= 0xffe6);
  }

某些 C 库也提供了函数

  #include <wchar.h>
  int wcwidth(wchar_t wc);
  int wcswidth(const wchar_t *pwcs, size_t n);

用来测定该宽字符 wc 或由 pwcs 指向的字符串中的 n 个宽字符码 (或者少于 n 个宽字符码, 如果在 n 个宽字符码之前遇到一个空宽字符的话) 所要求的列位置的数量. 这些函数定义在 Open Group 的 Single UNIX Specification 里. 一个拉丁/希腊/斯拉夫/等等的字符要求一个列位置, 一个 CJK 象形文字要求两个, 而一个组合字符要求零个.

最终 xterm 是否会支持从右到左的书写?

此刻还没有给 xterm 增加从右到左功能的计划. 希伯来与阿拉伯用户因此不得不靠应用程序在将希伯来文与阿拉伯文字符串送到终端前按左方向翻转它们, 换句话说, 双向处理必须在应用程序里完成, 而不是在 xterm 里. 至少, 希伯来与阿拉伯文在预作字形的可用性的形式上, 以及提示表格上的支持, 比 ISO 8859 要有所改进. 现在还远没有决定 xterm 是否支持双向文字以及该怎样工作.ISO 6429 = ECMA-48 和 Unicode bidi algorithm 都提供了可供选择的开始点. 也可以参考 ECMA Technical
Report TR/53
. Xterm 也不处理阿拉伯文, Hangul 或 印度文本的格式化算法, 而且现在还不太清楚在 VT100 模拟器里处理是否可行和值得, 或者应该留给应用软件去处理. 如果你打算在你的应用程序里支持双向文字输出, 看一下 FriBidi, Dov Grobgeld 的 Unicode 双向算法的自由实现.

我在哪儿能找到 ISO 10646-1 X11 字体?

在过去的几个月里出现了相当多的 X11 的 Unicode 字体, 并且还在快速增多.

  • Markus Kuhn 正和其他许多志愿者一起工作于手动将旧的 -misc-fixed-*-iso8859-1 字体扩展到覆盖所有的欧洲字符表 (拉丁, 希腊, 斯拉夫, 国际音标字母表. 数学与技术符号, 某些字体里甚至有亚美尼亚语, 乔治亚语, 片假名等). 更多信息请参考 Unicode fonts and tools for X11 页. 这些字体将与 XFree86 一起分发. 例如字体
      -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1

    (旧的 xterm 的 fixed 缺省字体的一个扩展, 包括超过 3000 个字符) 已经是 XFree86 3.9 snapshot 的一部分了.

  • Markus 也做好了 X11R6.4 distribution 里所有的 Adobe 和 B&H BDF 字体的 ISO 10646 版本. 这些字体已经包含了全部 Postscript 字体表 (大约 30 个额外的字符, 大部分也被 CP1252 MS-Windows 使用, 如 smart quotes, dashes 等), 在 ISO 8859-1 编码下是没有的. 它们在 ISO 10646-1 版本里是完全可用的.
  • XFree86 4.0 将携带一个集成的 TrueType 字体引擎, 这使得你的 X 应用程序可以将任何 Apple/Microsoft 字体用于 ISO 10646-1 编码.
  • 将来的 XFree86 版本很有可能从分发版中去除大多数旧的 BDF 字体, 取而代之的是 ISO 10646-1 编码的版本. X 服务器则会增加一个自动编码转换器, 只有当旧的 8 位软件请求一个类似于 ISO 8859-* 编码的字体时, 才虚拟地从 ISO 10646-1 字体文件中创建一个这样的字体. 现代软件应该优先地直接使用 ISO 10646-1 字体编码.
  • ClearlyU (cu12) 是一个非常有用的 X11 的 12 点阵, 100 dpi 的 proportional ISO 10646-1 BDF 字体, 包含超过 3700 个字符, 由 Mark Leisher 提供 (样例图象).
  • Roman Czyborra 的 GNU Unicode font 项目工作于收集一个完整的与免费的 8×16/16×16 pixel Unicode 字体. 目前已经覆盖了 34000 个字符.
  • etl-unicode 是一个 ISO 10646-1 BDF 字体, 由 Primoz Peterlin 提供.

Unicode X11 字体名字以 -ISO10646-1 结尾. 这个 X 逻辑字体描述器 (X Logical Font Descriptor, XLFD) 的 CHARSET_REGISTRY 和 CHARSET_ENCODING 域里的值已经为所有 Unicode 和 ISO 10646-1 的 16 位字体而正式地注册了. 每个 *-ISO10646-1 字体都包含了整个 Unicode 字符集里的某几个子集, 而用户必须弄清楚他们选择的字体覆盖哪几个他们需要的字符子集.

*-ISO10646-1 字体通常也指定一个 DEFAULT_CHAR 值, 指向一个非 Unicode 字形, 用来表示所有在该字体里不可用的字符 (通常是一个虚线框, 一个 H 的大小, 位于 0x1F 或 0xFFFE). 这使得用户至少能知道这儿有一个不支持的字符. xterm 用的小的定宽字体比如 6×13 等, 将永远无法覆盖所有的 Unicode, 因为许多文字比如日本汉字只能用比欧洲用户广泛使用的大的象素尺寸才能表示. 欧洲使用的典型的 Unicode 字体将只包含大约 1000 到 3000 个字符的子集.

我怎样才能找出一个 X 字体里有哪些字形?

X 协议无法让一个应用程序方便地找出一个 cell-spaced 字体提供哪些字形, 它没有为字体提供这样的量度. 因此 Mark Leisher 和 Erik van de Poel (Netscape) 指定了一个新的_XFREE86_GLYPH_RANGES BDF 属性, 告诉应用程序该 BDF 字体实现了哪个 Unicode 子集. Mark Leisher 提供了一些样例代码以产生并扫描这个属性, 而 Xmbdfed 3.9 以及更高版本将自动将其加入到由它产生的每个 BDF 文件里.

与 UTF-8 终端模拟器相关的问题是什么?

VT100 终端模拟器接受 ISO 2022 (=ECMA-35) ESC 序列, 用于在不同的字符集间切换.

UTF-8 在 ISO 2022 的意义里是一个 “其他编码系统” (参考 ECMA 35 的 15.4 节). UTF-8 是在 ISO 2022 SS2/SS3/G0/G1/G2/G3 世界之外的, 因此如果你从 ISO 2022 切换到 UTF-8, 所有的 SS2/SS3/G0/G1/G2/G3 状态都变得没有意义了, 直到你离开 UTF-8 并切换回 ISO 2022. UTF-8 是一个没有国家的编码, 也就是一个自我终结的短字节序列完全决定了它代表什么字符, 独立于任何国家的切换. G0 与 G1 在 ISO 10646 里与在 ISO 8859-1 里相同, 而 G2/G3 在 ISO 10646 里不存在, 因为任何字符都有固定的位置, 因而不会发声切换. 在 UTF-8 模式下, 你的终端不会因为你偶然地装入一个二进制文件而切换入一种奇怪图形字符模式. 这使得一个终端在 UTF-8 模式下比在 ISO 2022 模式下要健壮得多, 而且因此可以有办法将终端锁在 UTF-8 模式里, 而不会偶然地回到 ISO 2022 世界里.

ISO 2022 标准指定了一系列的 ESC % 序列, 以离开 ISO 2022 世界 (指定其他的编码系统, DOCS), 用于 UTF-8 的许多这样的序列已经注册进了 ISO 2375 International Register of Coded Character Sets:

  • ESC %G 从 ISO 2022 里激活一个未指定实现级别的 UTF-8 模式且允许再返回 ISO 2022.
  • ESC %@ 从 UTF-8 回到 ISO 2022, 条件是通过 ESC %G 进入的 UTF-8
  • ESC %/G 切换进 UTF-8 级别 1 且不返回.
  • ESC %/H 切换进 UTF-8 级别 2 且不返回.
  • ESC %/I 切换进 UTF-8 级别 3 且不返回.

当一个终端模拟器在 UTF-8 模式时, 任何 ISO 2022 逃脱码序列例如用于切换 G2/G3 等的都被忽略. 一个在 UTF-8 模式下的终端模拟器唯一会执行的 ISO 2022 序列是 ESC %@ 以从 UTF-8 返回 ISO 2022 方案.

UTF-8 仍然允许你使用象 CSI 这样的 C1 控制字符, 尽管 UTF-8 也使用 0×80-0x9F 范围里的字节. 重要的是必须理解在 UTF-8 模式下的终端模拟器必须在执行任何控制字符前对收到的字节流运用 UTF-8 解码器. C1 字符与其他任何大于 U+007F 的字符一样需先经过 UTF-8 解码.

已经有哪些支持 UTF-8 的应用程序了?

  • Yudit 是 Gaspar Sinai 的自由 X11 Unicode 编辑器
  • Mined 98 由 Thomas Wolff 提供, 是一个可以处理 UTF-8 的文本编辑器.
  • less 版本 346 或更高, 支持 UTF-8
  • C-Kermit 7.0 在传输, 终端, 及文件字符集方面支持 UTF-8.
  • Sam 是 Plan9 的 UTF-8 编辑器, 类似于 vi, 也可用于 Linux 和 Win32. (Plan9 是第一个完全转向 UTF-8, 将其作为字符编码的操作系统.)
  • 9term 由 Matty Farrow 提供, 是一个 Plan9 操作系统的 Unicode/UTF-8 终端模拟器的 Unix 移植.
  • Wily 是一个 Plan9 Acme 编辑器的 Unix 实现.
  • ucm-0.1 是 Juliusz Chroboczek 的 Unicode 字符映射表, 一个小工具, 使你可以选中任何一个 Unicode 字符并粘贴进你的应用程序.

有哪些用于改善 UTF-8 支持的补丁?

Postscript 字形的名字与 UCS 代码是怎么关联的?

参考 Adobe 的 Unicode and Glyph Names 指南.

X11 的剪切与粘贴工作在 UTF-8 时是如何完成的?

参考 Juliusz Chroboczek 的 客户机间 Unicode 文本的交换 草案, 对 ICCCM 的一个扩充的建议, 用一个新的可用于属性类型(property type)和选中(selection)目标的原子 UTF8_STRING 来处理 UTF-8 的选中.

现在有没有用于处理 Unicode 的免费的库?

各种 X widget 对 Unicode 支持的现状如何?

有什么关于这个话题的好的邮件列表?

你确实应该订阅的是 unicode@unicode.org 邮件列表, 这是发现标准的作者和其他许多领袖的话语的最好办法. 订阅方法是, 用 “subscribe” 作为标题, “subscribe YOUR@EMAIL.ADDRESS unicode” 作为正文, 发一条消息到 unicode-request@unicode.org.

也有一个专注与改进通常用于 GNU/Linux 系统上应用程序的 UTF-8 支持的邮件列表 linux-utf8@nl.linux.org. 订阅方法是, 以 “subscribe linux-utf8″ 为内容, 发送消息到majordomo@nl.linux.org. 你也可以浏览 linux-utf8 archive

其他相关的还有 XFree86 组的 “字体” 与 “i18n” 列表, 但你必须成为一名正式的开发者才能订阅.

更多参考

我不断地将新的材料加入这份文档, 因此请定期来查看. 欢迎所有关于改进的建议, 以及自由软件社区里关于改善 UTF-8 支持的广告. UTF-8 用在 Linux 里是新近的事, 因此我们在将来的几个月里可以见到大量的进展.

特别感谢 Ulrich Drepper 和 Bruno Haible 的有价值的注解

Markus Kuhn <<Markus.Kuhn@cl.cam.ac.uk>
创建于 1999-06-04 — 最近更新于 2000-01-15 — http://www.cl.cam.ac.uk/~mgk25/unicode.html

ThinkPHP3.0一个小的问题

在不设置UPLOAD_FILE_RULE的情况下实例化上传对象:

$upload = new UploadFile();

默认读取UPLOAD_FILE_RULE配置,而这个设置没有提醒设置,会对saveRule置空null,后面再用对象设置属性($upload->saveRule=’xxx’)则无效,因为__set方法用的是isset,所以isset对saveRule=null会返回不存在这个键,建议更新为array_key_exists即可:

public function __set($name,$value){
    if(array_key_exists($name,$this->config)) {
      $this->config[$name] = $value;
    }
}

这个问题已经新版纠正了。

在北大校园BBS引起轰动的一篇文章

我生长在东北的哈尔滨,虽然从小唱着”大刀向鬼子的头砍去……”,听着历史老师很愤恨的叫日本人”倭寇”、”鬼子”,看着诸如731部队之类的报道和展览;但这并不影响我儿时对日本的看法,记得小的时候,同学录上”最向往的地方”一栏,我填的都是”日本”。

那个时候觉得日本的动画片很好看,日本的小电器好用,甚至连日本的忍者和剑道高手,都是我心中的偶像。小时候拿着木棍模仿日本人劈剑的经历,我现在都记忆犹新。渐渐的,人也长大了, 有机会听到见到更多关于日本的东西,这中间当然有那段不短的历史,有日本国内对中国的看法,有日本经济的强大,和时常能听到的”友好邻邦”、”一衣带水”之类的宣传。
可以说,在相当长的一段时间里,我并没有对日本有任何心理上的戒备和敌意;甚至,可以说是有点谄媚的向往。我当然也听到过”南京大屠杀”、”731细菌部队”、”旅顺大屠杀”和数不清的日本人在侵略时的历史;但是,我始终认为,那些已过去了,记着就可以了,干吗要抱着不放哪?两国友好不是很好吗?这些和他们这一代日本人没关系啊……等等如是的想法。

2000年,我从东北的哈尔滨来到了上海,异乡的生活,给了我更多的机会接触不同的人和事,也让我有机会能够更深的思考一些问题。
刚来上海的时候,有人听到我是来自哈尔滨的,时常会问到:”你们恨日本吗?”。那时,我都会以东北人的身份告诉他:”东北人都恨日本,他们侵略过我们”;但是让我说具体我恨他什么?我根本说不出来,因为在那时的我的印象里,我是没有任何情感的累积的,只是出于道义和理所应当的层面上才会说这些。

直到那一天。

那时2000年冬天的一个晚上。我和几个好朋友在复旦旁边的一个漫画pub(乐静宜开的漫画吧)过通宵。那个pub在上海算是小有名气的,里面都是日本的漫画和其他的书籍,氛围弄得很好。
这时,旁边走过来一个服务生,头上系着头巾,很恭敬的在旁边问道:”先生,可以聊聊吗?”。我们高兴的欢迎了他,当然,第一句话是礼节性的问了一句”您是哪里人啊?”,他的回答很巧妙:”我是哪里人不重要,我在哪里就是哪里人,你们觉得我是哪里人呐?”,然后他用上海话问:”哪晓得伐?”。听到朋友说他是广东人,就用广东话说:”你知吾知嘎?”,然后用北京话一样的北方音调的普通话对我说:”您说哪?”。由于他的相貌和举止,我们一致猜他是日本人,他不置可否,对我们笑笑说:”这个不重要,我问你们一个问题好吗?”。他向我们借了笔和纸,然后,很认真地看着我,说:”你是东北人,我问你一个地方你知道吗?”然后在纸上很流利地写下了两个很漂亮的汉字:”奉天”;写好之后,他抬头看看我说:”这里本来可以做都城的,可惜……”,我马上觉得来者不善,可能因为面对的是外国人所以激发了我的感情,我很正经的和他说:”先生,您写错了,现在已经没有叫做奉天的城市了,’奉天’现在叫’沈阳’,叫做’奉天’的那个年代,一去不复返了。”

他笑笑说:”那可不一定”。

然后他在纸上画了一张世界地图说:”这个就是世界,你们对世界有什么看法吗?没有,因为你们是不思进取的民族。我们不是,我们的目标不只是奉天,东北,甚至中国。我们的目标就是——”,他用笔在地图上画了一个大圈,然后很有力量的说:”全世界!!!”

我笑了笑说:”世界属于谁不是你们定义的,什么事情都有他的规律。你凭什么说中国人不进取?你凭什么瞧不起一个这么有文化底蕴的民族?”

“你们总在谈文化,我很敬重中国的文化,我觉得我一辈子也不能完全理解其中的一点点内容,这也是我一直学习中国文化的原因,但是你们哪?你们中国人,自己的文化知道多少?甚至我可以说,中国人,懂中国的文化,绝对没有我们日本人懂得多。儒学的思想是什么?为什么孔孟会被尊奉到那么高的地位?你们谁能说出来?”

“中庸、仁,这些就是儒学的精髓”。我将我当时仅有的有关中国文化的知识搬出来。我那时的心情相当复杂。是啊,他问更多哪?我还能知道了吗?我们这一代认真的又很少人对中国的文化感兴趣甚至研究过,一个连自己文化都不懂的人,怎么配和别人理论文化的问题啊?

我们马上问了他很多关于中国的问题,看他是否真地对中国的文化有所了解,让我们吃惊的是:第一次大一统、唐代盛世、元清的少数民族统治、甚至”春天的故事”,这所有的东西,他都能很清晰甚至很透彻地告诉我们其经过和影响。他自豪地说:”一个不研究自己文化的民族,就是落后和愚昧的!是被别人瞧不起的!”

我马上回击:”你们日本人就被别人瞧得起吗?别忘了黄种人在美国是什么地位?”

“你去过美国吗?你了解美国吗?如果没有,请不要妄加判断。我在美国生活过两年,我想,在美国,亚洲人如何,我应该比你有发言权。”

我哑口。

“有一次我去买首饰,选了好久,服务生态度都很生硬;而当我告诉她我是日本人的时候,他马上很恭敬的帮我选,还抱歉地说:’对不起,我还以为您是香港人呐’,这就是尊重,是你们永远享受不到的尊重。”

“你当人家真的尊重你啊?还不是因为日本人的钱。”

“就算是为了钱,怎么样?事实就是人们尊重日本人,不只是因为钱,更是因为日本强大,因为日本人的素质比中国人高。”

“你凭什么说中国人素质低?你去过几个地方?”

“我去过十几个省,绝对比你去过的地方多,让我说为什么,我不举别的地方,我现在所在的城市是上海,这算是你们中国最好的城市了,可是怎么样呢?人们像盲人一样根本不看红灯的过马路,乘坐交通工具的时候向发狂一样的挤来挤去、随地吐痰、晚辈在街上辱骂长辈,这些都是真的吧?”

我又哑口,朋友接到说:”有些人是这样,但是不代表所有人是这样啊。我们深圳人就不会乱抢位子,乱穿马路。”

“噢?是这样的吗?对不起,我没有去过深圳,如果有机会,我一定会去看看。”他的表情变得恭敬起来。这更接近我过去对日本人的看法。但是,这没有维持多久。

“素质,什么叫素质?你们的孩子都被大人包在家里,生怕孩子吃苦。我小的时候,爸爸每天都让我四点起床去跑步,当时我很不理解,还有些恨他,可是现在,我感激我的爸爸,是因为这样的锻炼,使我形成了坚毅的意志,让我形成了日本人的精神。这么差的基础,怎么可能会有一个强大的民族? ”

“我在美国做过hotel的manager,当时有两个人被辞掉了,一个是日本人,一个是中国人。他们都归我管,两个人都来求我,说自己能胜任现在的工作,让我帮忙。我并没有因为其中有日本人而偏袒他,我让他们做同样的工作,谁做好了把谁留下。很不幸的,两个人真的都不是很熟练,我当时教了他们怎么做,让他们继续做好,那个日本人很认真地听我每一句话,最后做得很好,而那中国人又懒又不努力,我都不知道他搞了些什么。最后我忍无可忍。我没有把他当人的对他喊:’你给我滚!’”

“无可否认有素质差的人,但是这并不能代表全部,难道你的意思是每个中国人都这样?我们有很多人很努力的工作,很敬业,难道你就没看到这些?”
“工作?你们中国人最擅长的就是互相排挤,懂什么叫团队吗?你们连两个地方的人都会互相看不起,不要说一个团队里来自各个地方了。中国人是最恶心的民族,到处都是一个地方的人看不起另一个地方的。”

其实他说的这些有很多是我一直想说的,但是作为中国人,我只能抱着复杂的心情继续和他理论。

“你有什么资格说这些?你对中国的地域了解多少?”

“南方中国人和北方中国人我都研究过,我还做过类似的报告给日本政府。”他看着我说:”日本人比较看得起你们,你们像日本人,是真正的男人,在遇到侵略的时候会团结起来抗争。这也让我们吃了很多苦头;而南中国人比较聪明,他们不会愿意卷入牺牲和努力;所以他们愿意发展经济。但是一旦有战争发生,他们将是最容易制服的亡国奴。”

“不许你诬蔑我的同胞!”我义正言辞的告诉他。

“你不要觉得中国人多团结多伟大,韩国人在国家出现困难的时候可以全国人民捐金子给政府,在你们中国,可能吗???”

我完全怔住了。

是啊,他说的千真万确啊!可能吗?大家也可以自己想象,如果是你,你会吗?

“这个可以不谈,每个人有自己的想法。”他回到那张纸上,指着地图说:”我还是给你们介绍我们的大一统吧。这是世界,十五年后,他就是我们日本人的。”
他在纸上用繁体字写下:”大一统”。

“我们不用繁体字,对不起先生,请不要再写了,我们看不懂。”我们很生气他的做法。

“没关系,其实这也是你们文化的一部分。你们连祖先写的字都放弃了。”他轻蔑地笑着说。

“我们国家是有规划的,全世界都在看我们的动画片,我们的电视剧,用我们的电器,很多人疯狂的崇拜日本,在中国,也不再少数吧?你们接触的都是外面的文化,而中国人又对自己的文化不感兴趣,当有一天你们一觉醒来,发现身边的一切都是别人的时候。你们连后悔都来不及啦!顺理成章的,总有一天,你们的国土也会变成我们的,因为你们中很多人已经认同我们的东西,我们的思想了。”

多么的悲哀啊?他说的事情的的确确是真的。我们身边多少人对日本的美国的东西着迷,甚至有哈日,哈韩这样的词语出来。在欧洲,巨无霸被人们认为是美国文化的侵略而被抵制,而中国最近的调查有47%的中国孩子觉得麦当老是中国的品牌,这会有什么样的后果啊?我虽然嘴上在回击,但我的心里很不是滋味,那是一种什么感觉?此时此刻的你能体会到吗?

“劣等的民族是不应该生存的这么自在的,我们是来解救你们的。在日本,我这样的人有很多,全世界都有,我们是有组织的。我爸爸是老兵,我们都信奉天皇。我不只要到美国中国,还要去欧洲,到全世界宣传我们日本的文化和想法。”

“算了吧,自大狂,你一直在说中国的文化,中国的文化里面有一样你一直没学到。”

“噢?是什么?愿意请教。”

“那是尊重,这是你们日本人永远学不到的,你们以为鞠鞠躬就是尊重了?完全不是。一个不尊重别人的人是不会得到别人的尊重的。”

“我没有必要尊重你们,因为你们劣等。”

我当时心里面就像是有很大的火气但是发不出来,我既要保持中国人的气度,又要承受听着一个鬼子侮辱我们整个民族,动粗只是野蛮的表现,但是对他,我们还能怎么样呐?

“你快走开吧!省着我受不了打你!”

“小伙子不要乱说话,你打我犯法的,但是我打死你都没有事情,我们的一个朋友就这样做过,最后还是平平安安的被送回日本。你已经很生气了,可能听不下去了,打扰了。”

他说完这些就走了。桌子上留下了”奉天,大一统”几个字,和一张虽然草草但是画得很熟练的世界地图。

……就在他走之后,几个朋友都陷入了沉思。他说得真的好多都是真的。为什么会变成这样哪?

那天晚上到天亮之前的时间里,我们想了很多很多。

第二天,我在课上请求老师给我20分钟,我把前一天,看到的,听到的,想到的很没有技巧但是却很发自内心的讲给了一起上课的两个专业的同学。(可能有人还记得吧?00应化和00广电)我从上台的一刻起,就决定了:我没权利改变别人,但是我可以告诉别人,有些事情离我们很近,有些事情我们要警惕,有些事情,我们不能做,还有些事情,我们必须做!!!

第二年,韩国青年在日本领事馆前“切指明志”,我盯着韩国青年事后包手指时痛苦表情的照片,心里发出由衷的敬意。

同年,中国有一个很不争气的女明星穿着日本的军旗做的袍子拍照被谴责,可能她不知道,甚至很多人还站在她那边觉得是小题大做。我后来怎么看她的嘴脸,怎么觉得越发恶心。同年8月份,日本首相小泉参拜靖国神社,看着日本老兵穿着二战的衣服,心里又想起了那个日本人和我说过得很多话。

同年冬天,第一次看到王选的事迹。从心底支持这个”英雄”,在我眼里,他就是女英雄。日本人曾经对中国做过什么,当时日语系办了一个日本文化周,我当时真的百感交集,他们的宣传材料上全是说日本这么好那么好,举办活动加强什么交流,还要征文,那几天小泉刚刚参拜过靖国神社,日本导弹威胁中国也是那时候刚发生的事情,他们就不知道为这个来征文吗?想起有些学日语的学生给饭卡加钱的时候,写名字都用日文来写,心里更恼火,难道有些人学日语是为了媚日吗?我当着很多人的面把学校所有的宣传材料都撕掉了——你可以麻木,但是你不可以教唆别人!!!

2002年夏天,我去了沈阳,参观了9·18纪念馆。当我看到日本兵穿过的军装真实地摆在我面前的时候。我的心哭了。我真想把他拿出来烧掉,看着他,想着几十年前,穿这身衣服的人亲手做过些什么??我简直无法忍受!!!!

出馆的时候,我留了很多留言,足足有两页。但是我觉得,写在多都不够表达我的心情,那是一种真正的痛!等我以后有钱了,一定捐钱给9·18纪念馆,让更多的年轻人能够进去看看,让更多的人知道,有些历史是不能忘记的!!!

又是一年”九·一八”,在这天,在我的家乡。大连、沈阳、哈尔滨、长春所有的汽车都会在二十二点鸣一分钟喇叭,东北境内的所有火车也会鸣笛。听到笛声的时候。那是一种什么样的心情?那更像是一种嗥叫!向过去一切不平的嗥叫!——此时我落泪了!!!——-是一种无名的热泪!!!

 

p.s.后记

这一年多以来,我越来越觉得自己的无助和愤恨。很多人仍然麻木。可能有人会说,这管你P事啊?其实这关每个人的事

我还是说那句话:你可以麻木,但是你不能教唆别人。但是很多人一直在教唆别人。

他们有的只是一个想当然的想法和一张不负责任的嘴。在国人越来越欢迎外来事物的时候,谁知道告诉他们一声:有很多东西你应该更加注意,有多少人希望你能做那样的人呐?

再次谢谢大家了。这几天看到很多素不相识的朋友的回复。心里很是安慰,我知道有很多人是和我一起的。

当一个朋友说:”日本有他们的靖国神社,我们的靖国神社在哪?”的时候,我怔住了。是啊,我们的”靖国神社”在哪?哪里有我们吊唁的地方? 所以,我们要做的事情还有很多。

有人看到文章后对我说:”不能鼓吹极端民族主义”,我没有这么想;但是,如果中国没有韩国的民族精神,中国人永远都是一团散沙。难道这个时候,不应该找一种力量来团结自己吗?这样没有错吧。

有人告诉我:”我又没有穿马路,我又没有随地吐痰,这些与我无关。”,但是当你在地铁上看到外国人对这抢座的中国年轻人摇头的时候,你能欣然自得吗?不是的吧?你一定不是!

所有的中国人:在日本人预谋下一个无耻计划的时候,就让我们现在就开始做吧:

同胞们!如果您是个爱国者,请转交10个以上您的朋友、同事……。敬请各位把这篇文章贴到你所知道的任何地方,被日本人杀死的4000万同胞将感谢你!

无赖的老年日本人根本就不承认侵略过中国!
无知的年轻日本人根本就不知道侵略过中国!
无耻的军国主义者说当慰安妇在当时是一种荣耀……

如果你是一个不太喜欢狂热、冒进的温和派,那么我个人认为你应该所做的是:把“不买日货”这个原则默默地记在心里,我们没有必要非得用示威或游行来反对日本可耻的行为,我们应在心里默默的抗议日本对我们犯下的错误和他们对这些错误无耻的抵赖,我们只需要在购买商品的时候更多的忽视一下日货,能不买日货就不要去买。相信自己,只要我们团结起来,人人都能做到这一点,就会使日本在经济上受到打击就会使他们不敢再轻视我们的力量;如果你认为自己很狂热,那么可以先看看下面的数据:在世界各地,近90%的华人用的是:”日本车”,”日本电器”!

我统计过:如果世界各地的所有华人停止购买日货,日本每年将损失”1000-1400″亿美元的外汇收入!!!

“外汇收入”是任何一个国家的源泉和动力,它和国民经济的关系是”一动带八”,或者说:”损失一份外贸收入,这个国家就要损失八份的国内经济收入!”。
换算一下:1000-1400亿美元的外汇收入”等价于”一兆美元——日本经济的总产值的五分之一(1/5)=20%!所以,如果世界各地华人同心协力,不用动刀动枪,就可制日本于死地!而且是永久的死地!!!

我们应该学习犹太人——曾经集体拒买一家德国工厂的产品,最后导致这家公司的彻底破产,起因就是因为这个公司的总裁说了一些所谓”理解希特勒”的话!!
现在德国人对犹太人特别好!!您知道为什么吗?

原因有二:一个是怕——因为犹太人特别团结;第二个是犹太人的狠——犹太人从来没有放弃过对”纳粹分子”的追杀——只要在这个地球上发现有任何藏匿的”纳粹分子”,他们就一定就会”抓——绑架”,如果实在无法得手,那就”杀”!

看看我们中国吧?!”对刽子手的仁慈,无疑就是自杀!”

开始行动吧同胞们:多少年过去了,还要等吗?!开始行动吧!!

从我开始做起!
从我家开始做起!!
从我的朋友开始做起!!!
从我身边的各个组织开始做起!!!!
只要大家共同努力。
最后,我想最多10年,全世界所有的华人都会做到!既使能做到一半(50%),对日本的打击也是致命的!!组织一个全球性的”拒买日货复仇组织”!请在各地”串联串联”,好吗?!同胞们,开始行动吧!可以印些传单,让大家意识”拒买日货”的重要性!”拒买日货”首先要防止被”日本狗”误导,有些所谓的”爱国人士”——-(其时是被日本秘密收买的哈巴狗,目地是挑拨分离我们本来就不团结的中华大众)经常提出:拒买日货是不可能做到的,原因是几乎所有的轿车,电器里,多少都有日本的零件。所以还是打住吧!”、”拒买日货就到此为止”是什么用意?!那是因为日本害怕看到中国大众组织起来,进而进行有效的”抵制日货”运动!故而在这个五十多年来首次完全有可能组织起来一个有效的全球性的”拒买日货运动”时,他们便迫不急待地跳出来叫”停!”、”拒买日货”。并非像他们所说的哪样——”因为这个计算机里有一个或一些日本零件,我就不买;这电视里有几个日本造的电子器件,我就不要”。”拒买日货”的口号实际上是要求全球中国人,在有选择可能的情况下,尽量不买日本造的货物,如汽车,电冰箱,洗衣机,电视,音响……等等!

五十多年来,华人一直记恨于日本,但可笑的是却没有一个有力的”拒买日货”组织!!究其原因,就是因为中国有太多的日本狗从中挑拨分离我们本来就不团结的中华大众!中国同胞们:清醒过来吧!千万不要再被这种人玩了!!!

“拒买日货”的意义:”拒买日货”的意义是巨大的!她能让我们不动一刀一枪就打击了日本,同时又加快了中国经济的发展!她能让我们扼制日本,进而让中国立于不败之地!她能让我们的子孙免遭我们的前几代祖先和我们现代中国人所遭受的痛苦!!她最终也能让这个几百年来一直顽固不化,一再屠杀掠夺中国人民的丑陋民族遭受到它应有的惩罚!!!你以为这容易做到吗?绝对不是!这需要我们大家的共同努力,才能让全体中国人慢慢地,逐渐地意识到,然后才能真实地做到!

不必要的担心:
1、中日友好根本就不存在!过去没有,现在没有,将来也不会有!
2、现在中日贸易总额每年达600亿美元。是不是因为我们全球中华大众对日货的抵制,中国就会受到损失?这是不会的!原因是:a、日本出口到中国的是高级奢侈品——我们中华大众可以拒绝;b、中国出口到日本的是普通生活必须品——日本人很难抵制,他们其实是在享受着我们廉价的产品!
3、另外,从中国的长远利益来看,减少对日本产品的过分依赖,对中国的国家安全是非常重要的,比如日本参加美国的NMD,其目的就是与中国为敌!!!

ThinkPHP3出现“页面无法显示”的330错误问题解决

最近项目用到ThinkPHP,不得不佩服它的强大,今天就发现一个问题,当我们在PHP代码部分如果出现语法错误,带$this->display()模板输出的页面,就会出现330错误,浏览器提示如下:
后来百度,谷歌,能搜的地方都搜了,没有谁提到过,后来就想,是不是环境问题,因为330错误一般为不支持的编码,可是ThinkPHP都是统一编码,自己编码器也是统一UTF-8,几度抑郁之后发现3.0默认开启了”网页压缩输出”:
在配置文件中改为false就一切OK了!^_^..

完美支持中文的文章摘要插件WP CN Excerpt

首先声明一下下,这个插件不是原创,是基于Advanced Excerpt修改的,Advanced Excerpt对于英文文章来说可以说是完美的。

这次对插件的修改主要是加入了中文支持、可选主题内容函数摘要显示( the_excerpt 和the_content),解决了一些在中文环境使用时的bug,支持各种中文编码。可以说是一个非常理想的wordpress文章摘要插件。

当然这个插件在支持中文后有一些功能是没法使用的,比如原来的 按单词切割 功能对中文是无法识别的,不像英文一个单词一个空格分隔。

不管你们信不信,这是我见过摘要功能最强最好用的插件了,重点:支持带样式摘要哦!好了话不多说,看图你就明白它有多强大啦!

 

插件下载地址http://wordpress.org/extend/plugins/cn-excerpt/

2012.10.12日更新:

新增设置首段为摘要功能;

修复“阅读全文”链接位置不对问题;

字数计算不计算标签个数;

2012.9.30日更新:

新增可选主题内容函数摘要显示( the_excerpt 和the_content)功能;

2012.9.21日更新: 

修复Twenty Ten主题无法显示摘要的bug;

您也可以在您的客后台插件中心搜索:wp cn excerpt

如果您觉得此插件对您有帮助,您愿意资助的话,我愿意接受您的资助

如果各位在使用过程中遇到任何问题请到下面留言评论,我会第一时间尽可能解决您的问题。

非常感谢各位使用者,谢谢你们的支持!