有关Unicode

原作者:Joel Spolsky

原文:http://www.joelonsoftware.com/articles/Unicode.html

译者注 1:笔者翻译本文的主要目的是为了自学,所以翻译的比较粗,并且掐头去尾。

译者注 2:本文的翻译过程中,特地保留了一些技术性词汇的英文原词,因为译者认为牵强地翻译这些词汇是愚蠢的行为。

译者注 3:本文并非逐字翻译,一些译者人为不重要的部分被省略了。


  • 一段历史

想要理解这件事,最简单的角度就是从时间发展的角度来看。

你可能会以为我会要讲EBCDIC那些非常老的字符集。你错了。EBCDIC已经跟我们的生活没有任何关系,我们不用从那么早开始。

我们从稍微晚一点的时候开始讲起,那时候Unix正在被发明,K&R也正在编著The C programming Language。一切都非常简单。EBCDIC也正在渐渐退出历史舞台。那时候人们只关心没有重音的英文字符。我们有ASCII表,因此所有的英文字符都可以用32到127之间的数字来表示,比如’A’是65。7个bits就足够来表示这些了,而那时候的电脑已经普遍使用8个bits为一个字节。所以不但可以用一个字节来表示所有的ASCII字母,还多出一个bit。这个多出来的bit可以被你用来做你自己想做的事情。比如WordStar的那些人就把每一个词的最后一个字母的最高bit(多出来的bit)设为1。32以下的那些字符被称为unprintable(不可打印)字符,他们是“控制字符”。比如7号字符可以让你的计算机“滴”一声;而12号字符会让打印机略过当前的纸张剩余部分,而直接进入下一张纸。

由于一个byte有八个bits,人们开始想:我们可以用128-255这些字符来做一些有趣的事情。有很多人产生了这个想法,并且用自己各自的想法去实现。这就造成了128-255这些字符的定义因人而异了。比如IBM-PC发明了广为人知的OEM字符集,它包括带重音的字母(一些欧洲文字会用到),还有许多用来划线的字符:水平线;垂直线;最右端带有一些零零碎碎装饰的水平线等等不一而足。你可以用这些划线字符在屏幕上画出很漂亮的方块和线条。这些东西在当今的一些干洗店中使用的电脑上还是可以找到的。但是一旦人们开始从美国以外的地方购买电脑,各种各样的OME就出现了,它们都用了各自的方法来定义128-255这些字符。比如说,在某些电脑上,130号字符被定义为é,但那些在以色列销售的电脑,130号字符被定义为希伯来文的Gimel字母。所以如果一个美国人把自己的简历(英文:résumé)发送到以色列的话,就会得到很奇怪的结果。在许多其他地方,比如苏联,128-255的定义方法更是多种多样,所以根本不可能顺利地传输一份苏联的文件。

终于,大家各自为营的局面被终止了,因为出现了ANSI标准。在这个ANSI标准中,0-127的定义大家没有任何歧义,就跟ASCII一样;但对于128-255,不同的地方有不同的定义方法。这些不同的定义方法被称为不同的code page。比如以色列的DOS系统用的就是862号page code;希腊用的是737号。它们之间唯一的不同就是128-255这些字符。在美国用的MS-DOS有好几种code page,用来处理各种不同的语言。当时甚至有“多语言code page”,可以实现在同一台电脑上既能处理世界语也能处理加利西亚语。但是很多其他情况就不行了,比如如果你想在同一台电脑上处理希伯来文和希腊文,你只能自己重新定义和编写128-255字符集,并且用点阵把它们画出来,因为希伯来文和希腊文用的是不同的code page,也就意味着它们对于128-255的定义是不同的。

与此同时,在遥远的亚洲,人们在思考更加疯狂的问题。因为很多亚洲语言有上千个字符,一个byte根本不够用。这个问题通常是由一个非常二的叫做DBCS(“double byte character set”)的系统来解决的。在这个系统里,有些字符被存在一个byte里,而另一些则被存在两个bytes里面。这导致了正向遍历一个字符串是容易的,但如果想逆向的话是几乎不可能的。那时的程序员一般会避免使用s++或者s--这种方法来向前或者向后移动,而一般会选择使用微软出的AnsiNext和AnsiPrev来处理这个烂摊子。

谈不管怎么说,大部分人仍然生活在“一个byte就够用了”的气泡里。只要他们不把一个文件从一台计算机拷贝到另一台,或者讲另外一种语言,这个原则是够用的。但是,在因特网出现之后,文件从一台计算机拷贝到另一台变成了一件非常常见的事情,于是乎世界大乱。

好在,Unicode被发明了。

  • Unicode

Unicode的野心很大,它想用一个字符集来包括这个星球上所有的书写系统,甚至包括像克林贡这种语言。有些人误认为所谓Unicode其实就是使用两个byte也就是16bits来保存字符,那就可以保存65,536个不同的字符。但事实上,这并不完全正确。这是一个非常常见的错误。Unicode对于字符有自己全新的理解。想要理解Unicode,就必须使用它的一套哲学去思考问题。

