加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Ruby,比较字符串与UTF-8字符的问题

发布时间:2020-12-16 23:24:11 所属栏目:百科 来源:网络整理
导读:我有这两个UTF-8字符串: a = "Nu01b0u0303"b = "Nu1eef" 它们看起来很不一样,但渲染后它们是相同的: irb(main):039:0 puts "#{a} - #{b}"N?? - N? a版本是我存储在DB中的版本. b版本是一个来自浏览器的POST请求,我不知道为什么浏览器会发送不同的UTF8字
我有这两个UTF-8字符串:
a = "Nu01b0u0303"
b = "Nu1eef"

它们看起来很不一样,但渲染后它们是相同的:

irb(main):039:0> puts "#{a} - #{b}"
N?? - N?

a版本是我存储在DB中的版本. b版本是一个来自浏览器的POST请求,我不知道为什么浏览器会发送不同的UTF8字符组合,而且它总是不会发生,我无法在我的开发中重现这个问题环境,它发生在生产中,占总请求的百分比.

情况是我尝试比较它们但是它们返回false:

irb(main):035:0> a == b
=> false

我尝试过强制编码等不同的东西:

irb(main):022:0> c.force_encoding("UTF-8") == a.force_encoding("UTF-8")
=> false

另一个有趣的事实是:

irb(main):005:0> a.chars
=> ["N","?","?"]
irb(main):006:0> b.chars
=> ["N","?"]

我该如何比较这些字符串?

解决方法

这是 Unicode equivalence的问题.

你的字符串的一个版本由字符?(U 01B0:LATIN SMALL LETTER U WITH HORN)组成,然后是U 0303 COMBINING TILDE.第二个字符,顾名思义是combining character,当渲染时与前一个字符组合以产生最终字形.

字符串的b版本使用字符?(U 1EEF,LATIN SMALL LETTER U WITH HORN和TILDE),它是单个字符,并且等同于之前的组合,但使用不同的字节序列来表示它.

为了比较这些字符串,您需要对它们进行标准化,以便它们对这些类型的字符使用相同的字节序列.当前版本的Ruby内置了此功能(在早期版本中,您需要使用第三方库).

所以目前你有

a == b

这是假的,但如果你这样做

a.unicode_normalize == b.unicode_normalize

你应该成真.

如果您使用的是旧版本的Ruby,则有几种选择. Rails有一个normalize方法作为其多字节支持的一部分,所以如果你使用Rails,你可以这样做:

a.mb_chars.normalize == b.mb_chars.normalize

或者类似的东西:

ActiveSupport::Multibyte::Unicode.normalize(a) == ActiveSupport::Multibyte::Unicode.normalize(b)

如果您不使用Rails,那么您可以查看unicode_utils gem,并执行以下操作:

UnicodeUtils.nfkc(a) == UnicodeUtils.nfkc(b)

(nfkc指的是规范化形式,它与其他技术中的默认形式相同.)

有各种不同的方法来规范化unicode字符串(即你是使用分解版本还是组合版本),这个例子只使用默认值.我会留下研究差异给你.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读