Unicode Bidi 是一门学问

来源:互联网 发布:淘宝网成交量 编辑:程序博客网 时间:2024/05/20 11:26

试试把下面一行文字复制到纯文本编辑器内,比如记事本,下面的回复框,或者浏览器的地址栏:

123العربية456

结果如何呢?

至少在我的电脑上,是这样的:

Unicode Direction

很神奇吧?

对于大部分纯文本编辑器而言,在正确配置和识别 Unicode 的情况下,文字方向同上面写字板,大体上有如下规则(这里以从左到右文字的操作系统为例,另外严格的说法见文末链接的 Table 4 ):
1、默认从左到右;
2、如果中间出现从右到左的语言文字,则插入从右到左的片段;
3、如果该片段右侧有数字且片段和数字间没有字母,则数字片段放在左侧。
这里的字母是指 Unicode Letter ,汉字之类也算在内。
记事本似乎还多了一条规则:
4、如果该片段左侧有数字且片段和数字间没有任何字符,则数字片段放在右侧。
不过也有例外,比如 gedit 就更复杂,根据片段+数字外部字母的情况,有时是正确的顺序,有时同写字板顺序,有时左对齐,有时右对齐……

总而言之,这是毋庸置疑的 bug 。

那么,怎样才能得到正确的顺序呢?

很简单,数字之前插入字母就行了。(废话
不,不,这不是废话,虽然还有别的方法,不过我强烈建议你这么做,因为这是兼容性最好的方法

……就算我这么讲,你也一定对别的方法感兴趣吧?

在 HTML 中,可以用 <bdo dir=”ltr”> 和 <bdo dir=”rtl”> 控制:

<bdo dir="ltr">123<bdo dir="rtl">العربية</bdo>456</bdo>

结果是这样的:

123العربية456

在 CSS 中,可以用 direction: ltr 和 direction: rtl 控制:

<span style="direction: ltr; unicode-bidi: bidi-override; ">    123    <span style="direction: rtl; unicode-bidi: bidi-override; ">العربية</span>    456</span>

结果是这样的:

123العربية456

unicode-bidi 属性涉及到 Unicode Bidirectional Text 的两种算法,这里不讨论,感兴趣请参考最后面的链接。

另外靠标签解决问题只限于超文本内,像最开始那样复制出来然后粘贴到纯文本编辑器,或者类似于 HTML 的 <title> 之类不能用标签的地方,顺序就面目全非了。

那么对于纯文本,该怎么办呢?

答案是 Unicode 控制字符:

Unicode 控制字符

最容易上手的方法就是记事本的右键菜单,如果你是一位久经考验的敏感词战士,一定早听说过了。

这里只需要用到三个:
1、RLO ( Code "\u202E" ; HTML &#x202E; ) :开始从右到左的文字;
2、LRO ( Code "\u202D" ; HTML &#x202D; ) :开始从左到右的文字;
3、PDF ( Code "\u202C" ; HTML &#x202C; ) :结束上一次定义。
(另外还有四个相关的控制字符 RLE 、 LRE 、RLM 、LRM 姑且放在一边……)

这几个控制字符实际上是不可见的,以下为了说明方便,姑且用方括号括起来。

要显示正确的顺序,只要按如下方式加入这些控制字符:

[LRO]123[RLO]العربية[PDF]456[PDF]

结果是就是这样:

‭123‮العربية‬456‬

区别有木有!!!!!
三击鼠标选择那行文字复制粘贴到浏览器地址栏,如何,是不是也能保持正确的顺序啦~

什么?不是?
……你八成是 IE 用户吧|||
IE 不会把最前面的 LRO 选进去,别问我为啥……

还有一种情况是,确定两边是从左往右,但是中间有时是从左往右,有时是从右往左,有没有办法在不指定中间文字方向的情况下避免两边文字的顺序受中间文字顺序的影响呢?

也是有的,比如左边插入 RLO PDF ,右边插入 LRO PDF :

123[LRO][PDF]العربية[LRO][PDF]456123[LRO][PDF]abcd[LRO][PDF]456

结果如下:

123‭‬العربية‭‬456
123‭‬abcd‭‬456

……呃,这回 IE 和 Chrome 是正常的,火狐好像把控制字符都忽略掉了。

在片段中间插进一个空格试试:

123[LRO] [PDF]العربية[LRO] [PDF]456123[LRO] [PDF]abcd[LRO] [PDF]456

这下火狐倒是正常了,IE 把第一行右边的空格挪到了左边……

123‭ ‬العربية‭ ‬456
123‭ ‬abcd‭ ‬456

如果在右侧再加上一个 LRO PDF 呢?

123[LRO] [PDF]العربية[LRO][PDF][LRO] [PDF]456123[LRO] [PDF]abcd[LRO][PDF][LRO] [PDF]456

这下 IE 正常了,Chrome 把左边的空格移到了右边 Orz

123‭ ‬العربية‭‬‭ ‬456
123‭ ‬abcd‭‬‭ ‬456

……我也不想这样的:

123[LRO] [PDF][LRO][PDF]العربية[LRO][PDF][LRO] [PDF]456123[LRO] [PDF][LRO][PDF]abcd[LRO][PDF][LRO] [PDF]456

全浏览器!兼容!(才怪

123‭ ‬‭‬العربية‭‬‭ ‬456
123‭ ‬‭‬abcd‭‬‭ ‬456

……不过这也太丑陋了!

你可能在想用 ‍Zero Width Joiner 、‍ Zero Width Non-Joiner 、 Zero Width Space 或者 Zero Width No-Break Space 代替空格能不能解决火狐的兼容问题,很可惜,也不行。

不过姑且摆平了浏览器,再看看桌面软件,写字板没问题,gedit 没问题,记事本……还是不行??

……果然记事本里头还是有无穷的故事呀。

此外,控制字符的方法也不是万能的,比如遇上 Twitter 这种见到控制字符就删的或者 Google Calendar 这种见了阿拉伯文就给 direction: rtl 的,大概只能哭了……

如果你还想深入地研究这个问题,请移步 Unicode Bidirectional Algorithm 。


引自:http://blog.ieph.net/archives/446