首页  >  文章  >  Java  >  要记住的边缘情况。部分文字

要记住的边缘情况。部分文字

王林
王林原创
2024-08-09 06:41:221005浏览

Edge Cases to Keep in Mind. Part  Text

无论您是软件开发人员、文案撰稿人还是只是写电子邮件,文本都有许多您需要注意的陷阱。有些可能会导致许多问题,从应用程序中的错误到视觉假象甚至受害者!让我们看看如何避免它们。

背景

文本(又名字符串)几乎存在于所有软件项目中,从像 hello-worlds 这样的单行代码到包含数十亿行代码的企业系统,无论编程语言、平台等如何。文本只是字符序列,所以这不应该是一件复杂的事情,对吧?让我们看看你会遇到哪些陷阱!

信箱

世界上的一些字母(包括英语)是双院制的,这意味着它们同时包含大写和小写字母。
例如:a 是小写字符,A 是大写字符。从一种字母大小写转换为另一种字母大小写是一种很常见的操作。

大小写可能看起来微不足道——一个字符只是转换(映射)为另一个字符。如果它不是字母,它甚至可能本身就是一个字符,例如 1 或 + 等等。此外,这种映射总是可以简单地反转,例如A->a和a->A。所以,乍一看一切似乎都很好。好吧,事实并非如此!

大小写错误可能会导致死亡

这不是一个笑话,我们也不是在谈论愤怒的语法纳粹分子。正如您在本文中所读到的那样,外壳故障造成 2 名受害者,并使另外 3 人入狱。

这是怎么发生的?好吧,在土耳其语(和阿塞拜疆语)中,我们有 2 个不同的 i 字母:有点(封闭)和无点(开放)。在英语和其他拉丁字母中,小写字母总是带点,而大写字母则不带点。一切都在表 1 和在线演示中进行了说明。

表 1. 带点和不带点的 i 字母。

Lowercase Uppercase
English i dotted I dotless
Turkish i dotted İ dotted
Turkish ı dotless I dotless

如您所见,大小写更改结果取决于上下文,而上下文又取决于当前语言。在撰写供人类使用的文本时,使用适当的语言非常重要。如果你不关心这一点,你的话最终可能会产生与预期不同的含义。

另一方面,机器可读的文本(如 HTTP 标头或 JSON 键)应该以语言中立的方式处理。否则,您可能会在输出中得到非 ASCII 字符,这可能会破坏应用程序逻辑。这种情况就发生在 GSON 中,这是一个被数千(甚至数百万)个项目使用的库。

变音符号的秘密

带有变音符号的字符可以像 ó 这样预先组合,或者通过组合像 ó 这样的标记来创建。阅读此页时,它们看起来像是同一个角色。然而,如果查看第二个的十六进制转储,或者甚至尝试以编程方式获取其长度(如本演示所示),您将看到它由 2 个单独的字符组成:拉丁小写字母 o 和组合的锐音符。同样,每个 Hangul(韩文字母)音节块都可以预先组合或书写为不同的 jamos 单个字母/字符的组合。

为什么组合标记如此重要?大多数带变音符号的字符有两种书写方式(例如波兰语、匈牙利语或捷克语字母)。这使得排序、搜索或文本长度测量等操作变得非常重要。通常,为了获得最佳的用户体验,需要对文本进行规范化(转换为一种规范形式)。否则,当用户看到多个“不同”的登录名或看起来相同的文件名时,他们可能会感到困惑。 Slack 如何处理频道名称就是一个很好的例子。它们在通道创建之前就已标准化,因此相同名称以不同方式书写的情况不能共存。

有些角色比其他角色更平等

字符等效性有 2 个级别。 规范等价 当字符被假定具有相同的含义和外观时发生,例如上述 ó 和 ó 仅在(技术)书写方式上有所不同。另一方面,兼容性意味着字符可能看起来不同,但可能具有相同的含义。例如,连字 ffi 与三个不同的字母 ffi 兼容,但它们在规范上并不相等。有关 Unicode 规范化的更多信息可以在标准文档中找到。

