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

时间:2014-08-28 09:25:51

标签: ruby text character-encoding

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

示例:

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

'аnd' == 'and' #=> false

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

'and' == 'and' #=> true

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

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

3 个答案:

答案 0 :(得分:5)

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

第一个字符串的第一个字符不是“普通”a,实际上是U+0430 CYRILLIC SMALL LETTER A - 前两个字节(208和176,或0xD0和{{ 1}} in hex)是此字符的UTF-8编码。它恰好看起来像“普通”拉丁语0xB0,即U+0061 LATIN SMALL LETTER A

这是“正常”a:a,这是西里尔文a:a,它们看起来非常相似。

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

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

另一种选择可能是选择应用程序支持的一组Unicode脚本,并拒绝这些脚本之外的任何字符。您可以使用Ruby的正则表达式脚本支持轻松地检查这一点,例如: gsub将匹配所有西里尔字符。

答案 1 :(得分: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. LATIN SMALL LETTER N
  3. 拉丁文小写字母D
  4. 第二个字符串有3个八位字节:0x61 0x6E 0x64。所有三个八位字节都是Unicode代码点的一个八位字节UTF-8编码。

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

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

    1. LATIN SMALL LETTER A
    2. LATIN SMALL LETTER N
    3. 拉丁文小写字母D
    4. 真的,根本没有问题!两个字符串 不同。使用您使用的字体,西里尔字母看起来与拉丁语a相同,但就Unicode而言,它们是两个不同的字符。 (在不同的字体中,它们甚至可能看起来不同!)从编码或Unicode角度来看,你真的无能为力,因为问题不在于编码或Unicode。

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

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

      1. 西里尔文来自哪里?
      2. 也许意味着是一个西里尔字母a而且应该被视为不等于拉丁语a?
      3. 根据这些问题的答案,您可能要么修复源代码,要么根本不做任何事情。

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

答案 2 :(得分:1)

我认为这是eccoding问题,你可以试试这样。

irb(main):010:0> 'and'.each_byte {|b| puts b}
97
110
100
=> "and"

irb(main):011:0> 'аnd'.each_byte {|b| puts b} #copied and
208
176
110
100
=> "аnd"