Unicode 控制字符及其有关的双向算法

2018-10-12 admin

控制字符(有时候也称非打印字符),是出现在特定的信息文本中,表示某一控制功能的字符.这类字符并不显示,只包含某种特定的功能.

前段时间介绍了ASCII 控制字符,但是不止ASCII有这类控制字符,Unicode也有,而且应用的更广泛.如果你使用Safari浏览器,建议换成Chrome配合控制台中Element查看元素阅读更佳.

介绍

我们需要理解的是:在所有主要的Web浏览器中内存中的字符顺序(逻辑)与它们显示的顺序(可视)是不同的.Unicode 定义了它其中每个字符的方向属性,浏览器应用的一组规则(通过这个来进行自动判断文本Unicode方向属性应该使用哪种方向)在显示时产生正确的顺序由Unicode双向算法进行描述,也可以简称为“bidi算法”.

Unicode 方向属性包含三种类型:强字符、弱字符和中性字符.在这三种主要类型下面还有很多细小的属性分类.大部分的字符都属于强字符,比如英文字母、汉字和阿拉伯字母.它们的方向性是确定的,从左到右或者从右到左,和其上下文的bidi属性无关.并且,强字符在bidi算法中可能会影响其前后字符的方向性.中性字符的方向性是不确定的,由上下文的bidi属性来决定其方向,比如大部分的标点符号和空格.有意思的是弱字符的特性,它们的方向是确定的,但对其前后字符的方向性并不会产生影响.数字和数字相关的一些符号就属于弱字符.

方向性 相关字符 效果
Left-to-Right (LTR) 强字符从左至右(英文字母、汉子以及世界上大部分左->右书写的文字) 方向性确定,LTR 或 RTL,和上下文无关.并且可能会影响其前后字符的方向性.
Right-to-Left (RTL) 强字符从右至左(阿拉伯文字、希伯来文字以及右->左书写的文字) 同上
Left-to-Right (LTR) / Right-to-Left (RTL) 弱字符(数字和数字相关的符号) 和强字符一样方向性也是确定的,但是不会影响前后字符的方向性.
Neutral 中性字符(大部分标点符号和空格) 方向性不确定,由上下文环境决定其方向

这个表格至关重要,涉及到后面所讲的所有知识点.

全局方向

也可以称为基础方向.全局方向是一个文本中的总体方向,文本在页面上显示方向运行的顺序取决于主要的全局方向,确定一个文本的全局方向主要靠以下几点:

  • 默认从文档(HTML)的左->右继承.
  • 如果有相关的dir属性或者direction样式,则根据相应的值指定方向.
<p>ولدت quietboy 12 34 56 ولدت</p>
<p dir="rtl">ولدت 12 34 56 ولدت</p>

ولدت quietboy 12 34 56 ولدت

ولدت 12 34 56 ولدت

方向串

方向串是指在一段文字中具有相同方向性的连续字符,这是由于bidi算法产生具有相同方向性的每个连续字符序列的单独方向运行,并且其前后没有相同方向性的其它方向串.

听起来可能很绕,下面看一个例子:

<p>ولدت (+86)138-3456-1000</p>
<p dir="ltr">ولدت (+86)138-3456-1000</p>
<p dir="rtl">ولدت (+86)138-3456-1000</p>

ولدت (+86)138-3456-1000

ولدت (+86)138-3456-1000

ولدت (+86)138-3456-1000

手机号并不是故意反着输入,而是输入完成后最后再后面加了一个阿拉伯文字就变成这样的,正确的手机号是(+86)138-3456-1000.

由于文中有包含阿拉伯文字(强类型RTL),因此整个文本中的全局方向为右->左(即使手动设置了全局方向dirltr,也无法覆盖被强字符影响的中性字符).

弱类型的数字保持了自己本来的方向,而中性类型的字符()-+跟随了全局方向(首个强类型文字方向给出的).

方向串

上面文本被分为7个方向串,由于中性符号被全局方向影响,使得原本号码被拆分成不同方向串,被重新排序.为此Unicode 标准中定义了一系列方向性控制字符,这些字符在界面上并不会显示.比如U+202E,可以强制文本右->左:

<p>‮welcome to my quietboy blog.‬</p>
<p>welcome to my ‮quietboy‬ blog.</p>
<!-- U+202E 使它之后的所有方向串的方向被强制定向为 右->左 -->

‮welcome to my quietboy blog.‬

welcome to my ‮quietboy‬ blog.

但是为何上面代码块能显示这些控制字符呢?这是因为我所使用的markdown编译器自动帮我将所有的#转义成了Unicode中的&来替换,你可以打开控制台选中代码块,右击选择Edit as HTML就能看到它.

如何使用?

大部分情况,Unicode 双向算法能根据字符属性和全局方向等信息运算并正确地显示双向文字,这是该算法的隐性模式.在这种模式下,双向文字的显示方式基本上由算法完成,不需要人为的干预.但是,隐性模式的算法在处理复杂情况的双向文字时会显得不足,这时就可以使用显性模式来进行补充.在显性模式的算法中,除了隐性算法的运算外,可以在双向文字中加入关于方向的 Unicode 控制字符来控制文字的显示.这些被加入文字中的 Unicode 控制字符在显示界面上是不可见的,也不占用任何显示空间.它们只是在默默地影响着双向文字的显示.

下面列举了常用的一些控制字符:

名称 方向 Unicode Code HTML Code 模式
Left-To-Right Mark(LRM) 左->右 U+200E (实体是) 隐性
Right-To-Left Mark(RLM) 右->左 U+200F (实体是) 隐性
Left-To-Right Embedding(LRE) 左->右 U+202A ordir ="ltr" 显性
Right-To-Left Embedding(RLE) 右->左 U+202B ordir ="rtl" 显性
Left-To-Right Override(LRO) 左->右 U+202D or<bdo dir ="ltr"> 显性
Right-To-Left Override(RLO) 右->左 U+202E or<bdo dir ="rtl"> 显性
Left-To-Right Isolate(LRI) 左->右 U+2066 or<bdi dir ="ltr"> 显性
Right-To-Left Isolate(RLI) 右->左 U+2067 or<bdi dir ="rtl"> 显性
First Strong Isolate(FSI) U+2068 ordir ="auto" 显性
Pop Directional Formatting(PDF) 结束标记 U+202C or</bdo> 显性
Pop Directional Isolate(PDI) 结束标记 U+2069 or</bdi> 显性

显性,隐性字符都不会显示出来,他们的区别如下:

隐性

当使用实体时必须成对使用,LRM为从左到右的强字符,而RLM为从右到左的强字符,使用他们可以影响被包裹起来的中性字符方向,达到控制方向串的目的.

我们可以使用隐性字符包裹住下面中性字符()+-,使他们的方向为左->右,让手机号正确显示.

<!-- 使用实体 -->
<p>ولدت ‎(+‎86‎)‎138‎-‎3456‎-‎1000</p>
<p>ولدت ‎(+86)138-3456-1000‎</p>

<!-- 更常规的做法是使用一个内联元素区分开强字符并设置中性字符的方向 -->
<p>ولدت <span dir="ltr">(+86)138-3456-1000</span></p>
<p><span dir="ltr">ولدت</span> (+86)138-3456-1000</p>

<!-- bdi标签能隔离外面的方向,默认值为auto,自动判断文本应该使用哪种方向 -->
<p>ولدت <bdi dir="auto">(+86)138-3456-1000</bdi></p>
<p><bdi dir="auto">ولدت</bdi> (+86)138-3456-1000</p>

ولدت ‎(+‎86‎)‎138‎-‎3456‎-‎1000

ولدت ‎(+86)138-3456-1000‎

ولدت (+86)138-3456-1000 ولدت (+86)138-3456-1000 ولدت <bdi>(+86)138-3456-1000</bdi> <bdi>ولدت</bdi> (+86)138-3456-1000

不管使用上面哪种方式,你都可以正确的设置他们的全局方向,当然除了实体外,其它的都是一些web中常用的方法使用例子.

显性

需要成对使用,开始字符为它们自己的HTML Code,结束字符中RLE,LRE,RLO,LROPDF,而RLI,LRI,FSIPDI

<!-- 使用LRE, LRO将阿拉伯字符改成 左->右 -->
<p dir="ltr">‪ولدت‬ (+86)138-3456-1000</p>
<p dir="ltr">‭ولدت‬ (+86)138-3456-1000</p>

