西里尔字符串 Я̆ Я̄ Я̈ return 长度为 2 而不是 ruby 和其他编程语言中的 1
cyrillic strings Я̆ Я̄ Я̈ return length 2 instead of 1 in ruby and other programming languages
在 Ruby、Javascript 和 Java(其他我没试过)中,有西里尔字符 Я̆ Я̄ Я̈ 长度 2。当我尝试检查字符串的长度时有了这些字符,我得到了错误的输出值。
"Я̈".mb_chars.length
#=> 2 #should be 1 (ruby on rails)
"Я̆".length
#=> 2 #should be 1 (ruby, javascript)
"Ӭ".length
#=> 1 #correct (ruby, javascript)
请注意,字符串以 UTF-8 编码,每个字符都表现为单个字符。
我的问题是为什么会有这样的行为,我怎样才能正确地得到带有这些字符的字符串的长度?
潜在的问题是 Я̈
实际上是两个代码点:Я
和变音符号是分开的:
'Я̈'.chars
#=> ["Я", "̈"]
通常你会通过 unicode 规范化来解决这类问题,但单凭这一点对你没有帮助,因为 Я̈
或 Я̆
没有单一代码点(但有Ӭ
).
您可以在检查长度之前去除变音符号:
'Я̆'.gsub(/\p{Diacritic}/, '')
#=> "Я"
'Я̆'.gsub(/\p{Diacritic}/, '').length
#=> 1
您将获得所需的长度,但字符串不会完全相同。这也适用于 Ӭ
之类的东西,它可以用一个代码点表示:
'Ӭ'.length
#=> 1
'Ӭ'.gsub(/\p{Diacritic}/, '')
#=> "Ӭ"
'Ӭ'.gsub(/\p{Diacritic}/, '').length
#=> 1
Unicode 很棒,很棒,解决了很多曾经困扰我们的问题。不幸的是,Unicode 也很可怕和复杂,因为人类语言和字形并不是完全设计出来的。
Ruby 2.5 添加 String#each_grapheme_cluster
:
'Я̆Я̄Я̈'.each_grapheme_cluster.to_a #=> ["Я̆", "Я̄", "Я̈"]
'Я̆Я̄Я̈'.each_grapheme_cluster.count #=> 3
请注意,您不能使用等同于 each_char.size
的 each_grapheme_cluster.size
,因此在上例中两者都将 return 6
。 (这看起来像是一个错误,我刚刚提交了一个 bug report)
尝试 unicode-display_width,它是为给出这个问题的准确答案而构建的:
require "unicode/display_width"
Unicode::DisplayWidth.of "Я̈" #=> 1
在 Ruby、Javascript 和 Java(其他我没试过)中,有西里尔字符 Я̆ Я̄ Я̈ 长度 2。当我尝试检查字符串的长度时有了这些字符,我得到了错误的输出值。
"Я̈".mb_chars.length
#=> 2 #should be 1 (ruby on rails)
"Я̆".length
#=> 2 #should be 1 (ruby, javascript)
"Ӭ".length
#=> 1 #correct (ruby, javascript)
请注意,字符串以 UTF-8 编码,每个字符都表现为单个字符。
我的问题是为什么会有这样的行为,我怎样才能正确地得到带有这些字符的字符串的长度?
潜在的问题是 Я̈
实际上是两个代码点:Я
和变音符号是分开的:
'Я̈'.chars
#=> ["Я", "̈"]
通常你会通过 unicode 规范化来解决这类问题,但单凭这一点对你没有帮助,因为 Я̈
或 Я̆
没有单一代码点(但有Ӭ
).
您可以在检查长度之前去除变音符号:
'Я̆'.gsub(/\p{Diacritic}/, '')
#=> "Я"
'Я̆'.gsub(/\p{Diacritic}/, '').length
#=> 1
您将获得所需的长度,但字符串不会完全相同。这也适用于 Ӭ
之类的东西,它可以用一个代码点表示:
'Ӭ'.length
#=> 1
'Ӭ'.gsub(/\p{Diacritic}/, '')
#=> "Ӭ"
'Ӭ'.gsub(/\p{Diacritic}/, '').length
#=> 1
Unicode 很棒,很棒,解决了很多曾经困扰我们的问题。不幸的是,Unicode 也很可怕和复杂,因为人类语言和字形并不是完全设计出来的。
Ruby 2.5 添加 String#each_grapheme_cluster
:
'Я̆Я̄Я̈'.each_grapheme_cluster.to_a #=> ["Я̆", "Я̄", "Я̈"]
'Я̆Я̄Я̈'.each_grapheme_cluster.count #=> 3
请注意,您不能使用等同于 each_char.size
的 each_grapheme_cluster.size
,因此在上例中两者都将 return 6
。 (这看起来像是一个错误,我刚刚提交了一个 bug report)
尝试 unicode-display_width,它是为给出这个问题的准确答案而构建的:
require "unicode/display_width"
Unicode::DisplayWidth.of "Я̈" #=> 1