Primates 的个人资料Primates照片日志列表更多 ![]() | 帮助 |
|
|
谈谈Unicode编码 简要解释UCS/UTF/BMP/BOM这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题: 使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big endian和UTF-8这几种编码方式间相互转换。同样是txt文件,Windows是怎样识别编码方式的呢? 我很早前就发现Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但这些标记是基于什么标准呢? 查了查相关资料,总算将这些问题弄清楚了,顺带也了解了一些Unicode的细节。写成一篇文章,送给有过类似疑问的朋友。本文在写作时尽量做到通俗易懂,但要求读者知道什么是字节,什么是十六进制。 big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。 “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。 我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。 字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。 GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。 GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。 从ASCII、GB2312、GBK到GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。 有的中文Windows的缺省内码还是GBK,可以通过GB18030升级包升级到GB18030。不过GB18030相对GBK增加的字符,普通人是很难用到的,通常我们还是用GBK指代中文Windows内码。 这里还有一些细节: GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。 在DBCS中,GB内码的存储格式始终是big endian,即高位在前。 GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和GB18030的低字节最高位都可能不是1。不过这不影响DBCS字符流的解析:在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位是什么。 前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。 Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。Unicode的学名是"Universal Multiple-Octet Coded Character Set",简称为UCS。UCS可以看作是"Unicode Character Set"的缩写。 根据维基百科全书(http://zh.wikipedia.org/wiki/)的记载:历史上存在两个试图独立设计Unicode的组织,即国际标准化组织(ISO)和一个软件制造商的协会(unicode.org)。ISO开发了ISO 10646项目,Unicode协会开发了Unicode项目。 在1991年前后,双方都认识到世界不需要两个不兼容的字符集。于是它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从Unicode2.0开始,Unicode项目采用了与ISO 10646-1相同的字库和字码。 目前两个项目仍都存在,并独立地公布各自的标准。Unicode协会现在的最新版本是2005年的Unicode 4.1.0。ISO的最新标准是10646-3:2003。 UCS规定了怎么用多个字节表示各种文字。怎样传输这些编码,是由UTF(UCS Transformation Format)规范规定的,常见的UTF规范包括UTF-8、UTF-7、UTF-16。 IETF的RFC2781和RFC3629以RFC的一贯风格,清晰、明快又不失严谨地描述了UTF-16和UTF-8的编码方法。我总是记不得IETF是Internet Engineering Task Force的缩写。但IETF负责维护的RFC是Internet上一切规范的基础。 UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。下面让我们做一些简单的数学游戏: UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。 UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第3个字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同。 group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节为0的码位被称作BMP。 将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。 UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下: 例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。 读者可以用记事本测试一下我们的编码是否正确。 UTF-16以16位为单元对UCS进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不小于0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为UTF-16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。 UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”? Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法: 在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。 这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。 UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。 Windows就是使用BOM来标记文本文件的编码方式的。 本文主要参考的资料是 "Short overview of ISO-IEC 10646 and Unicode" (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。 我还找了两篇看上去不错的资料,不过因为我开始的疑问都找到了答案,所以就没有看: 我写过UTF-8、UCS-2、GBK相互转换的软件包,包括使用Windows API和不使用Windows API的版本。以后有时间的话,我会整理一下放到我的个人主页上(http://fmddlmyy.home4u.china.com)。 我是想清楚所有问题后才开始写这篇文章的,原以为一会儿就能写好。没想到考虑措辞和查证细节花费了很长时间,竟然从下午1:30写到9:00。希望有读者能从中受益。 网站利润研究(3)2:创建具有盈利点的网站
网站利润研究(2)1.2:功能类网站
1.3:中介类网站
网站利润研究(1)开始着手张罗自己的事情了,以往的经历已经让我迫不及待了——该放弃的需要放弃。 网站,是我将来的内容之一,但并不是全部。研究几年的网站盈利的模式,就要开始自己的历程了。 1:网站的分类
1.1:内容类网站
Google的遗憾最近,看到不少朋友的网站,同时和他们做了一些交流。得到一下几个遗憾: 1:几乎所有的人都不了解如何通过网站得到利润; 2:大家都在一窝蜂的使用同样的方式“想”得到利润,跟风现象严重; 3:没有人好好的研究过这个行业。 ============== 通过Google是最近几年风行的一种利润获取方式之一。这种方式其实是Google参考以往广告点击方式,回报个人网站的一种方式。在以前,不少的网站早就如此做了,国人为此作了不少的努力,很多的个人网站打开后,往往到处都是广告或者弹出式的页面。 其实,我也知道,不少的个人网站的主人,他们把自己的网站做大作强仅仅只停留在一种想象中——就是幻想,并没有真正的努力过。这一点,我不能否认,因为对于大部分人来说,短期的利益是值得考虑的,如果自己的网站几年后就倒闭了,大不了自己再办一个网站,重新换一个面孔再去骗取用户的点击。 也许我个人的性格使然,我一直想努力做一个自己的、长期的、有价值的个人网站。同样,我的个人网站会放上Google的广告,但我并不会刻意的去点击他,也不会勉强用户去点击。 JavaScript:Window.ShowModalDialog使用手册基本介绍: showModalDialog() (IE 4+ 支持) showModelessDialog() (IE 5+ 支持) window.showModalDialog() 方法用来创建一个显示HTML内容的模态对话框。 window.showModelessDialog()方法用来创建一个显示HTML内容的非模态对话框。 使用方法: vReturnValue = window.showModalDialog(sURL [, vArguments] [,sFeatures]) vReturnValue = window.showModelessDialog(sURL [, vArguments] [,sFeatures]) 参数说明: sURL -- 必选参数,类型:字符串。用来指定对话框要显示的文档的URL。 vArguments -- 可选参数,类型:变体。用来向对话框传递参数。传递的参数类型不限,包括数组等。对话框通过window.dialogArguments来取得传递进来的参数。 sFeatures -- 可选参数,类型:字符串。用来描述对话框的外观等信息,可以使用以下的一个或几个,用分号“;”隔开。 ---------------- 1. dialogHeight: 对话框高度,不小于100px,IE4中dialogHeight 和 dialogWidth 默认的单位是em,而IE5中是px,为方便其见,在定义modal方式的对话框时,用px做单位。 2. dialogWidth: 对话框宽度。 3. dialogLeft: 离屏幕左的距离。 4. dialogTop: 离屏幕上的距离。 5. center: { yes | no | 1 | 0 } : 口是否居中,默认yes,但仍可以指定高度和宽度。 6. help: {yes | no | 1 | 0 }: 是否显示帮助按钮,默认yes。 7. resizable: {yes | no | 1 | 0 } [IE5+]: 是否可被改变大小。默认no。 8. status: {yes | no | 1 | 0 } [IE5+]: 是否显示状态栏。默认为yes[ Modeless]或no[Modal]。 9. scroll: { yes | no | 1 | 0 | on | off }:指明对话框是否显示滚动条。默认为yes。 下面几个属性是用在HTA中的,在一般的网页中一般不使用。 10. dialogHide:{ yes | no | 1 | 0 | on | off }:在打印或者打印预览时对话框是否隐藏。默认为no。 11. edge:{ sunken | raised }:指明对话框的边框样式。默认为raised。 12. unadorned:{ yes | no | 1 | 0 | on | off }:默认为no。 参数传递: 1. 要想对话框传递参数,是通过vArguments来进行传递的。类型不限制,对于字符串类型,最大为4096个字符。也可以传递对象,例如: ------------------------------- parent.htm modal.htm ------------------------------- 2. 可以通过window.returnValue向打开对话框的窗口返回信息,当然也可以是对象。例如: ------------------------------ parent.htm modal.htm JavaScript:window.open的使用方法以及参数说明一、window.open()支持环境: JavaScript1.0+/JScript1.0+/Nav2+/IE3+/Opera3+ 二、基本语法: window.open ( pageURL , name , parameters ) 其中: pageURL 为子窗口路径 name 为子窗口句柄 parameters 为窗口参数(各参数用逗号分隔) 三、示例: 脚本运行后,page.html 将在新窗体 NewWindow 中打开,宽为100,高为400,距屏顶0象素,屏左0象素,无工具条,无菜单条,无滚动条,不可调整大小,无地址栏,无状态栏。 请对照上例中涉及的为常用的几个参数,除此以外还有很多其他参数,请见四。 四、各项参数 其中 yes/no 也可使用 1/0;pixel value 为具体的数值,单位象素。 参数 取值范围 说明 alwaysLowered yes/no 指定窗口隐藏在所有窗口之后alwaysRaised yes/no 指定窗口悬浮在所有窗口之上 depended yes/no 是否和父窗口同时关闭 directories yes/no Nav2和3的目录栏是否可见 height pixel value 窗口高度 hotkeys yes/no 在没菜单栏的窗口中设安全退出热键 innerHeight pixel value 窗口中文档的像素高度 innerWidth pixel value 窗口中文档的像素宽度 location yes/no 位置栏是否可见 menubar yes/no 菜单栏是否可见 outerHeight pixel value 设定窗口(包括装饰边框)的像素高度 outerWidth pixel value 设定窗口(包括装饰边框)的像素宽度 resizable yes/no 窗口大小是否可调整 screenX pixel value 窗口距屏幕左边界的像素长度 screenY pixel value 窗口距屏幕上边界的像素长度 scrollbars yes/no 窗口是否可有滚动栏 titlebar yes/no 窗口题目栏是否可见 toolbar yes/no 窗口的像素宽度 z-look yes/no 窗口被激活后是否浮在其它窗口之上构建稳健的B/S系统——词语过滤机制 (有待商榷)最近,问了很多业内的朋友,询问有关如何有效控制过滤用户输入的内容。结果却让我大失所望,很多业内的同行,长期以来并没有在意这个问题,尤其是那些只做B/S系统的人,基本上就是敞开式的接受任何用户的输入。 要构建一个稳健的系统,那么必须考虑操作者的任何的可能性。比如,在以ASP.NET为平台的系统上,如果在输入框中输入"<"或者">"(尖括号),那么势必引起 .NET 安全机制的的警告,系统不会执行下去。同时,如果操作者在输入框里面输入"'"(英文状态下的单引号),势必会造成数据库语言的错误... ... 还有更多的是因为政治的需要,需要过滤或者替换的一些词语。这些,都是需要程序员的努力,做到系统的稳定和社会的稳定。 为此,我们可以单独写一个类,如下( VB.NET ): 1 Imports System.Text.RegularExpressions 2 Namespace MiniData 4 Function WordPress(ByVal Textstr As String) As String 14 ObjRe = New Regex("\n") 19 End Class ========== 这里,我创建了一个命名空间 MiniData,定义了一个 MiniDataPress 类。主要是利用 "正则表达式" 类 (RegularExpressions) 的替换方法。我这里写的仅仅只是一个例子。 其中,自定义 WordPress 方法是用来过滤用户输入的。这里面,执行的顺序应该是有讲究的。 对于 asp:textbox 控件为单行属性的输入框,不会有"换行符"的现象存在;还有,如果像"姓名"之类的输入框,中文姓名我们必须要去除文字之间的的空格,如: "张 三" (汉字之间有空格) 要成为 "张三" (无空格),而对于英文名称,单词之间又必须有一个空格,如: " Report Abouse" ,这就不需要处理。 还有就是为了系统安全,我们必须去除掉"<"、">"、"@@"(数据库控制命令前缀)、"'"(单引号)... ... 另外,为了排版的问题,很多人喜欢把 "换行符" 替换成 "<br>",根据我的经验,这样不是很好,因该替换成 "</p><p>",因为一个换行,是上一段文字的结束和下一段文字的开始,然后再给所有内容的开始和结尾分别加上<p>与</p>,补齐标签。这就是上面第14行到第17行的处理方式。出来的形式应该是: <p>开始.......</p><p>第一段文字........</p><p>第二段文字... ...</p><p> ... ... </p> 这样子的形式,很容易在 CSS 当中设置 p 的样式,可以做到每个段落的起始行缩进两个字符 (12号宋体的话应该是 24px 的缩进量),符合中国人的习惯。如: p { ============= 以上是我只对一些安全性而作的过滤,但是面对众多的政治性的过滤词,我觉得这种方式太繁琐。 还没有一个值得在这里记载的方法,因此,本文标题是“有待商榷”。希望高手能给与指点。 |
|
|