你会发现上面的代码显示到非常奇怪,根本没有将阿拉伯字符包裹起来,其实这是处理后的样子,真实的样子是在我的源文件里,我试着很多方法都没能让他在上面那段代码里显示正常,甚至你打开控制台看这段代码也是一样的,因此我只能截图如下:

真实的样子

是带有Override的替换符,强制文字使用全局方向,因此整个阿拉伯字母被转换为左->右方向,下面这段就是浏览器显示的效果:

‪ولدت‬ (+86)138-3456-1000

‭ولدت‬ (+86)138-3456-1000

需要注意的是,我们应该尽量避免使用这些Unicode控制符,应该使用能产生相同结果的HTML标签,具体可以看我这篇文章css3中的unicode-bidi与direction使用.只有当某些特定的情况下才能使用这些控制符,比如title标签以及标签的一些属性值.

引用

原文链接:https://www.quietboy.net/posts/uniocde-控制字符

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-42537.html

文章标题:Unicode 控制字符及其有关的双向算法

相关文章
12个你未必知道的CSS小知识
虽然CSS并不是一种很复杂的技术,但就算你是一个使用CSS多年的高手,仍然会有很多CSS用法/属性/属性值你从来没使用过,甚至从来没听说过。 1.CSS的color属性并非只能用于文本显示 对于CSS的color属性,相信所有Web开发人员...
2015-11-12
ajax为什么令人惊异?ajax的优缺点
使用Ajax的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变的信息。 Ajax不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。就像DHT...
2015-11-12
HTML5的5个不错的开发工具推荐
HTML5规范终于在今年正式定稿,对于从事多年HTML5开发的人员来说绝对是一个重大新闻。数字天堂董事长,DCloud CEO王安也发表了文章,从开发者和用户两个角度分析了HTML对两个人群的优势。其实,关于HTML5的开发工具,我们以往的...
2015-11-12
JavaScript教程:JS中的原型
Keith Peters 几年前发表的一篇博文,关于学习没有“new”的世界,其中解释了使用原型继承代替构造函数。两者都是纯粹的原型编码。 标准方法(The Standard Way) 一直以来,我们学习的在 JavaScript 里创建对...
2015-11-12
AJAX的浏览器支持
AJAX 的要点是 XMLHttpRequest 对象。 不同的浏览器创建 XMLHttpRequest 对象的方法是有差异的。 IE 浏览器使用 ActiveXObject,而其他的浏览器使用名为 XMLHttpRequest 的 Jav...
2015-11-12
Riot.js:不足1KB的MVP客户端框架
Riot.js是一款MVP(模型-视图-呈现)开源客户端框架,其最大的特点就是体积非常小,不足1KB,虽然体积小,但它可以帮助用户构建大规模的Web应用程序。 Riot.js是由Moot公司开发,目前最新版本为v0.9.2,遵循MIT开源许...
2016-03-11
JavaScript的组成
一个完整的JavaScript由3个部分组成:核心(ECMAScript) 文档对象模型(DOM) 浏览器对象模型(BOM) ECMAScript 描述了该语言的语法和基本对象 ; DOM 描述了处理网页内容的方法和接口 ; BOM 描...
2015-11-12
typeof、instanceof和contructor的区别
typeof:以字符串的形式返回变量的原始类型,typeof在两种情况下会返回&quot;undefined&quot;:一个变量没有被声明的时候,和一个变量的值是undefined的时候,注意,typeof null也会返回object,...
2015-11-12
必须记住的 30 类 CSS 选择器
开篇 有 30 个 CSS 选择器你必须烂熟于心,它们适应于当今各大主流浏览器。 1.* * { margin: 0; padding: 0; } *选择器选择的是每一个单一元素。很多程序员用上面的 CSS 将所有元素的 ma...
2015-11-16
JavaScript变量的声明
声明变量 变量在脚本中的首次亮相是在其声明中。 在变量首次出现时将会在内存中设置它,因此您稍后可在脚本中引用它。 应在使用变量之前先声明变量。 可以使用 var 关键字实现此目的。 &lt;span id=“mt9” class=“sent...
2015-11-12
回到顶部