到现在为止,我们一直认为,每一个字符对应的是硬盘或内存中的一些bits,比如:

A —> 0100 0001

在Unicode中,一个字母对应的是一个code point。不要被这个词吓到,这只是一个存在于理论中的概念。这些code point如何对应到硬盘或内存中的bits,就是一件完全不同的事情了。

在Unicode中,字母A是一个柏拉图式的完美存在。它不同与B,也不同于a,但是如果仅仅是字体不同的A之间是没有差别的。这貌似很好理解,但是在某些其他语言中,仅仅是辨别字母就有可能会引发争论。比如德文字母b就很容易被误认为是另一种写ss的写法。如果一个字母当出现在单词末尾的时候会变形,那它还是同一个字母么?在希伯来文中,答案是是;但在阿拉伯文种,答案是否。但是不管怎样,发明Unicode的那群人已经把这些问题都考虑到了。为此他们花了过去十年的时间,以及许多政治博弈。总之就是,你不必再为这些事情担心了,它们已经都被考虑到了。

在Unicode中,每一种语言中的每一个柏拉图式的字母都被赋予了一个奇妙数字。这个奇妙数字长这样:U+0639。这个奇妙数字被称为code point。U+表示是Unicode,而后面的数字是十六进制的。U+0639表示的是阿拉伯字母Ain。英文字母A的奇妙数字是:U+0041。你可以在Windows中的charmap工具里查找这些奇妙数字,也可以去Unicode的网站上查。

Unicode可以定义的不同字符数量是无限的。事实上现在已经超过了65,536 个并且已经不能用两个bytes来表示了。

不管怎样吧,假设现在我们有一个字符串:Hello,那么在Uniocde中,它对应了五个code point:U+0048 U+0065 U+006C U+006C U+006F。注意,这仅仅是几个code point,我们还没有讨论到如何把它们存储到计算机里去。

这就是编码发挥作用的时候了。

  • 编码

Unicode最早的想法是:为什么不把code point后面的数字存储在两个bytes里面呢?这也就是为什么很多人会把Unicode理解为两个bytes。如果是这样的话,上文中的“Hello”一词就变成了:00 48 00 65 00 6C 00 6C 00 6F。但不要这么快,是不是也可以变成:48 00 65 00 6C 00 6C 00 6F 00?这么做看似可行。由于当时对于Unicode的实现必须要考虑是high-endian还是 low-endian模式(有关high-endian和 low-endian,情自行wiki)。为了这种情况人们不得不形成一种很奇怪的规定,也就是在每一个Unicode前面加上FF FE或者FE FF,这个东西叫做Unicode Byte Order Mark。

这一切看上去似乎可行,但不久后,程序员们开始抱怨了:“怎么他喵的这么多0?”因为他们是美国人,并且很少使用英语以外的语言,所以他们很少会用到U+00FF以上的字符。而且之前已经有ANSI和DBCS等各种各样麻烦的标准,谁又来负责转换呢?我吗?所以很多人故意忽略Unicode的存在忽略了很多年,与此同时,事情变得恶化了。

这就是为什么会有UTF-8这个聪明的发明。UTF-8是一种把Unicode code point存储进内存的系统,也就是那些带U+的奇妙数字。它把每一个奇妙数字都用8个bits来表示。在UTF-8中,每一个0-127的code point都被存储为1个byte,只有那些超过128的,才被存储为2,3甚至到6个bytes。这样做有一个很好的地方在于,所有的英文字符跟ASCII是一样的,所以那群骄傲的美国人就会觉得很开心,他们根本不需要做任何的适应。只有世界上其他地方的人需要来适应这个系统。比如说,Hello这个词,对应的code point是U+0048 U+0065 U+006C U+006C U+006F,那么在计算机中就被存为48 65 6C 6C 6F。注意了,这跟ASCII,ANSI以及每一个OME字符集都相符合。只有当你需要使用带注音的字符或者比如希腊字母的时候,你才需要多余的bytes来存储一个code point,但是美国人是不需要知道这些的。

到目前为止,我已经告诉了你三种存储Unicode的方式。传统的把Unicode存为两个bytes的方法叫做UCS-2,或者UTF-16,但你还需要搞清楚到底是high-endian UCS-2还是low-endian UCS-2。而比较流行的是UTF-8标准,它的好处是英文字母跟ASCII一样。

事实上,Unicode还有许多其他的编码方式,比如有一种叫做UTF-7,它很像UTF-8,但最高位bit永远是0。这也就意味着其实7个bits就足够存储了。还有一种叫做UCS-4,它的特点是,所有的code point都是4个bytes。这样的好处是,所有的code point都一样,但缺点也是显而易见:太耗费内存了。

好了,现在你可以用unicode的code point来想象你的那些柏拉图式的字母了,而这些字母也可以用老式的encoding方法来编码,只不过有些字母可能显示不出来。因为你用unicode来表示的这些字母可能跟你所使用的编码方式不吻合,于是你就得到许多问号。有很多传统的编码方式只能正确地表示一部分unicode的code point,而其他的字符都被表示为问号。比较流行的引文的编码方式有Windows-1252和ISO-8859-1,即Latin-1。但是如果你试图用这些编码方式来存储俄文或者希伯来文,你将会得到许多问号。而UTF 7, 8, 16, 和 32 等这些编码方式的一个特点就是,它们能够正确地存储任何code point。

  • 有关encoding最重要的事情

