Unicode 感知数据库中 \u202b RLE 和 \u202c PDE 的 Unicode 存储?

Eva*_*oll 4 postgresql encoding unicode

我正在为地名构建一个新产品,其中阿拉伯语显示有点像这样:

^IArabic^I<202b>???????<202c>^I<202b>?????? ???????<202c>$
Run Code Online (Sandbox Code Playgroud)

其实不完全是。这对我的 ASCII 喷出终端来说是一个真正的问题,所以我会例外并截屏文本。

阿拉伯

我的问题是关于那些U202B“从右到左嵌入”(RLE)U202C“流行方向格式”(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
Run Code Online (Sandbox Code Playgroud)

在数据库中存储阿拉伯语时,您通常存储\u202b, 和\u202c? 他们似乎在渲染角色而不是技术数据?我只是想处理此文本以将其放入数据库,并想知道这些字符是否应该存在于数据库中,或者在插入之前去除。

背景

Sol*_*zky 6

阿拉伯语(以及希伯来语和叙利亚语)是从右到左的语言。因此,它们以与物理存储字节相反的方向显示。通过仅由字体/渲染系统解释的不可打印字符控制正确显示。这两个字符特别用于控制这一点(请参阅初学者的原始 Unicode 规范:https : //www.unicode.org/charts/PDF/U2000.pdf),尤其是在从右到左嵌入文本的上下文中与从左到右的文本相同的段落(反之亦然)。

因此,您必须将它们存储起来,否则以后尝试显示这些数据会使它从语言应有的显示方式向后呈现,因此将被视为数据丢失。这些是许多不可打印/零宽度的格式控制字符之一。

来自 Unicode Consortium 的关于如何使用这些字符的“官方”描述是(摘自第 868 页的“第 23 章:特殊区域和格式字符”):

与其他格式控制字符一样,双向排序控制会影响包含它们的文本的布局,但对于其他文本处理(例如排序或搜索)应忽略。但是,修改文本内容的文本处理必须正确维护这些字符,因为必须协调匹配的双向排序控件对,以免破坏双向文本的布局和解释。a lre, rle, lro, or 的每个实例rlo通常与相应的 配对pdf。同样, an lri, rli, or 的每个实例fsi通常都与相应的 配对pdi

关于保留(而不是丢弃)这些隐藏格式代码点的重要性,“Unicode® 标准附件 #9:UNICODE 双向算法”在“ 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);
-- ???!?
Run Code Online (Sandbox Code Playgroud)

计划稍后重新添加它们,或让客户端应用程序将它们重新添加,将不起作用,因为没有内在的方法知道它们甚至正在被使用,如果是,它们被放置在哪里。

最安全的方法是保持这些字符

例如,您试图在问题的顶部包含一些文本:

^IArabic^I<202b>???????<202c>^I<202b>?????? ???????<202c>$

但显然这没有以正确的顺序显示。字节,但是,正确的顺序:

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

SELECT CONVERT(VARBINARY(MAX), N'<202b>???????<202c>');
Run Code Online (Sandbox Code Playgroud)

字节是:

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    >
Run Code Online (Sandbox Code Playgroud)

如您所见,没有其他格式字符。因为阿拉伯字符是从右到左强,<202后面的字符 - - 中性 ( <) 和弱 ( 202),继续向左显示标题(甚至<变成>)。需要明确的是,202 本身是从左到右显示的,如果数字不是回文,这会更清楚。如果数字是 203,那么它仍然会显示为 203 而不是 302。但是c从左到右很强,所以它(以及后面的字符)按预期显示。

怎么修?只需在阿拉伯语之后添加隐含的从左到右标记,以指示从右到左的方向性应该在该点结束。如果我们<在这两个段中的最后一个阿拉伯字符之后(并且就在 之前)添加代码点 U+200E ,我们将得到以下结果:

^IArabic^I<202b>????????<202c>^I<202b>?????? ????????<202c>$

现在,如果 StackOverflow 去掉格式,那么它会恢复到不正确的显示,并且没有迹象表明可以通过编程方式发现此处所需的意图。

如果您想删除格式并稍后重新添加,您是否 100% 确定为什么这些字符存在的意图?它们并不总是被使用,那么当它们出现时你怎么知道为什么使用它们?不认为会有任何非阿拉伯字符吗?好的,那么你如何分类<202>?我省略了“b”和“c”,因为标点符号和数字可能没有任何拉丁字符,但仍然是“完全阿拉伯语”。

这就是为什么我说让他们呆在里面是“最安全”的路线。不是唯一的路线。但是,如果您不控制输入值,那么我看不出您如何保证永远不会意外更改数据的含义。


小智 5

您的情况比处理 U+202B 和 U+202C 字符的问题更深刻。我将首先回答您最关心的问题,然后再回答更重要的问题。

\n\n

在数据库中存储阿拉伯语时,通常是否应该存储U+202B“从右到左嵌入”(RLE)U+202C“流行方向格式”(PDF)字符?不会。以与语言无关的方式存储数据值的纯文本。仅当 U+202B 和 U+202C 位于混合不同方向性字符的数据值内时才存储它们。

\n\n

为什么这些字符出现在您的输入数据中?您的输入数据似乎是从 PDF 文件中提取的,因此我敢打赌,创建 PDF 文件只是为了在 PDF 查看器中正确显示。如果您发现提取的文本可用于重新调整用途,那么您很幸运。预计必须清理从 PDF 文件中提取的文本。

\n\n

请注意,提取的文本混合了具有从左到右方向性的拉丁脚本文本和具有从右到左方向性的阿拉伯脚本文本。无论使用什么软件编写该文本,似乎都发现 U+202B 和 U+202C 字符对其目的很有用。这并不意味着这些字符对您的目的有用。就像过滤掉 U+0009 TAB 字符一样,明智地过滤掉方向性格式字符。

\n\n

检查阿拉伯文本,确认它按阅读顺序存储在文件中。由于文本是从 PDF 文件中提取的,因此它可能会按显示顺序存储。也就是说,阿拉伯字符在您的摘录中可能是相反的顺序。

\n\n

现在,一些您没有提出的重要问题的答案。

\n\n

显示和处理所有阿拉伯文本是否都需要这些字符?不,但它们通常是必要的。

\n\n

开始理解这一点的一个好地方是UAX #9 Unicode 双向算法。阿拉伯语正字法将从右到左显示的阿拉伯字母与从左到右显示的数字和拉丁字母结合在一起,因此阿拉伯文本被称为双向文本。

\n\n

Unicode 标准定义了字符的属性。这些属性中包括双向类型。字符可以具有从左到右或从右到左类型、弱类型或中性类型。字符按读取顺序存储,无论其双向类型如何。Unicode双向算法指定如何从阅读顺序开始,以正确的方向组合显示字符。当双向类型本身不够时,双向格式化字符(例如 U+202B 和 U+202C)可帮助算法获得正确的结果。

\n\n

为什么将输入中的行粘贴到 StackExchange Web 表单中会得到与“ASCII 喷出终端”不同的结果?因为呈现 StackExchange Web 表单的浏览器应用了Unicode 双向算法。我不读阿拉伯语,所以我不确定,但我怀疑阿拉伯语文本后面的“<202c>”被分割成“<”,“2”,“0”,“2”部分从右到左显示,然后“c”、“>”部分从左到右显示。并且“<”从右到左显示为“>”。同时,您的终端可能会按存储顺序独立显示每个字符,而不应用Unicode 双向算法

\n\n

如果您想要本地语言的地名,您是否会陷入从联合国创作的 PDF 文件中抓取文本的困境?不会。本地化地名的另外两个来源是WikidataCommon Locale Data Repository。维基数据有一个关于赞比亚的页面,其中有各种语言的该国家的本地化名称。有一个查询用于以机器可读的形式提取此数据。CLDR 可以轻松地用阿拉伯语显示许多国家的名称。通过查询每种语言的此数据,您可以将其重构为每种可用语言的赞比亚或任何国家/地区的名称。

\n\n

如果您只是弄清楚如何将这些阿拉伯文本存储在数据库字段中,您可能会产生好的结果吗?我担心不会。

\n\n

我怀疑您的数据库以及显示数据库数据的网页或应用程序到目前为止仅处理从左到右的文本。通过添加阿拉伯文本,您不仅要面对数据库,还要面对具有双向文本的应用程序。您的数据库和应用程序需要解决与双向性相关的新问题。当您显示数据元素时,如何确定方向性上下文?您系统中的哪个软件将执行Unicode 双向算法?如何根据数据项使用的语言和字符为数据项选择正确的字体?您是否要为您的应用程序或网页添加从右到左布局显示的功能?

\n\n

我希望只要去掉方向格式字符并将阿拉伯文本放入数据库中即可给您带来足够的结果。请做好准备,包含此文本可能不会 \xe2\x80\x94 要求您面对有关双向性的问题,而到目前为止您还不需要担心这些问题。

\n