虽然每 2 个级别的组合形式和分解形式都是标准化的 - 所以我们总共有 4 种范式 - 标准化并不总是可逆的。例如,埃符号 Å 分解为拉丁大写字母 A A 加上 ̊ 上方的组合环,再组合回拉丁大写字母 A 且 Å 上方有环,而不是其起源的埃符号。

组合标准化错误导致冒险

共享给定文本的所有应用程序都使用相同的标准化方法也很重要。如果不这样做,可能会导致细微的错误和/甚至无声的数据丢失。此类错误可能很难发现,因为每个应用程序都可以完美运行,至少在单独运行时是这样。在这种情况下,应用程序通常不会“崩溃”,而只是发送或接收与应有的数据不同的数据,从而导致意想不到的后果。 nettalk 中的这个错误就是这样的一个例子。

上述印刷连字用于改善某些字符的视觉外观,这些字符彼此相邻时看起来不太好。大多数用户不需要担心连字,因为它们是由软件(例如)从单个字母自动生成的。 TeX 默认生成连字。然而,此类工具的开发人员必须考虑到,在某些情况下,连字可能不合适并引入错误。

看看这个:fi。第二个字母是有点的还是无点的?土耳其语读者可能会感到困惑。在某些情况下不应使用包含 i 的连字。

我的大写字母在哪里?

一些文字(所谓的两院制)如拉丁语和希腊语包含两种大小写的字母。几乎所有字母都有小写和大写。几乎……但不是全部!
虽然小写字母集始终存在,但大写字母集并非如此。那么,如果存在只有小写的字符,如果您尝试将它们转换为大写,会发生什么情况?会不会是一个错误导致操作失败呢?角色会保持不变吗?答案不是这样的!

最引人注目的例子之一是德语升音 s — ß。它是一个小写字符,转换为大写时,它变成双 S - SS。这种转变是不可逆的——SS 变成了 ss。网上看看。 TL;DR Unicode 5.1 引入了 ẞ(拉丁文大写字母升 S),但就字符映射而言,它通常不被视为 ß 的大写字母。它最近(2016 年)作为 SS 的同等有效形式添加到德语正字法规则集中。

许多其他小写连字没有相应的预组合大写形式。完整列表可以在 Unicode 特殊大小写文档中找到。

双重或三重问题

缺少一些大写字符,怎么办?连字可以由 2 个甚至 3 个字符组成,因此大写文本可能比原始小写文本长 3 倍。当生成的文本长度有限时,这一点非常重要。例如,在头像或缩写生成器中,就像 bitrise.io 上的这个错误一样。

神秘的第三种情况

希腊字母表包含 Sigma 字母,大写如下:Σ。它的小写形式是什么?嗯,这取决于!通常,它是 σ(非词尾),但在单词末尾,它是 ς(词尾)。但是,如果西格玛是唯一的字母或单词全部大写,则始终使用非最终版本,即使在最终位置也是如此。请参阅互动示例。

另一个边缘情况

带波形符 Ĩ 的拉丁文大写字母 i 的小写字母是什么?正如您可能已经猜到的,答案并非那么微不足道。存在相应的小写形式。两种形式都是无点的,但这是完全正常的。如果 i 和 j 附加了一些变音符号,则它们都没有点。那么这里有什么问题吗?

除了土耳其语之外,立陶宛语的拼写规则在 I 字母的情况下也很例外。在后者中,点保留在重音符号下方。例如,这意味着前面提到的 Ĩ 在立陶宛语中小写时会变成 i̇̃。如果你仔细观察,你会发现有 3 个字符:一个拉丁小写字母 i,上面是一个组合点,上面是一个组合波浪号。文本长度(再次)增加了3倍。

继续学习连字和多重图

如何只用 6 个字符写出一个由 7 个字母组成的单词?只需使用预先组合的连字和多重字母(二字母、三字母等)!当然,对于连接字母的每种可能的组合,没有预先组成的字符。然而,现有的可以用来有效地增加文本长度限制。例如,西里西亚语单词 dzbonek(锅)由 7 个字母组成,但仅使用 6 个字符即可写为 dzbonek。网上看看。请注意,dz 是二合字母,而不是连字。

