注:本翻譯使用符號「」來突出某些可能會產生歧義的名詞。
目前狀態:勘誤中。
Unicode?標準附錄#9
UNICODE雙向算法#####
版本 | Unicode 8.0.0 |
編者 | Mark Davis, Aharon Lanin, and Andrew Glass |
日期 | 2015-05-29 |
當前版本 | http://www.unicode.org/reports/tr9/tr9-33.html |
當前版本 | http://www.unicode.org/reports/tr9/tr9-31.html |
以前版本 | http://www.unicode.org/reports/tr9/tr9-31.html |
最新版本 | http://www.unicode.org/reports/tr9/ |
提出的更新 | http://www.unicode.org/reports/tr9/proposed.html |
修正 | 33 |
目錄#####
├ 1 引言
├ 2 定向格式化字符
│├ 2.1 顯式定向嵌入
│├ 2.2 顯式定向重寫
│├ 2.3 終止顯式定向嵌入和重寫
│├ 2.4 顯式定向隔離
│├ 2.5 終止顯式定向隔離
│├ 2.6 隱式定向標記
│└ 2.7 標記和格式化字符
├ 3 基本顯示算法
│├ 3.1 定義
││├ 3.1.1 基礎:BD1,BD2,BD3,BD4,BD5,BD6,BD7
││├ 3.1.2 匹配顯式定向格式化字符:BD8,BD9,BD10,
│││ BD11,BD12,BD13
││├ 3.1.3 成對括號:BD14,BD15,BD16
││└ 3.1.4 其他縮略語縮略語翻譯
│├ 3.2 雙向字符類型
│├ 3.3 解析嵌入層次level是層次還是等級?
││├ 3.3.1 分段層次: P1,P2,P3
││├ 3.3.2 顯式層次和方向:X1,X2,X3,X4,X5,X5A,
│││ X5b,X5c,X6,X6A,X7,X8
││├ 3.3.3 隱式處理的準備: X9,X10
││├ 3.3.4 分析弱類型: W1,W2,W3,W4,W5,W6,W7
││├ 3.3.5 分析中性類型和隔離格式化類型: N0,N1,N2隔離格式化?
││└ 3.3.6 分析隱式層次:I1,I2
│├ 3.4 分析重排序層次: L1,L2,L3,L4
│└ 3.5 成型定型?翻譯
├ 4 雙向一致性
│├ 4.1 中性邊界
│├ 4.2 顯式格式化字符
│├ 4.3 高層協議:HL1,HL2,HL3,HL4,HL5,HL6高等級協議
│└ 4.4 雙向一致性測試
├ 5 實現說明
│├ 5.1 參考代碼
│└ 5.2 保留的BN和顯式格式化字符保留還是確定
├ 6 用法
│├ 6.1 結合
│├ 6.2 豎排文本
│├ 6.3 格式化
│├ 6.4 分離標點符號
│└ 6.5 轉換為純文本
├ 7 鏡像
├ 遷移問題
│└部分重組
├ 致謝
├ 參考
└ 修改
3.3.3 隱式處理的準備
通過之前的規則,顯式嵌入水平已被分配給字符,在字符的隱式雙向類型的基礎上,顯式嵌入將作進一步調整。對于一個給定字符的調整,將依賴于它周圍的字符。然而,這種依賴性會被如下規則界定: 在邏輯上將分段分成子單元,獨立地對每個單元進行后續的隱式處理限制。
X9. 移除所有的RLE,LRE,RLO,LRO,PDF和BN字符。
注意:這個實現并沒有真正刪除那些字符,只是在后面的算法中,字符表現得不存在一樣。只要其他字符正確排序,一致性不對字符作特殊的規定。
參閱章節5,執行注釋,有關執行該算法而不需要刪除格式化字符的資料。
零寬度連接器(zero width joiner)和非連接器(non-joiner)影響相鄰字符(即使這些字符在雙向算法中重排序后可能變得不相鄰,字符在最初存儲器中的順序相鄰即可)的成型,具體可參閱章節6.1,連接符。
注意:FSI,LRI,RLI和PDI 字符沒有被移除。正如下列規則指出的,在某種程度上,它們被用于確定分段的隔離運行序列,其中,它們會被看作是中性字符。當然,它們是像LRM和RLM這類的零寬度字符,在最后輸出中不可見。
X10. 執行以下步驟:
按BD13指定的計算隔離運行序列的集合,基于字符的雙向類型和上面規則(X1-X9)賦值的嵌入等級。
對每個隔離運行序列,確定分段的起點(start-of-sequence,簡稱sos)和分段的終點(end-of-sequence,簡稱eos)類型,L或R其中之一。這取決于在序列邊界兩側的兩個等級更高的那個:
對于sos,序列中第一個字符的等級與分段內sos前面的字符(不包括被X9移除的字符)等級比較,如果找不到sos前面的字符,則是與分段嵌入等級比較。
對于eos,序列中最后字符的等級與分段內soe后面的字符(不包括被X9移除的字符)等級比較,如果找不到soe后面的字符或序列的最后字符是隔離啟動器(缺少一個匹配的PDI),則是與分段嵌入等級比較。
如果最高的級別是奇數,sos或eos是R,否則是L。
注意這個計算必須用到上面規則所賦值的嵌入等級,下面的步驟執行產生的變化。
應用規則W1-W7,N0-N2和I1-I2,對每個隔離運行序列,按照序列出現的順序,對序列中的所有字符,按照字符在序列中的順序,且對序列的任意部分應用其他規則之前,應用一條規則。對每個隔離運行序列順序的處理都很類似。當對一個隔離運行序列應用一條規則時,隔離運行序列中每個運行等級的最后一個字符均被看作字符的后面會緊接著序列中下一運行等級的第一個字符(無論是否存在這個字符)。
這里有幾個例子,其中每個texti被假定為是一個基礎等級為0和內部無字符序列的分段,texti包含了顯式定向格式化字符或分段分隔符。例子中的點號是為了視覺清晰把元素分開,它們不是文本的一部分。
例1:
text1·RLE·text2·LRE·text3·PDF·text4·PDF·RLE·text5·PDF·text6
隔離運行序列 | 嵌入等級 | sos | eos |
---|---|---|---|
text1 | 0 | L | R |
text2 | 1 | R | L |
text3 | 2 | L | L |
text4·text5 | 1 | L | R |
text6 | 0 | R | L |
例2: text1·RLI·text2·LRI·text3·PDI·text4·PDI·RLI·text5·PDI·text6
隔離運行序列 | 嵌入等級 | sos | eos |
---|---|---|---|
text1·RLI·PDI·RLI·PDI·text6 | 0 | L | L |
text2·LRI·PDI·text4 | 1 | R | R |
text3 | 2 | L | L |
text5 | 1 | R | R |
例3: text1·RLE·text2·LRI·text3·RLE·text4·PDI·text5·PDF·text6
隔離運行序列 | 嵌入等級 | sos | eos |
---|---|---|---|
text1 | 0 | L | R |
text2·LRI·PDI·text5 | 1 | R | R |
text3 | 2 | L | R |
text4 | 3 | R | R |
text6 | 0 | R | L |
3.3.4 解析弱類型
首先,每個無間距標記(nonspacing mark,簡稱NSM)的解析是基于它后面的字符。
W1.在每個隔離運行序列中檢查每個NSM,如果前一個字符是隔離啟動器或PDI,將NSM的類型更改為其他中性的,否則類型更改為與前一個字符相同。如果NSM是隔離運行序列的第一個字符,NSM的類型將是sos。(注意,在一個隔離運行序列中,一個隔離啟動器后面是一個NSM或任何非PDI類型,那么這個隔離啟動器就是一個溢出隔離啟動器。)
這個例子中,假設SOS是R:<pre><b>AL NSM NSM → AL AL AL
sos NSM → sos R
LRI NSM → LRI ON
PDI NSM → PDI ON</b></pre>下一步是解析數字。這階段會將雙向類型歐洲數字分隔符、歐洲數字終止符和普通數字分隔符變更為歐洲數字文本,或者其他中性文本。對于已經被掃描的文本,它的類型可能已經被定向重寫改變。如果是這樣,那么就不會解析為數字。
W2.從每個歐洲數字的實例反向搜索直到找到第一個強類型(R,L或sos)。如果找到AL,將歐洲數字的類型變更為阿拉伯數字。<pre><b>AL EN → AL AN
AL NI EN → AL NI AN
sos NI EN → sos NI EN
L NI EN → L NI EN
R NI EN → R NI EN</b></pre>W3.強所有AL類型變更為R。
W4.在兩個歐洲數字之間的唯一的歐洲數字分隔符變更為歐洲數字。兩個同一類型的數字之間的唯一普通分隔符變更為該類型。<pre>EN ES EN → EN EN EN
EN CS EN → EN EN EN
AN CS AN → AN AN AN</pre>W5.與歐洲數字相鄰的歐洲數字分隔符變更為歐洲數字。<pre>
ET ET EN → EN EN EN
EN ET ET → EN EN EN
AN ET EN → AN EN EN
</pre>W6.否則,分隔符和終止符變更為其他中性類型。<pre>AN ET → AN ON
L ES EN → L ON EN
EN CS AN → EN ON AN
ET AN → ON AN</pre>W7.從每個歐洲數字開始,反向搜索直到找到第一個強類型(R,L或sos)。如果找到L,則將歐洲數字的類型變更為L。<pre>L NI EN → L NI L
R NI EN → R NI EN</pre>3.3.5 解析中性類型和隔離格式化類型
在下一階段,在一個隔離運行序列中,進行一次中性和隔離格式化(即 NI)字符的解析。這將導致所有NI變更為R或L。一般來說,NI類型由其周圍的文本決定。萬一發生沖突,NI類型由定向嵌入決定。 At isolating run sequence boundaries where the type of the character on the other side of the boundary is required, the type assigned to sos or eos is used.在隔離運行序列中的一對括號被當作單元來處理,這樣開括號和閉括號均被解析為同一方向。注意這條規則是基于每對括號的當前定向字符類型而不是原始類型,同時這可能在規則X6下發生了改變。The current bidirectional character type may also have changed under a previous iteration of the for loop in N0 in the case of nested bracket pairs.
N0.
使用下面給出的邏輯處理在開括號的文本位置的邏輯順序的一個隔離運行序列中的對括號。在范圍內,雙向類型EN和AN看作R。
根據BD16,識別在當前隔離運行序列中的對括號
對于每個在文本位置的列表中的每個對括號元素:
a.檢查在對括號內所包含的字符的雙向類型。
b.如果發現任何匹配了嵌入方向的強類型(L或R),將對括號的類型設置為嵌入方向。<pre>o [ e ] o → o e e e o
o [ o e ] → o e o e e
o [ NI e ] → o e NI e e</pre>c.否則,如果這里有一個強類型,它必須是與嵌入方向相反。因此,帶著上述的強類型,測試一個確定的上下文,通過在開括號的前面開始反向檢查,直到發現第一個強類型(L,R或sos)。
1.如果上述的強類型也是與嵌入方向相反,上下文被確定,因此,將對括號設置成該方向。<pre>o [ o ] e → o o o o e
o [ o NI ] o → o o o NI o o</pre>2.否則將對括號設置成嵌入方向。<pre>e [ o ] o → e e o e o
e [ o ] e → e e o e e</pre>d.否則,在對括號里沒有強類型。因此,對括號不設置類型。<pre>e ( NI ) o → e ( NI ) o</pre>注意,如果封閉的文本里沒有強字符,括號會逐一使用規則N1和N2來解析到相同的等級。
無論有多少個字符,只要字符含有原始雙向字符類型NSM,該NSM優先應用規則W1,且NSM后面緊跟在規則N0下變更為L或R對括號,那么字符應該變更為匹配它們之前括號的類型。
例1.從邏輯順序的開括號位置開始,依次解析對括號。
(RTL分段方向)
Storage | AB | ( | CD | [ | & | ef | ] | ! | ) | gh |
Bidi_Class | R | ON | R | ON | ON | L | ON | ON | ON | L |
N0 applied (first pair) | N0b: ON→R | N0b: ON→R | ||||||||
N0 applied (second pair) | N0c2: ON→R | N0c2: ON→R | ||||||||
Display | gh(![ef&]DC)BA |
例2.括號對內包含混合強類型則選取分段方向。
(RTL分段方向)
Storage | smith | ( | fabrikam | ARABIC | ) | HEBREW | |||
Bidi_Class | L | WS | ON | L | WS | R | ON | WS | R |
N0 applied | N0b: ON→R | N0b: ON→R | |||||||
Display | WERBEH (CIBARA fabrikam) smith |
注意,在上面例子中,如果smith與HEBREW或fabrikam與ARABIC的順序調換,對括號的解析仍然不變。
例3.對括號內包含與嵌入方向相反的強類型with additional strong-type context,選取與嵌入方向相反的方向。
(RTL分段方向)
||||||||
|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|
|Storage|ARABIC||book|(|s|)|
|Bidi_Class|R|WS|L|ON|L|ON|
|N0 applied||||N0c1: ON→L||N0c1: ON→L|
|Display|book(s) CIBARA||||||
N1.如果NI兩邊的文本具有相同的方向,那么NI選取周圍的強文本方向。在對NI的影響方面,歐洲數字和阿拉伯數字表現得像R類型一樣。sos和eos類型用于隔離運行序列邊界上。<pre> L NI L → L L L
R NI R → R R R
R NI AN → R R AN
R NI EN → R R EN
AN NI R → AN R R
AN NI AN → AN R AN
AN NI EN → AN R EN
EN NI R → EN R R
EN NI AN → EN R AN
EN NI EN → EN R EN</pre>
N2.剩下的NI選取嵌入方向。<pre>NI → e</pre>對于給定的NI字符的嵌入方向,是來源于它的嵌入等級:如果字符被設置偶數等級,則為L,如果是奇數等級,則為R。(參閱BD3.)
在以下例子中,假定eos是L類型,sos是R類型。應用N1和N2后如下:<pre>L NI eos → L L eos
R NI eos → R e eos
sos NI L → sos e L
sos NI R → sos R R</pre>
一列數字被中性字符隔開和嵌入在定向運行中,它會出現在運行的順序中。<pre>Storage: he said "THE VALUES ARE 123, 456, 789, OK".
Display: he said "KO ,789 ,456 ,123 ERA SEULAV EHT".</pre>
在這個例子中,逗號和空格均在數字之間,它們忽略數字并獲取周圍文本的方向(大寫字符即right-to-left)。逗號不用考慮數字部分,因為它們的兩側不是被數字包圍(參閱章節3.3.4,解析弱類型)。然而,如果前面有一個left-to-right序列,歐洲數字會采取如下方向:<pre>Storage: IT IS A bmw 500, OK.
Display: .KO ,bmw 500 A SI TI</pre>
3.3.6 解析隱式層次
在最后階段,基于已被解析的字符類型,文本的嵌入等級可能增加。Right-to-left文本總是以奇數等級結束,left-to-right和中性的文本總是以偶數等級結束。此外,數字的文本總是以比分段等級高的等級結束。(注意,在這過程中,文本以max_depth+1等級結束是可能的。)這將導致以下規則:
I1.對于所有在偶數(left-to-right)嵌入等級的字符,那些類型為R的提升一個等級,那些類型為AN或EN的提升兩個等級。
I2.對于所有在奇數(right-to-left)嵌入等級的字符,那些類型為L,EN或AN的提升一個級別。
表格5歸納了隱式算法的結果。
|類型|嵌入水平|嵌入水平|
|:--|:--|:--|:--|:--|
||偶數|奇數|
|L|EL|EL+1|
|R|EL+1|EL|
|AN|EL+2|EL+1|
|EN|EL+2|EL+1|
3.4 重排序已被解析的等級
以下規則描述了尋找正確的顯示順序的邏輯過程。相對于解析階段,these rules act on a per-line basis and are applied after any line wrapping is applied to the paragraph.
邏輯上有以下幾個步驟:
文本等級由前面的規則確定。
字符根據它們的上下文(對鏡像考慮嵌入等級)成型。
這些字形(按邏輯順序)的累計寬度被用與確定換行。
對于每一行,規則L1-L4被用于重排序該行上的字符。
對應行中字符的字形的顯示。
L1.在每一行中,將以下字符的嵌入等級重置成分段嵌入等級:
1.段分隔符,
2.分段分隔符,
3.任何在段分隔符或分段分隔符前面的空白字符和/或隔離格式化字符(FSI,LRI,RLI和PDI)序列,和
4.任何在行的結尾的空白字符和/或隔離格式化字符(FSI,LRI,RLI和PDI)序列。
這里所使用的字符類型是原始類型,不是被以前階段修改過的類型。
因為分段分隔符會中斷行,在每行中最多有一個在該行的結尾。
結合以下規則,這意味著尾隨的空白字符將出現該行的視覺結束位置(分段方向)。分段中的制表符總有一個連貫的方向。
L2.在文本中發現的最高等級到每行中最低的奇數等級,包括中間等級,這些等級實際上并不存在于文本中,顛倒字符在該等級或更高的所有相鄰序列
這條規則反向逐步增大的子串。
以下例子說明重排序,展示應用規則L2的連續步驟。原始文本展示在表格里行“存儲器(Storage)”中。無形的,零寬度格式化字符LRI,RLI和PDI分別使用>,<,=號來代替。章節3.3,解析嵌入等級和規則L1的應用所生成的已被解析等級展示在行“已被解析等級(Resolved Levels)”中。(由于這些例子只是利用隔離格式化字符,規則X9不會移除任何字符。注意,如果使用嵌入來替代,例3將不起作用,因為兩個right-to-left短語會連同中性標點合并成一個right-to-left運行。)。此后,每一個連續的行按規則L2展示一遍逆轉,例如“反向等級1-2”.在每次反向中,下劃線表示該段文本已經被反向。
例1,例2,例3的分段嵌入等級為0(left-to-right方向),例4為1(right-to-left方向)。
例1.(嵌入等級=0)<pre><b>Storage: car means CAR.
Resolved levels: 00000000001110
Reverse level 1: car means <u>RAC</u>.
Display: car means RAC</b></pre>
例2.(嵌入等級=0)<pre><b>
Storage: <car MEANS CAR.=
Resolved levels: 0222111111111110
Reverse level 2: <<u>rac</u> MEANS CAR.=
Reverse levels 1-2: <<u>.RAC SNAEM car</u>=
Display: .RAC SNAEM car
</b></pre>
例3.(嵌入等級=0)<pre><b>
Storage: he said “<car MEANS CAR=.” “<IT DOES=,” she agreed.
Resolved levels: 000000000022211111111110000001111111000000000000000
Reverse level 2: he said “<<u>rac</u> MEANS CAR=.” “<IT DOES=,” she agreed.
Reverse levels 1-2: he said “<<u>RAC SNAEM car</u>=.” “<<u>SEOD TI</u>=,” she agreed.
Display: he said “RAC SNAEM car.” “SEOD TI,” she agreed.
</b></pre>
例4.(嵌入等級=1)<pre><b>
Storage: DID YOU SAY ’>he said “<car MEANS CAR=”=‘?
Resolved levels: 111111111111112222222222444333333333322111
Reverse level 4: DID YOU SAY ’>he said “<rac MEANS CAR=”=‘?
Reverse levels 3-4: DID YOU SAY ’>he said “<RAC SNAEM car=”=‘?
Reverse levels 2-4: DID YOU SAY ’>”=rac MEANS CAR<“ dias eh=‘?
Reverse levels 1-4: ?‘=he said “<RAC SNAEM car=”>’ YAS UOY DID
Display: ?‘he said “RAC SNAEM car”’ YAS UOY DID
</b></pre>
L3.在這點上,應用在right-toleft基本字符(base character)的組合標記(Combining marks)優于它們的基本字符。如果渲染引擎希望它們在最后展示流程中跟隨基本字符,則標記的順序和基本字符必須顛倒。Many font designers provide default metrics for combining marks that support rendering by simple overhang. Because of the reordering for right-to-left characters, it is common practice to make the glyphs for most combining characters overhang to the left (thus assuming the characters will be applied to left-to-right base characters) and make the glyphs for combining characters in right-to-left scripts overhang to the right (thus assuming that the characters will be applied to right-to-left base characters). With such fonts, the display ordering of the marks and base glyphs may need to be adjusted when combining marks are applied to “unmatching” base characters. See Section 5.13, Rendering Nonspacing Marks of [Unicode], for more information.
L4.當且僅當已被解析的字符方向是R、字符的Bidi_Mirrored屬性值是Yes時,該字符由一個鏡像字形描述。
BIdi_Mirrored屬性在[Unicode]的章節4.7,Bidi Mirrored中定義;屬性值在[UCD]中詳細說明。
這條規則可以在某些情況下被覆蓋;參閱HL6.
例如,U+0028左圓括號(LEFT PARENTHESIS),它在Unicode Standard中翻譯為開放的圓括號,當它解析后的等級為偶數,顯示為“(”,當它解析后的等級為奇數,顯示為“)”。注意,為了向后兼容字符U+FD3E“?”裝飾的左括號(ORNATE LEFT PARENTHESIS)和U+FD3F“?”裝飾的右括號(ORNATE RIGHT PARENTHESIS,它們沒有鏡像。
3.5 成型
手寫連接的語言,例如阿拉伯語或敘利亞語,需要選擇位置的字符形狀,會依賴于鄰近的字符(參閱[Unicode]的章節8.2,Arabic)。在雙向算法的規則I2后應用成型,成型受到相同運行等級內的字符限制。(注意,限制的整形對一個運行等級和一個隔離運行序列沒有實際的差異,是因為隔離啟動器和PDI字符被定義去加入類型U,即非鏈接(non-joining)。因此,定向隔離前后的字符不會連接隔離,即使隔離是空的或溢出深度限制。)參考以下例子,阿拉伯字符串,在內存中作為字符1,2,3和4表示,并且其中前兩個字符是LTR方形的重寫。同時顯示分段方向,后兩個字符是RTL方向的嵌入。
|1|2|3|4|
|:--:|:--:|:--:|:--:|:--:|
|<b>?</b>|<b>?</b>|<b>?</b>|<b>?</b>|
|062C|0639|0644|0645|
|JEEM|AIN|LAM|MEEM|
|L|L|R|R|
在HTML中的文本或使用,
在純文本中使用顯式定向格式化字符,或者在HTML中使用標記,均可達到這個效果,例子如下。(粗體文本是right-to-left的分段方向。)
LRM/RLM LRO JEEM AIN PDF RLO LAM MEEM PDF
<p dir="ltr"/"rtl">LRO JEEM AIN PDF RLO LAM MEEM PDF</p>
<p dir="ltr"/"rtl"><bdo dir="ltr">JEEM AIN</bdo>
<bdo dir="rtl">LAM MEEM</bdo></p>
根據分段方向,所得的形狀如下:
Left-Right Paragraph
|||||
|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|
|1|2|4|3|
|<b>?</b>|<b>?</b>|<b>?</b>|<b>?</b>|
|JEEM-F|AIN-I|MEEM-F|LAM-I|
Right-Left Paragraph
|||||
|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|:--|
|4|3|1|2|
|<b>?</b>|<b>?</b>|<b>?</b>|<b>?</b>|
|MEEM-F|LAM-I|JEEM-F|AIN-I|
3.5.1 成型和斷行
將分段分成符合特定邊界的一行或多行的過程超出了雙向算法的范圍。當字符成型參與時,寬度計算必須基于字形的形狀。
注意,軟連字符(soft-hyphen,簡稱SHY)插入到手寫連接語言時與插入到其他語言一樣。也就是說,它指出了一點,在該點上單詞的中間可以中斷該行。如果渲染系統在該點上中斷,對于給定的語言,顯示(包括成型)應該是恰當的。關于這些和其他斷行問題的更多信息,見附件# Unicode標準14,“斷行特性”[UAX14]。
雙向一致性
雙向算法指定部分right-to-left字符的內在語義,因此需要與Unicode Standard中顯示的任何字符保持一致性。
與本規范保持一致性的過程應滿足下列條款:
UAX9-C1.在沒有允許的更高級別的協議下,渲染文本的過程應該在順序描述中顯示出所有列出的可見的字符(不包括格式化字符),參閱章節3,Basic Display Algorithm。此外,這包括定義BD1-BD16和步驟P1-P3,X1-X10,W1-W7,N0-N2,I1-I2,和L1-L4。
如同所有其他的Unicode算法,只要他們產生相同的結果,這一邏輯描述在特定實現下可以有更高效的機制。參[Unicode]第三章Conformance,注意事項如下。
UAX9-C2.唯一允許更高級別的協議在4.3節,Higher-Level Protocols中列出。他們是HL1、HL2、3,4,5,和HL6。
注意:不鼓勵使用更高級別的協議是因為它引入了交換問題,并可能導致安全問題。有關更多信息,參見Unicode的技術報告# 36、“Unicode Security Considerations”[UTR36]。
4.1 中性邊界
標記一個格式化字符或控制字符為BN的目的它對算法的其余部分不產生影響。(ZWJ和ZWNJ是例外;參閱X9)。相對于其它字符,一致性并不要求對格式化字符進行精確地排序,只要它們保留其他字符的順序時,可以用不同的方式來處理它們。
4.2 顯式格式化字符
就Unicode字符來說,系統不必支持所有的顯式定向格式化字符(雖然一般只含有一個終止字符而不含啟動器是沒用的)。
一般情況下,一致性系統將分為四類:
無雙向性格式化。這意味著系統并不能直觀地解釋right-to-left語言的字符。
隱式雙向性。這意味著支持雙向算法和定向標記ALM,RLM和LRM。
無隔離雙向性。這意味著支持雙向算法,隱式定向標記,顯式非隔離定向格式化字符ALM,RLM,LRM,LRE,RLE,LRO,RLO,PDF。
完整的雙向性。這意味著支持雙向算法,隱式定向標記,顯式定向格式化字符ALM,RLM,LRM,LRE,RLE,LRO,RLO,PDF,FSI,LRI,RLI,PDI。
4.3 高級協議
下列條款是系統對雙向文本的排序,應用更高級別的協議唯一允許的方式。部分條款適用于結構化文本段。這指的是文本被解析為結構化時,無論是帶有顯式標記的例如XML或HTML,或是不帶顯式標記的內部結構化如文字處理器或電子表格。在這種情況下,一個段的范圍是通過結構用某種方式來區分。
HL1。重寫P3,并顯式地設置分段嵌入等級。當在規則X5c中決定怎樣對待FSI時,本規則不會被應用。
更高級別的協議可能設置所有分段等級。這可以在上下文的基礎上進行,例如在一個表格單元格,分段,文檔或系統等級。(如果P3被重寫,P2可能會被跳過)。注意,這不允許更高級別的協議來重寫BD2中指定的限制。
一個更高級別的協議可能應用相當于P2和P3的規則,但默認為1級(RTL)而不是0級(LTR),以適應整體的RTL環境。
更高級別的協議可能會使用完全不同的算法,基于分段文本和內容上,啟發式地自動檢測分段嵌入等級。例如,它可以將它基于是否在文本中RTL字符比LTR多。作為另一個例子,當分段不含有強字符,其方向可以由分段之前或之后的等級確定。
HL2.重寫W2,顯式地設置EN或AN。
更高級別的協議可能將字符的EN類型重置為AN類型,反之亦然,并忽略W2。例如,樣式表或標記信息可以用在文本范圍內,來將設置為EN的文本重寫為AN,反之亦然。
HL3。模擬顯式定向格式化字符。
更高級別的協議可以對在結構化段落施加定向嵌入,隔離和重寫的作用。該行為必須通過參考,如果同等的在算法中定義的顯式定向格式化字符被插入到文本會發生什么來定義。例如,樣式表或標記信息可以修改文本范圍內的嵌入等級。
HL4。對段落應用雙向算法。
雙向算法可以被單獨地應用在一個或多個結構化段落中。例如,當在編輯器中顯示一個包含文本數據和可見標記的文檔時,更高級別的協議可以從文本數據中,分別處理標記中的語法元素。
HL5。提供人為的上下文。
文本可以通過雙向算法進行處理,就好像文本的前面或后面是一個給定類型的字符。這允許從文本中的長段落提取出一片文本來表現出該片文本在更大的上下文中。
HL6。額外的鏡像。
沒有Bidi_Mirrored屬性的某些字符也可以通過在專門上下文的鏡像圖像字符描述。這些上下文包括但不限于,歷史上的語言和相關的標點,私人使用的字符和數學表達式的字符。
這些字符至少符合下列一個條件:
1.字符帶有已被解析的方向是R
2.字符帶有已被解析的方向是L,它的雙向類型是R或AL。
條款HL1和HL3是專業的應用,條款HL4和HL5更常規。它們在這里明確規定是因為它們直接對應著常用操作。
對HL4應用的一個例子,假設一個XML文檔包含以下片段。(注意,這是一個簡化的例子:元素名,屬性名和屬性值都可能參與進來。)<pre>ARABICenglishARABIC<e1 type='ab'>ARABICenglish<e2 type='cd'>english</pre>這可以被分析為五個不同的片段:<ol><li>ARABICenglishARABIC</li><li><e1 type='ab'></li><li>ARABICenglish</li><li><e2 type='cd'></li><li>english</li></ol>為了使作為源文本的XML文件可讀,在編輯器中顯示可以命令這些元素都在統一方向(例如,所有都是left-to-right)和分別對每部分應用雙向算法。它也可以選擇去命定元素名,屬性名和屬性值在同一方向上統一(例如,所有都是left-to-right)。對最終的顯示,標記可以被忽略,允許所有的文本(片段a,c和e)一起進行重排序。
4.4 雙向一致性測試
Unicode字符數據庫[UCD]包含兩個文件來為雙向算法[Tests9]的實現提供一致性測試。其中一個文件,BidiTest.txt
,
包含了雙向類型詳細的測試序列直到一個給定的長度,一般是4。另一個文件,BidiCharacterTest.txt
,包含顯式代碼點的測試序列,包括例如:括號對。每個測試文件的格式在該文件的頭部均被說明。
5 實現注意事項
5.1 參考代碼
可獲得用Java編寫雙向算法的參考實現。源代碼可以從[Code9]下載。鼓勵實施者使用這一資源來測試它們的實現。可在[Demo9]找到顯示雙向算法的結果以及嵌入等級和調用每個字符的規則的在線演示。
參考代碼被設計成遵循該算法的步驟,而沒有應用任何優化。一個有效優化的例子是僅當right-to-left字符存在時,首先測試它們并調用雙向算法。另一個優化是對匹配括號對。雙向括號對(字符的Bidi_Paired_Bracket_Type屬性值Open或Close)構成雙向類型為ON的字符的一個子集。相反,雙向類型非ON的字符的Bidi_Paired_Bracket_Type屬性為None。因此, 被 通過限制對雙向類型為ON的字符處理,可以優化查找Bidi_Paired_Bracket_Type屬性值來識別括號對的過程。
5.2 保留BN和顯式格式化字符
一些實現可能希望在算法運行時,能保留顯式定向嵌入、重寫格式字符和BN。事實上,保留這些格式化字符和BN對用戶是很重要的。例如有些用戶需要顯示隱藏字符的圖示,因此為了顯示而需要獲取格式化字符和BN。
以下描述如何通過算法的步驟來保留這些字符的具體實現。注意,本描述是信息的實施指南;它應該提供與上述顯式算法一樣的結果,但萬一與顯式算法存在偏差,顯式算法對于一致性來說更規范。
在規則X2-X5,給雙向狀態棧中最后一個條目的嵌入等級,插入一個初始步驟來設置顯式嵌入或重寫字符的嵌入等級。這適用于RLE,LRE,RLO和LRO。
在規則X6,移除BN字符外的字符。換句話說,對除了B,RLE,LRE,RLO,LRO,PDF,RLI,LRI,FSI和PDI的所有類型應用規則。
在規則X7,在所有情況下,添加最后一步來將PDF的嵌入等級設置成定向狀態棧中最后一個條目的嵌入等級。
在規則X9,不移除所有字符,但將所有RLE,LRE,RLO,LRO和PDF字符轉換成BN。
在規則X10,在確定隔離運行序列的sos和eos過程中,當尋找隔離運行序列的首字符前的字符和末字符后的字符時,跳過任何BN。
在規則W1,從每個NSM開始反向搜索直到找到隔離運行序列中首個雙向類型為非BN的字符,如果NSM是一個隔離啟動器或PDI并將NSM設置成ON,否則不變。如果NSM是第一個非BN字符,NSM的類型轉換為sos。
在規則W4,掃描越過鄰近是ES或CS的BN類型。
在規則W5,轉換所有適當的ET和BN序列,而不只是ET。
在規則W6,同樣將所有鄰近ET,ES或CS的BN類型轉換成ON。
在規則W7,掃描越過BN。
在規則N0-N2,將鄰近中性字符的BN字符看作與中性字符一樣。
在規則I1和I2,忽略BN。
在規則L1,在序列中,包括嵌入和重寫格式化字符和BN連同空格字符和隔離格式化字符,它們的等級在分隔符或換行符之前被重置。如果LRE,RLE,LRO,RLO,PDF或BN的前一個字符等級是1,則將它們的等級解析為1,否則解析為基礎等級。
6 用法
6.1 結合
正如X9中描述的,零寬度連接符和非連接符影響鄰近(指在原始儲存備份(backing-store)中的鄰近順序,即使這些字符經過雙向算法重新排列后最終變得不鄰近)字符的成型。為了確定特定字符在應用雙向算法后的連接行為,這里有兩種主要的策略:
在成型時,實現可以回查儲存備份,看是否有相鄰的ZWNJ或ZWJ字符。
另外,實現可以通過一個與相鄰字符關聯的帶外(out-of-band)字符屬性代替ZWJ和ZWNJ,這樣信息不會與雙向算法和保存在字符重新排列的信息相沖突。只要雙向算法被應用,帶外信息可以用于適當的成型。
6.2 豎排文本
在垂直方向上,雙向算法仍然用于確定文本的等級。然而,這些等級不是用來對文本重排序,因為字符通常是統一地由上至下。相反,等級是用于確定文本的旋轉。有時垂直線遵循的垂直基線,基線上每個字符方向確定且正常(非旋轉),字符排列從上到下,無論是希伯來語,數字或拉丁語。當在垂直線上,將文本設置成阿拉伯語時,更普遍的是使水平線逆時針旋轉90°,那么字符就從上到下排列。拉丁文字和拉丁數字可能順時針旋轉90°,那么字符也從上到下排列。
雙向算法也可以用于字符從下往上排列。例如,混合了阿拉伯語和拉丁符號,此時所有圖像字符順時針旋轉90°。Unicode標準不會指定文本是否水平的或垂直的,或是旋轉的。那是留給更高級別的協議。
6.3 格式化
由于隱式字符類型和對解析中性和數字的啟發式定向行為,隱式雙向排序一般會在沒有進一步工作就可以產生正確的顯示。但是,當一個right-to-left分段首字符是left-to-right時,或有不同方向文本的嵌套片段,或是弱字符在定向的邊界時,就可能會出現問題。在這些情況下,為得到正確的顯示,可能需要嵌入或定向標記。部分數字可能還需要定向重寫。
最常見的問題是中性字符在嵌入式語言的邊界。這可以通過正確設置嵌入式文本的等級來解決。例如:以下所有的文本在等級0中:
<pre>Memory: he said "I NEED WATER!", and expired.
Display: he said "RETAW DEEN I!", and expired.</pre>
如果感嘆號是阿拉伯語括號的一部分,那么用戶可以選擇文本I NEED WATER!并明確將它標記為嵌入式阿拉伯語,并產生以下結果:<pre>Memory: he said "RLII NEED WATER!PDI", and expired.
Display: he said "!RETAW DEEN I", and expired.</pre>
然而,一個更簡單和更好的方法是在感嘆號后面放置一個RLM。因為這樣感嘆號標記不是在定向邊界,這會產生正確的結果。當人為地編輯文本或程序化生成需要編輯的文本,或處理根本不支持顯式格式化字符的應用程序,這是最好的方法。
<pre>Memory: he said "I NEED WATER!RLM", and expired.
Display: he said "!RETAW DEEN I", and expired.</pre>
首選后者的方法因為它不使用顯式格式化字符,在不完全支持編輯器和其他字符處理的情況下,它可以輕松擺脫同步。然而,顯式格式化字符是絕對必要的,當一個文本包含與之相反方向的文本,相反方向的文本包含著與原始方向相同的文本。這種情況并不像人們想象的那樣罕見,因為拉丁語的品牌名稱、技術術語和縮寫常書寫在非拉丁語文本的原始拉丁語字符中,包括right-to-left文本,如下所示:
<pre>Memory: it is called "RLIAN INTRODUCTION TO javaPDI" - $19.95 in hardcover.
Display: it is called "java OT NOITCUDORTNI NA" - $19.95 in hardcover.</pre>
因此,當文本通過插入數據到模板中而程序化生成,不打算以后手動編輯,而且特定的插入恰好是與模板文本方向相反,這種情況使用顯式格式化字符(或等同它們的標記)包裹插入的數據是最簡單的,而不用分析是否真的有必要這樣做或可以使用無狀態定向標記完成。
此外,在這種常見的情景中,強烈建議使用定向隔離格式化字符而不是定向嵌入格式化字符(一旦知道目標展示平臺支持隔離)。這是因為嵌入會像強字符一樣影響周圍文本。嵌入的強影響會產生不可預料效果,強影響很少產生有益的效果。為了證明,這里使用嵌入代替隔離:
<pre>Memory: it is called "RLEAN INTRODUCTION TO javaPDF" - $19.95 in hardcover.
Display: it is called "$19.95 - "java OT NOITCUDORTNI NA in hardcover.</pre>
這當然不是預期中的顯示,這是因為數字(連同里面所有的中性字符)“粘(sticking)”在前面的RTL嵌入上,就表現得“粘”上了前面的RTL字符了。
定向隔離也提供了一個解決方案,在普通情況下,程序化插入的文本方向是不知道的。與分析插入文本的字符并決定是否使用LRE或RLE(或LRI或RLI或什么都不使用)不同的是,軟件可以采取簡單的方式,即使用FSI和PDI包裹插每個未知方向。因此,FSI而不是RLI在上述例子中會產生相同的顯式。FSI的第一個強啟發式并不是可靠的,但它能在大多數情況下甚至在混個文本中起作用。
雖然用隔離包裹插入是一種有用的計數,但更好的方式是,在已知內部沒有被隔離包裹的反方向字符的文本時,不包裹文本。不必要的包裹層次不單增大體積和復雜度;它們還可能最終超過了深度限制和渲染無效的內部隔離,這會導致文本錯誤顯示。一個普遍的情況是,不需要包裹的插入是一個已知的本地化的上下文環境,即一個帶著插入值的轉換消息要不本地化,要不包裹在隔離中。
6.4 分離標點符號
一個常見的問題是其中文本確實表示著一系列具有分隔標點符號的片段,并且通常是串聯的。這些分隔符通常是中性字符的字符串。例如,一個網頁的底部可能如下:
<pre>advertising programs - business solutions - privacy policy - help - about</pre>
例如,這可能通過分隔符“-”來連接數量不定的字符串建立在服務器上。如果所有的文本轉換成阿拉伯語或希伯來語,整體的頁面方向設置成RTL,正確的顯示結果如下:
<pre>TUOBA - PLEH - YCILOP YCAVIRP - SNOITULOS SSENISUB - SMARGORP GNISITREVDA</pre>
然而,假定在轉換中,保留一些LTR字符。這種情況對公司名、產品名、技術術語等來說很常見。如果其中一個分隔符兩邊是LTR字符,那么會導致頁面產生嚴重的混亂。例如,假如“programs”和“business”以英語術語留下而不轉換。結果如下:
<pre>TUOBA - PLEH - YCILOP YCAVIRP - SNOITULOS programs - business GNISITREVDA</pre>
顯而易見,第一個術語“advertising business”和第二個“programs solutions”就產生了混亂。對這個問題最簡單的解決方式是在每個分隔符字符串中包含一個RLM字符。這將導致各分隔符采用right-to-left的方向,并產生正確的展示:
<pre>TUOBA - PLEH - YCILOP YCAVIRP - SNOITULOS business - programs GNISITREVDA</pre>
顯式格式化字符(LRE,RLE,和PDF或LRI,RLI,FSI和PDI)可以用于取得相同的效果;網頁會使用帶有屬性dir="ltr"
或dir="rtl"
的span
標簽。嵌入到每個單獨字段中,不包括分隔符。總的來說,首選的顯式格式化字符LRM和RLM,因為它們的影響范圍更本地化,當文本被復制時比使用dir
屬性更穩健(理論上程序在將文字轉換成純文本時,會將dir
屬性轉變成相應的顯式格式化字符,但通常并不支持這個功能)。
6.5 轉換為純文本
為了外觀一致,當雙向文本受制于高級協議來轉換成Unicode純文本時,應該插入格式化字符來確保展示順序,展示順序由Unicode雙向算法應用程序匹配,通過高級協議指定。每當文本使用高級協議來轉換成標記(marked-up)文本時that is unaware of the higher-level protocol.,應該遵守同樣的原則。例如,如果高級協議基于L比R/AL字符的數量來設置分段方向為1(R),當轉換為純文本,文本里的分段會被嵌入到括號對RLE..PDF格式化字符中。如果同一文本轉換成HTML4.0,屬性dir="rtl"
會被添加到分段元素。
7 鏡像
鏡像屬性對確保正確的字符用于所需的語義來說,非常重要。這是特別重要,當字符的名字與所需的語義不符時,如U+0028“(”左括號(LEFT PARENTHESIS)。雖然字符的名字表明它是個左括號,字符確實表現出開括號(在括號短語開頭的字符,而不是尾隨的那個。)
某些沒有Bidi_Mirrored屬性的字符在被渲染成鏡像圖像字符,是由高級協議添加鏡像:參閱章節4.3,Higher-Level Protocols,尤其是HL6。除了這種情況,鏡像必須根據規則L4,去確保正確的字符被用于表達所需的語義,并避免互相干擾和安全問題。
實行規則L4需要鏡像圖像字符。這些圖像字符可能不會是精確的圖形鏡像。例如,一個斜體圓括號不是另一個的鏡像(“(”不是“)”的圖形鏡像)。Instead, mirror glyphs are those acceptable as mirrors within the normal parameters of the font in which they are represented.
在實現中,有時候字符對是互相接受的鏡像,例如,U+0028“(” 左括號(LEFT PARENTHESIS)和U+0029“)”右括號(RIGHT PARENTHESIS)或U+22E0 “?”不領先與或等于(DOES NOT PRECEDE OR EQUAL)和and U+22E1 “?”不繼承或等于(DOES NOT SUCCEED OR EQUAL)。其他字符例如U+2231 “?”順時針積分(CLOCKWISE INTEGRAL)沒有相應的可接受的鏡像字符。文件BidiMirroring.txt data file[Data9],列出互為鏡像字形的字符對。這一數據在[UCD]正式的屬性名是Bidi_Mirroring_Glyph。文件中的注釋指出鏡像對“合適的才是最好的”:雖然理論的鏡像字形的形狀不同,但在渲染中它們也是可以接受的。
遷移問題
在UBA的Unicode 6.3版本有兩個主要的新增功能:
定向隔離
括號對
新的定向隔離的實現應該存在很少的兼容問題;UBA經過謹慎的修改以求縮小與以前的文本的差異。等級數量的限制可能會有些不同,但這在實際中很少碰到。
對于括號對,可能會有更多不同。在不知道(沒有良好的用戶界面)定向標記或嵌入的情況下,人們構建的文本雖然有正確的視覺呈現但內部結構不正確。(即...[...[...,表現為...[...]...)。新算法捕獲這類型的問題,因為這樣畸形的括號序列不會被匹配。
然而,某些情況如缺少規則N0的舊實現會產生預期的表現,而新實現不會。用戶對實現的反饋對決定添加規則N0具有積極的影響。
對于那些未能正確更新到以前的Unicode版本的實現,也存在一些兼容問題,特別對處理不當的斜線“T 1/2”(T是一個阿拉伯字符)表現出錯誤的“2/1 T”。
為了減輕兼容問題的影響,強烈建議實現采用以下步驟:
在任何括號的兩邊,增加適當的定向格式化字符讓其能被規則N0解析,這樣也能在舊系統正確地表示。也可以在括號兩邊使用定向標記(RLM或LRM)。為了向前兼容,在舊系統中撰寫的文本應該使用語義正確的括號(必要時使用定向格式化字符),以確保Unicode的6.3后的系統實現得到正確的顯示。
在圍繞數字+斜線+數字(如3/2)的序列添加適合的顯式嵌入。
部分重組
在Unicode 6.3,對其文本進行了重要的重組。下表顯示了新舊章節變化。
|Unicode 6.3|Unicode 6.2|
|:--|:--|:--|
|2.4 Explicit Directional Isolates|n/a|
|2.5 Terminating Explicit Directional Isolates|n/a|
|2.6 Implicit Directional Marks|2.4|
|3.3.3 Preparations for Implicit Processing|n/a|
|3.3.4 Resolving Weak Types …3.3.6 Resolving Implicit Levels|3.3.3…3.3.5|
|6.1 Joiners|5.3|
|6.2 Vertical Text|5.4|
|6.3 Formatting|5.5|
|6.4 Separating Punctuation Marks|5.6|
|6.5 Conversion to Plain Text|n/a|
|Migration Issues|5.7|
致謝
Mark Davis created the initial version of this annex and maintains the text. Aharon Lanin and Andrew Glass made substantial additions to Revision 29 (Unicode 6.3.0).
Thanks to the following people for their contributions to the Bidirectional Algorithm or for their feedback on earlier versions of this annex: Ahmed Talaat (???? ????), Alaa Ghoneim (???? ????), Asmus Freytag, Avery Bishop, Ayman Aldahleh (???? ??????), Behdad Esfahbod (????? ??????), Doug Felt, Dwayne Robinson, Eric Mader, Ernest Cline, Gidi Shalom-Bendor (???? ????-?? ???), Gilead Almosnino (???? ?????????), Isai Scheinberg, Israel Gidali (????? ?????), Joe Becker, John McConnell, Jonathan Kew, Jonathan Rosenne (????? ????), Kamal Mansour (???? ?????), Kenneth Whistler, Khaled Sherif (???? ????), Lauren?iu Iancu, Maha Hassan (??? ???), Markus Scherer, Martin Dürst, Mati Allouche (?????? ????), Michel Suignard, Mike Ksar (????? ????), Murray Sargent, Paul Nelson, Peter Constable, Rick McGowan, Robert Steen, Roozbeh Pournader (????? ???????), Steve Atkin, and Thomas Milo (???????? ??????).
參考
修改
以下總結了本附件先前的修訂。
完