为什么''''=''和'是假的?

use*_*983 2 ruby text character-encoding

我标记了字符编码和文本,因为我知道如果你键入'and' == 'and'rails控制台,或者大多数其他编程语言,你会得到true.但是,当我的一个用户将他的文本粘贴到我的网站时,我遇到了问题,由于文本的某些问题,我无法拼写检查或通过copyscape验证它的原创性.(或者我对文本编码的理解?)

例:

如果您将以下行复制并粘贴到rails控制台中,您将获得false.

'?nd' == 'and' #=> false
Run Code Online (Sandbox Code Playgroud)

如果将以下行复制并粘贴到rails控制台中,true即使它们在浏览器中看起来完全相同,也会得到.

'and' == 'and' #=> true
Run Code Online (Sandbox Code Playgroud)

不同之处在于,在第一个示例中,第一个'?nd'是从我的用户文本中复制并粘贴导致问题的文本.所有其他实例'and'都在浏览器中输入.

这是编码问题吗?如何解决我的问题?

mat*_*att 5

这不是一个真正的编码问题,在第一种情况下,字符串只是因为它们不同而比较为false .

第一字符串的第一个字符不是"正常的" a,它实际上是U+0430 CYRILLIC SMALL LETTER A-的前两个字节(208和176,或0xD00xB0在十六进制)是UTF-8编码此字符.它恰好看起来像一个"正常"的拉丁文a,就是这样U+0061 LATIN SMALL LETTER A.

这是"正常"a : a,这是西里尔文a:,?它们看起来非常相似.

对此的修复实际上取决于您希望应用程序执行的操作.理想情况下,您可能希望处理所有语言,因此您可能希望保留它并依赖用户提供合理的输入.

您可以a使用例如用拉丁语替换有问题的角色gsub.问题在于还有许多其他角色与更熟悉的角色具有相似的外观.如果你选择这条路线,你最好找一个为你做这件事的图书馆/宝石,你可能会发现你对转换过于严格.

另一种选择可能是选择应用程序支持的一组Unicode脚本,并拒绝这些脚本之外的任何字符.您可以使用Ruby的正则表达式脚本支持相当容易地检查,例如,/\p{Cyrillic}/将匹配所有西里尔字符.


Jör*_*tag 5

问题不在于编码.单个文件或单个终端只能有一个编码.如果将两个字符串复制并粘贴到同一个源文件或同一个终端窗口中,它们将以相同的编码插入.

问题也不在于标准化或折叠.

第一个字符串有4个八位字节:0xD0 0xB0 0x6E 0x64.前两个八位字节是单个Unicode代码点的两个八位字节UTF-8编码,第三个和第四个八位字节是Unicode代码点的一个八位字节UTF-8编码.

因此,该字符串由三个Unicode代码点组成:U+0430 U+006E U+0064.

这三个代码点解析为以下三个字符:

  1. CYRILLIC SMALL LETTER A
  2. 拉丁文小写字母N.
  3. 拉丁文小写字母D.

第二个字符串有3个八位字节:0x61 0x6E 0x64.所有三个八位字节都是Unicode代码点的一个八位字节UTF-8编码.

因此,该字符串由三个Unicode代码点组成:U+0061 U+006E U+0064.

这三个代码点解析为以下三个字符:

  1. 拉丁文小写字母A.
  2. 拉丁文小写字母N.
  3. 拉丁文小写字母D.

真的,没有任何问题可言!这两个字符串不同的.使用您使用的字体,西里尔字母看起来与拉丁语a相同,但就Unicode而言,它们是两个不同的字符.(在不同的字体中,它们甚至可能看起来不同!)从编码或Unicode角度来看,你真的无能为力,因为问题不在于编码或Unicode.

这称为同形体,两个不同但具有相同(或非常相似)字形的字符.

可以尝试做的是将所有字符串音译为拉丁语(前提是您可以保证没有人想要输入非拉丁字符),但实际上,问题是:

  1. 那个西里尔字母来自哪里?
  2. 也许这是意味着是一个西里尔和真正应该被视为不等于一个拉丁语?

根据这些问题的答案,您可能要么修复源代码,要么根本不做任何事情.

对于浏览器供应商来说,这是一个非常热门的话题,BTW,因为现在有人可以注册域名google.com(其中一个字母被切换为同名),你将无法发现地址栏中的差异.这被称为同形攻击.这就是为什么除了Unicode域名外,他们总是显示Punycode域.