就算你忘记了我上面所解释的一切,请记住我下面这句最重要的话:如果我们有一个string却不知道它的encoding方式,那么这个string就没有意义。你不能还用固有的眼光来看问题,以为所有的“plain text”都是ASCII。

这个世界上没有”plain text”这件事。

如果你的内存中、文件中或者是邮件中有一些string,你必须知道它们是用什么方式编码的,这样才能正确地显示它们。所有的“邮件读不了”等类似的问题,都是因为有一个二逼程序员不能理解如果不告诉别人你的string是如何编码的,别人就读不了你的string。

好了,我们应该如何来保存有关编码的信息呢?有一些标准的方法来解决这个问题。比如在邮件中,header里应该有一句话:

Content-Type: text/plain; charset=“UTF-8"

而在网页中,原来的计划是让服务器返回一个类似Content-Type的东西,跟网页一起。注意,不是在网页中,而是在html网页发送前所发送的一些回复的头部。

(后面的懒得翻译了……有兴趣的自己去看原文吧。)

下面这张图是我从Wiki上截的,比较清楚地说明了UTF-8的组成。UTF-8是世界上最流行的encoding方式。


今天看到一道google面试题说的是给一个文件,要求写一段程序来判断它是不是UTF-8 encoding。根据上面这个表格,我们可以轻松地搞定这个程序。

下载前可以先看下教程 https://pan.quark.cn/s/a426667488ae 标题“仿淘宝jquery图片左右切换带数字”揭示了这是一个关于运用jQuery技术完成的图片轮播机制,其特色在于具备淘宝在线平台普遍存在的图片切换表现,并且在整个切换环节中会展示当前图片的序列号。 此类功能一般应用于电子商务平台的产品呈现环节,使用户可以便捷地查看多张商品的照片。 说明中的“NULL”表示未提供进一步的信息,但我们可以借助标题来揣摩若干核心的技术要点。 在构建此类功能时,开发者通常会借助以下技术手段:1. **jQuery库**:jQuery是一个应用广泛的JavaScript框架,它简化了HTML文档的遍历、事件管理、动画效果以及Ajax通信。 在此项目中,jQuery将负责处理用户的点击动作(实现左右切换),并且制造流畅的过渡效果。 2. **图片轮播扩展工具**:开发者或许会采用现成的jQuery扩展,例如Slick、Bootstrap Carousel或个性化的轮播函数,以达成图片切换的功能。 这些扩展能够辅助迅速构建功能完善的轮播模块。 3. **即时数字呈现**:展示当前图片的序列号,这需要通过JavaScript或jQuery来追踪并调整。 每当图片切换时,相应的数字也会同步更新。 4. **CSS美化**:为了达成淘宝图片切换的视觉效果,可能需要设计特定的CSS样式,涵盖图片的排列方式、过渡效果、点状指示器等。 CSS3的动画和过渡特性(如`transition`和`animation`)在此过程中扮演关键角色。 5. **事件监测**:运用jQuery的`.on()`方法来监测用户的操作,比如点击左右控制按钮或自动按时间间隔切换。 根据用户的交互,触发相应的函数来执行...
垃圾实例分割数据集 一、基础信息 • 数据集名称:垃圾实例分割数据集 • 图片数量: 训练集:7,000张图片 验证集:426张图片 测试集:644张图片 • 训练集:7,000张图片 • 验证集:426张图片 • 测试集:644张图片 • 分类类别: 垃圾(Sampah) • 垃圾(Sampah) • 标注格式:YOLO格式,包含实例分割的多边形点坐标,适用于实例分割任务。 • 数据格式:图片文件 二、适用场景 • 智能垃圾检测系统开发:数据集支持实例分割任务,帮助构建能够自动识别和分割图像中垃圾区域的AI模型,适用于智能清洁机器人、自动垃圾桶等应用。 • 环境监控与管理:集成到监控系统中,用于实时检测公共区域的垃圾堆积,辅助环境清洁和治理决策。 • 计算机视觉研究:支持实例分割算法的研究和优化,特别是在垃圾识别领域,促进AI在环保方面的创新。 • 教育与实践:可用于高校或培训机构的AI课程,作为实例分割技术的实践数据集,帮助学生理解计算机视觉应用。 三、数据集优势 • 精确的实例分割标注:每个垃圾实例都使用详细的多边形点进行标注,确保分割边界准确,提升模型训练效果。 • 数据多样性:包含多种垃圾物品实例,覆盖不同场景,增强模型的泛化能力和鲁棒性。 • 格式兼容性强:YOLO标注格式易于与主流深度学习框架集成,如YOLO系列、PyTorch等,方便研究人员和开发者使用。 • 实际应用价值:直接针对现实世界的垃圾管理需求,为自动化环保解决方案提供可靠数据支持,具有重要的社会意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值