Postgresql

Unicode 感知數據庫中 u202b RLE 和 u202c PDE 的 Unicode 儲存?

  • January 1, 2019

我正在為地名建構一個新產品,其中的阿拉伯語顯示有點像這樣:

^IArabic^I<202b>ﺰﻤﺑﺎﺑﻮﻳ<202c>^I<202b>ﺞﻫﻭﺮﻳﺓ ﺰﻤﺑﺎﺑﻮﻳ<202c>$

其實也不全。這對我的 ASCII 終端來說是一個真正的問題,所以我會做一個例外並截圖文本。

阿拉伯

我的問題是關於那些U202B “Right-To-Left Embedding” (RLE)U202C “Pop Directional Formatting” (PDF)。這些是否被儲存為數據?我的第一個假設是這些字元是渲染的,而不是在文件中,但可惜它們在那裡..

360    5E03 97E6 5171 548C 56FD 000A 0009 0041 0072 0061 0062 0069 0063 0009 202B 0632    布韦共和国..Arabic..ز
.............................................................................^HERE
389    0645 0628 0627 0628 0648 064A 202C 0009 202B 064F 062C 0647 0648 0631 064A 0629    مبابوي...ُجهورية
.....................................^HERE.....^HERE
422    0020 0632 0645 0628 0627 0628 0648 064A 202C 000A 0009 004E 006F 0074 0065 0073    .زمبابوي...Notes
...............................................^HERE

在數據庫中儲存阿拉伯語時,您通常會儲存\u202b\u202c嗎?他們似乎在渲染字元而不是技術數據?我只是想處理這個文本以放入數據庫,並想知道這些字元是否應該存在於數據庫中,或者在插入之前被剝離。

背景

阿拉伯語(以及希伯來語和敘利亞語)是從右到左的語言。因此,它們以與物理儲存字節相反的方向顯示。通過僅由字型/渲染系統解釋的不可列印字元來控制正確顯示。這兩個字元特別用於控制這一點(請參閱原始 Unicode 規範以了解初學者:https ://www.unicode.org/charts/PDF/U2000.pdf ),尤其是在嵌入從右到左文本的上下文中與從左到右的文本相同的段落(反之亦然)。

因此,您必須將它們儲存起來,否則稍後嘗試顯示此數據將使其與語言應該出現的方式相反,因此將被視為數據失去。這些是許多不可列印/零寬度的格式化控製字元之一。

Unicode 聯盟對如何使用這些字元的“官方”描述是(取自“第 23 章:特殊區域和格式字元”第 868 頁頂部):

與其他格式控製字元一樣,雙向排序控制會影響包含它們的文本的佈局,但對於其他文本處理(例如排序或搜尋)應忽略。但是,修改文本內容的文本程序必須正確地維護這些字元,因為匹配的雙向排序控制項必須相互協調,以免破壞雙向文本的佈局和解釋。lrerlelro或的每個實例rlo通常與對應的 配對pdf。同樣,每個 、 或 的實例lri通常rlifsi與對應的 配對pdi

關於保留(而不是丟棄)這些隱藏的格式化程式碼點的重要性,“Unicode® 標準附件 #9:UNICODE BIDIRECTIONAL ALGORITHM”,在“ 2.7 標記和格式化字元”部分中指出(強調我的):

顯式格式化字元將狀態引入純文字,在編輯或顯示文本時必須保持狀態。在不知道此狀態的情況下修改文本的程序可能會無意中影響大部分文本的呈現,例如通過刪除 PDF。

和:

每當從包含標記(ed:HTML 和/或 CSS)的文件中生成純文字時,都應引入等效的格式化字元,以免失去正確的順序。

Cal Henderson的(優秀的)“ Understanding Bidirectional (BIDI) Text in Unicode ”文件中提供了進一步的解釋(取自 OP 的回答)指出:

…我們可以禁止這些顯式字元(U+202A - U+202E),這很容易。這確實意味著任何想要使用它們在其阿拉伯語使用者名邊緣包含 Neutrals 的人都將不走運 - 當他們發布評論時,這更糟糕,期間跳轉到“開始”文本。

如果我們想允許使用這些字元,解決方案相當簡單(如果難以實現):我們需要確保每個開始標記都有一個成對的結束標記(PDF),以便從字元串中出來的狀態堆棧是與我們進入時的狀態相同。我們還需要注意,我們不允許在沒有附帶推送標記的情況下使用任何 PDF,否則我們不能在塊之外使用任何自己。

**因此,**即使特定單元格的文本應該完全是從右到左的語言,刪除這些標記也可能會改變中性字元(例如標點符號)的位置。例如(使用 SQL Server):

SELECT NCHAR(0x0671) + NCHAR(0x0679) +  N'!';
-- ٱٹ!

SELECT NCHAR(0x202B) + NCHAR(0x0671) + NCHAR(0x0679) + N'!' + NCHAR(0x202C);
-- ‫ٱٹ!‬

計劃稍後重新添加它們,或者讓客戶端應用程序重新添加它們將不起作用,因為沒有固有的方法可以知道它們甚至被使用,如果是,它們被放置在哪裡。

安全的方法是保留這些字元

**例如,**您試圖在問題的頂部包含一些文本:

^IArabic^I<202b>ﺰﻤﺑﺎﺑﻮﻳ<202c>^I<202b>ﺞﻫﻭﺮﻳﺓ ﺰﻤﺑﺎﺑﻮﻳ<202c>$

但顯然這並沒有以正確的順序顯示。但是,字節的順序正確:

只看第一<202b>...<202c>部分(同樣,使用 SQL Server,因此它是 Little Endian):

SELECT CONVERT(VARBINARY(MAX), N'<202b>ﺰﻤﺑﺎﺑﻮﻳ<202c>');

字節是:

3C00 3200 3000 3200 6200 3E00 B0FE E4FE 91FE 8EFE 91FE EEFE F3FE 3C00 3200 3000 3200 6300 3E00
<    2    0    2    b    >    .    .    .    .    .    .    .    <    2    0    2    c    >

如您所見,沒有其他格式字元。因為阿拉伯字元是從右到左的強字元,<202所以後面的中性 ( <) 和弱 ( 202) 字元繼續向左顯示航向(甚至<變成>)。需要明確的是,202 本身顯示從左到右,如果數字不是回文,這會更清楚。如果數字是 203,那麼它仍然會顯示為 203 而不是 302。但是c從左到右是強的,所以它(以及後面的字元)按預期顯示。

怎麼修?只需在阿拉伯語後面添加隱式的從左到右標記,以指示從右到左的方向性應在該點結束。<如果我們在這兩個段中的最後一個阿拉伯字元之後(並且就在 之前)添加程式碼點 U+200E ,我們會得到以下結果:

^IArabic^I<202b>ﺰﻤﺑﺎﺑﻮﻳ‎<202c>^I<202b>ﺞﻫﻭﺮﻳﺓ ﺰﻤﺑﺎﺑﻮﻳ‎<202c>$

現在,如果 StackOverflow 要刪除格式,那麼它將恢復到不正確的顯示,並且沒有跡象表明可以通過程式方式發現此處所需內容的意圖。

如果您想刪除格式並稍後將其重新添加,您是否 100% 確定這些字元存在的意圖?它們並不總是被使用,那麼你怎麼知道當它們出現時為什麼會被使用呢?不會有非阿拉伯字元吧?好的,那你怎麼分類<202>?我省略了“b”和“c”,因為可能存在沒有任何拉丁字元的標點符號和數字,並且仍然是“完全阿拉伯語”。

這就是為什麼我說讓他們留在裡面是“最安全”的路線。不是唯一的路線。但是,如果您不控制輸入值,那麼我看不出您如何保證永遠不會意外更改數據的含義。

您的情況不僅僅是處理 U+202B 和 U+202C 字元的問題。我會先回答你的相關問題,然後再回答更重要的問題。

在數據庫中儲存阿拉伯語時,您通常應該儲存U+202B“從右到左嵌入”(RLE)U+202C“流行方向格式”(PDF)字元嗎?否。以與語言無關的方式儲存數據值的純文字。僅當 U+202B 和 U+202C 位於混合了不同方向性字元的數據值內時,才儲存它們。

為什麼這些字元會出現在您的輸入數據中?您的輸入數據似乎是從 PDF 文件中提取的,所以我敢打賭,PDF 文件的創作目的只是為了在 PDF 查看器中正確顯示。如果您發現提取的文本可用於重新調整用途,那麼您很幸運。預計必須清理從 PDF 文件中提取的文本。

請注意,提取的文本混合了具有從左到右方向性的拉丁腳本文本和具有從右到左方向性的阿拉伯腳本文本。無論編寫該文本的軟體似乎都發現 U+202B 和 U+202C 字元對其目的有用。這並不意味著這些字元對您的目的有用。就像您過濾掉 U+0009 TAB 字元一樣,明智地過濾掉方向性格式字元。

檢查阿拉伯文本,以確認它以閱讀順序儲存在文件中。由於文本是從 PDF 文件中提取的,因此可能會按顯示順序儲存。也就是說,阿拉伯字元在您的摘錄中可能是相反的順序。

現在,一些你沒有問的重要問題的答案。

顯示和處理所有阿拉伯文本都需要這些字元嗎?不,但它們通常是必要的。

開始理解這一點的好地方是UAX #9 Unicode Bidirectional Algorithm。阿拉伯正字法結合了從右到左顯示的阿拉伯字母與從左到右顯示的數字和拉丁字母,因此阿拉伯文本被稱為雙向

Unicode 標准定義了字元的屬性。在這些屬性中是雙向類型。一個角色可以有從左到右或從右到左的類型,或者弱類型,或者中性類型。字元按閱讀順序儲存,無論它們的雙向類型如何。Unicode 雙向算法指定如何以正確的方向組合從閱讀順序開始顯示字元。雙向格式化字元,如 U+202B 和 U+202C,有助於算法在雙向類型本身不夠時獲得正確的結果。

為什麼將輸入中的行粘貼到 StackExchange Web 表單中會產生與“ASCII 噴射終端”不同的結果?因為呈現 StackExchange Web 表單的瀏覽器應用了Unicode 雙向算法。我不讀阿拉伯語,所以我不確定,但我懷疑阿拉伯語文本後的“<202c>”被拆分為顯示的“<”、“2”、“0”、“2”部分從右到左,然後從左到右顯示“c”、“>”部分。並且“<”從右到左顯示為“>”。同時,您的終端可能會按儲存順序獨立顯示每個字元,而無需應用Unicode Bidirectional Algorithm

如果您想要當地語言的地名,您是否卡在從聯合國創作的 PDF 文件中抓取文本?沒有。本地化地名的另外兩個來源是WikidataCommon Locale Data Repository。Wikidata 有一個關於贊比亞的頁面,該頁面以各種語言顯示該國的本地化名稱。有一個查詢以機器可讀的形式提取此數據。CLDR 很容易用阿拉伯語顯示許多國家的名稱。通過查詢每種語言的數據,您可以將其重構為在每種可用語言中使用贊比亞或任何國家的名稱。

如果您只是想出如何將這個阿拉伯文本儲存在您的數據庫欄位中,您可能會產生好的結果嗎?我不怕。

我懷疑您的數據庫和呈現數據庫數據的網頁或應用程序到目前為止只處理從左到右的文本。通過添加阿拉伯語文本,您不僅要面對數據庫,而且要面對應用程序,以及雙向文本。您遇到了與數據庫和應用程序需要解決的雙向性相關的新問題。顯示數據元素時如何確定方向性上下文?您系統中的哪個軟體將執行Unicode 雙向算法?您將如何根據數據項使用的語言和字元為數據項選擇合適的字型?您是否要為您的應用程序或網頁添加從右到左佈局顯示的功能?

我希望僅剝離方向格式字元並將阿拉伯文本放入數據庫中即可為您提供足夠的結果。準備好它可能不會——包括這篇文章需要你面對關於雙向性的問題,而這些問題你直到現在才需要擔心。

引用自:https://dba.stackexchange.com/questions/225996