我标记了字符编码和文本,因为我知道如果你在rails控制台中输入'and' == 'and'
,或者大多数其他编程语言,你会得到true
。但是,当我的一位用户将他的文字粘贴到我的网站时,我遇到了问题,我无法通过copyscape拼写检查或通过copyscape验证它的原创性,因为文本有些问题。 (或者我对文本编码的理解?)
示例:
如果您将以下行复制并粘贴到rails控制台,您将获得false
。
'аnd' == 'and' #=> false
如果您将以下行复制并粘贴到rails控制台中,即使它们在浏览器中看起来完全相同,也会得到true
。
'and' == 'and' #=> true
不同之处在于,在第一个示例中,第一个'аnd'
被复制并粘贴到导致问题的用户文本中。 'and'
的所有其他实例都输入到浏览器中。
这是编码问题吗? 如何解决我的问题?
答案 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
。
这三个代码点解析为以下三个字符:
第二个字符串有3个八位字节:0x61 0x6E 0x64
。所有三个八位字节都是Unicode代码点的一个八位字节UTF-8编码。
因此,该字符串由三个Unicode代码点组成:U+0061 U+006E U+0064
。
这三个代码点解析为以下三个字符:
真的,根本没有问题!两个字符串 不同。使用您使用的字体,西里尔字母看起来与拉丁语a相同,但就Unicode而言,它们是两个不同的字符。 (在不同的字体中,它们甚至可能看起来不同!)从编码或Unicode角度来看,你真的无能为力,因为问题不在于编码或Unicode。
这称为homoglyph,两个字符不同但具有相同(或非常相似)的字形。
你可以尝试做的是将所有字符串音译成拉丁语(前提是你可以保证没有人想要输入非拉丁字符),但实际上,问题是:
根据这些问题的答案,您可能要么修复源代码,要么根本不做任何事情。
对于浏览器供应商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"