例如,现在您可以发送包含超过 140 个字符的推文消息!可以在此处找到预先组合的 Unicode 二合字母和连字列表。

鲜为人知的按字母顺序排列的方法

字母顺序通常是在小学开始时教授的。 A、B、C、D...等等到 Z。就像馅饼一样简单!

不幸的是,字母顺序取决于语言。甚至基本拉丁字母(没有变音符号)的位置也可能不同。例如,在爱沙尼亚语中,字母 Z 位于 S 和 T 之间。

带有变音符号的字母的位置也不是通用的。有几种可能的方案:

  1. 在相应的基本字母之前,如马耳他语:W、X、Ż、Z。

  2. 在相应的基本字母之后,如波兰语:A、Ą、B、C、Ć。

  3. 在字母表的末尾,如瑞典语:Z、Å、ä。

  4. 与基本字母位于相同位置(用于整理目的),如匈牙利语:O=Ó。

请注意,同一字母在不同语言中的整理方式可能不同,甚至在同一语言中也可能有所不同,具体取决于上下文!。例如,在斯洛伐克语中,带变音符号的 A 始终位于 A 之后。但是,在德语中,它可能与非变音版本具有相同的值、位于其之后,甚至被视为 A+E。有关在哪些情况下使用哪种方式的更多信息可以在此处找到。

面包、收银机和赌场

需要校对的不仅仅是单个字母。多重图也可以有自己的规则。在斯洛伐克语中,CH 在 H 和 I 之间进行整理。因此,例如,单词 chlieb(面包)将在 hodina(一小时)之后进行整理。另一方面,在波兰语中,二合字母被视为两个单独的字母 - C 和 H - 因此没有特殊的排序规则。在线查看。

匈牙利语甚至有双合字母,每个合字母都有自己的排序规则。这导致了许多复杂的情况。让我们考虑一个可能的例子。我们有 SZ 有向图。它是在 S 之后整理的。它的双重版本(SZ + SZ)是 SSZ。这意味着 kaszinó(赌场)一词应该位于 kassza(收银机)之前。通常 Z 在 S 之后,但这里我们在第一个单词中有 K A SZ I,在第二个单词中有(相当于)K A SZ SZ。

此外,同一组字母可能是也可能不是(双)二合字母,具体取决于上下文。例如,上述斯洛伐克语 CH 在某些单词中被视为 2 个单独的字母 C 和 H,例如viachlas(复调音乐)。通常,在匈牙利语中,NNY = NY + NY,就像单词 mennybolt(天堂)一样。然而,我们还有一个 tizennyolc(十八),其中 NNY = N + NY,因此有一个字母 N 和一个二合字母 NY。

ΤНЅ ІЅ NОТ WНаТ ΥОй ТНІNΚ ІТ IЅ

您可能认为上面的标题仅由简单的拉丁字母组成。事实上,其中绝大多数是希腊语、西里尔语或亚美尼亚语大写字母。它们只是一些拉丁字母的同形字。

所以 A(拉丁文大写 A)与 A(希腊文大写 Alpha)或 А(西里尔文大写 A)不同。为什么这很重要?由于它们无法区分,因此可用于 IDN 同形异义词攻击。例如,仅包含拉丁字母的域bank.com看起来与包含西里尔小A而不是拉丁小A的bаk.com非常相似。此类域可能用于网络钓鱼。

包起来

在某些情况下处理文本可能会很棘手 - 特别是当您在多语言环境中工作时。根据经验,所有配置都应该适合给定的上下文。例如,在处理用户可见的文本时应考虑用户当前的语言,而机器可读的文本应以语言中立的方式处理(如果不可能,则使用英语)。选定的排序规则设置也应符合实际使用情况。文本应在需要时进行标准化,并且所选的标准化方法应在整个系统中保持一致。
想了解更多边缘情况吗?请继续关注,第二部分即将推出!

以上是要记住的边缘情况。部分文字的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn