加载中…
正文 字体大小:

新浪微博可以发140个字符?谁告诉你的!

(2012-12-21 15:57:07)
标签:

微博

unicode

分类: 陈述题
新浪微博可以发140个字符?谁告诉你的!

新浪微博可以发140个字符,这句话对吗?“呃……我从来没想过这个问题,好像是吧。难道不是吗?”

新浪微博无论是用专用的客户端(比如iPhone上的新浪微博,或者Weico),还是用浏览器直接输入,其实都会显示还可以输入“140字”。字面上看,似乎没有什么错。可是既然我提问了,当然不是这么回事了。

其实一般人大概不会这么无聊的提这样一个问题,不过大部分人都应该知道这不是一个正确的描述。因为当我们转发内容的时候,假如右边信息量太大,我们甚至会偷偷的通过将全角的冒号“:”,修改成半角的冒号“:”,来省半个字符。“艹,我怎么不知道。”不能吧?难道你没有注意到,当你在一个空白的输入框当中输入两个英文字母的时候,会显示还可以输入139个字符?

新浪微博可以发140个字符?谁告诉你的!

“嗯,好吧!那就是可以输入140个全角字符,半角字符算半个呗!”你确定?要确认这个事情,我们必须搞清楚一件事:半角字符有哪些呢?

所谓全角半角,其实只是同样形状的字符,在显示时宽度不一样而已。这个本来并非一个学术上的严谨定义,所以我们很难找到很严肃的定义。幸好维基百科记载了有关全角字符和半角字符的对比,比如说:

全角 半角
B

“哎,没错啊!你看那B!”嗯,B这个嘛,是没有错。可是你看,有全角和半角不仅仅是英文字母啊,还有日文、韩文,甚至还有各种符号。比如说“←”这个就是半角字符了吧,你在网页版上输入一下看看?

新浪微博可以发140个字符?谁告诉你的!

新浪微博可以发140个字符?谁告诉你的!

对啊,为啥这两个半角字符又算俩了呢?其实啊,这和他们俩的Unicode编码有关系:B是U+0042,而←是U+FFE9。很显然啊,后者的Unicode编码比较大,前者则非常小。你看啊,普通英文字母加数字,还有很多标点符号都的Unicode编码在U+00FF以内。大家试试看是不是这样?(噼里啪啦……)“哦!果然如此啊!你看,输入abc,还有标点符号什么的果然两个算一个。但是那些半角的日文韩文什么的,都是一个字符就是一个了。”大家有没有想到点什么啊?

新浪微博可以发140个字符?谁告诉你的!

没错,UTF-8确实会对编码比较小的字符,比如半角英文数字,使用1个字节来编码,而编码值较大的字符则使用更多的字节来表示。而且呢,新浪微博在HTTP传输协议中指明了编码格式是UTF-8。我一度也这么怀疑,因为这个解释最合理了:你看啊,B是用一个字节来编码,而“草”则需要使用两个字节来编码……

新浪微博可以发140个字符?谁告诉你的!

别急啊!错了啊!首先呢,“草”这个字符并不是占用2个字节,而是3个字节(请仔细看UTF-8的编码方式);其次呢,“£”这个字符(U+00A3)占用2个而不是1个字节,但是在新浪微博里面他算半个字符,如下图所示:

新浪微博可以发140个字符?谁告诉你的!

新浪微博可以发140个字符?谁告诉你的!

要搞清楚这个问题,看来呢还是得要挖掘一下新浪到底是怎么判定的。很简单,我们用Chrome打开之后,对那个“140字”的标签加上DOM对象移除断点,然后跟啊跟啊就能跟踪到判定到底怎么算数量的地方了。(过程比较复杂,略过。)实际上呢,他判定长度的代码如下所示:

STK.register(" kit.extra.count",="" function(a)="" {<="" div="">
    function b(b) {
        var c = 41, d = 140, e = 20, f = b, 
          g = b.match(/http:\/\/[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+([-A-Z0-9a-z_\$\.\+\!\*\(\)\/,:;@&=\?\~\#\%]*)*/gi) || [], 
          h = 0;
        for (var i = 0, j = g.length; i < j; i++) {
            var k = a.core.str.bLength(g[i]);
            if (/^(http:\/\/t.cn)/.test(g[i]))
                continue;
            /^(http:\/\/)+(t.sina.com.cn|t.sina.cn)/.test(g[i]) || /^(http:\/\/)+(weibo.com|weibo.cn)/.test(g[i]) ? h += k <= c ? k : k <= d ? e : k - d + e : h += k <= d ? e : k - d + e;
            f = f.replace(g[i], "")
        }
        var l = Math.ceil((h + a.core.str.bLength(f)) / 2);
        return l
    }
    return function(a) {
        a = a.replace(/\r\n/g, "\n");
        return b(a)
    }
});

STK.register("core.str.bLength", function(a) {
    return function(a) {
        if (!a)
            return 0;
        var b = a.match(/[^\x00-\xff]/g);
        return a.length + (b ? b.length : 0)
    }
});

关键的那几句我已经高亮了,尤其注意第二个高亮的代码行。这一行的意思就是说:所有编码不在U+0000至U+00FF的,都要多算一遍。嗯,这就解释了为啥“£”也算作半个字符了。(因为是U+00A3嘛!)

“哦!明白了,就是说,所有Unicode编码在0xFF及以内的,都算半个字符,编码更大的字符就算一个!噢耶!”

还是错了,问题没有那么简单。比如说,如果我们输入一个Unicode编码为U+E0001的字符“󠀁”(如果你用IE浏览器,两个引号之间看不到内容,请使用Chrome)时,会变成这样:

新浪微博可以发140个字符?谁告诉你的!

新浪微博可以发140个字符?谁告诉你的!

确实有点坑爹,难道说还有什么别的没看见的JS脚本在影响?答案是“没有”。实际上用Javascript执行var b = a.match(/[^\x00-\xff]/g);这一句时,如果a是一个大于U+FFFF的字符,比如U+20005的𠀅(哎?这字怎么念?),会被识别为长度为2的字符串,并且会得到两个匹配,于是2+2=4然后4/2=2,就得到了2个字符的结果。如下图所示:

新浪微博可以发140个字符?谁告诉你的!

于是,我们似乎要这么描述才能说清楚:“你可以输入140个尼玛,Unicode编码在U+0000到U+00FF之间的(含)算半个尼玛,在U+0100至U+FFFF之间的(含)算一个尼玛,而在U+FFFF以上的(不含)则算两个尼玛。”

“嗯,事情到这里总算是结束了吧?”其实还没有……

新浪微博可以发140个字符?谁告诉你的!

比如说这个转发后的微博,如果你再次转发,你会发现是这样的:

新浪微博可以发140个字符?谁告诉你的!

或者是这样的:

新浪微博可以发140个字符?谁告诉你的!

这是因为我这个转发当中,“大家”之间长了大概129个U+FEFF(不可见分页符)。如果你用iPhone上的客户端转发呢,这些字符统统看不见,却还是要计算在内的。而在网页客户端呢,则被转换成了普通的空格(U+0020),于是给你腾出了一定的空间。

当然了,这个例子并没有破坏刚才我们对“140个尼玛”的定义。只不过呢,谁知道别的客户端会不会对这个计算方式产生什么奇怪结果呢…… 

唔……没看过新浪的开发手册,不知道有没有对此作出严谨的定义呢?知道的站出来说句话呗。

P.S.: 其实为啥U+FFFF以上的字符(不含),会认为是2个呢?这是因为一般来说我们的机器在处理字符的时候,使用的是UTF-16编码,也就是用两个字节算作一个字符。但是如果字符是U+FFFF以上(不含)的时候该怎么办呢?答案是使用两个代理字符来表示。

Unicode编码特地保留了U+D800至U+DBFF之间的字符,专门用于表示辅助平面的字符(U+10000至U+10FFFF)。比如说,U+D800、U+DC00这一组合就表示U+10000,具体请参见维基百科这里的描述。换句话说,U+10000及以上的字符,在UTF-16的系统中,就是用两个字符表示的。

嘿,所以,“𠀅”这是2个字符(用VS2012 RC的即时窗口看):
新浪微博可以发140个字符?谁告诉你的!

或者,我们应该说“𠀅”这个字符串包含了两个尼玛更合适……

新浪微博可以发140个字符?谁告诉你的!

0

阅读 评论 收藏 转载 喜欢 打印举报
已投稿到:
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4006900000 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有