计算Unicode字符串长度而不组合标记

时间:2012-04-05 01:41:44

标签: ruby unicode

考虑以下Ruby代码分析三字节UTF-8字符串:

#encoding: utf-8
s = "\x65\xCC\x81"
p [s.bytesize, s.length, s, s.encoding.name]
#=> [3, 2, "é", "UTF-8"]

如上所述[{3}},上面的 是一个双字符的字符串:拉丁文小写e后跟on this page of mine。但是,它看起来像一个字符,这在布局固定宽度显示时很重要。

例如,查看Combining Acute Accent上“moiré.svg”的两个条目,并注意其中一个条目如何搞乱列对齐。

如何计算Ruby中字符串的“等宽视觉长度”,它不包含任何零宽度组合字符? (一种有效的技术可能是将Unicode字符串转换为其规范表示的方法,将上述内容转换为"\xC3\xA9",其中é看起来像length1 {{1}} 。)

3 个答案:

答案 0 :(得分:5)

unicode_utils gem可能有所帮助:

http://unicode-utils.rubyforge.org/UnicodeUtils.html

char_display_width方法:

require "unicode_utils/char_display_width"
UnicodeUtils.char_display_width("別")  # => 2
UnicodeUtils.char_display_width(0x308) # => 0
UnicodeUtils.char_display_width("a")   # => 1

有一个字符串display_width方法:

require "unicode_utils/display_width"
UnicodeUtils.display_width("別れ") => 4
UnicodeUtils.display_width("12") => 2
UnicodeUtils.display_width("a\u{308}") => 1

另请参阅each_grapheme

(感谢Michael Anderson指出了其他方法)

答案 1 :(得分:1)

您可以使用正则表达式来获取Unicode属性:

s = "\x65\xCC\x81"
count = s.each_char.inject(0) do |c, char|
  c += 1 unless char=~/\p{Mn}/
  c
end

puts count #=> 1

这适用于这种情况,但您必须确定要在更强大的解决方案中排除哪些属性。

使用@joelparkerhenderson's answer中建议的unicode_utils gem可能是更好的选择,但我想我会将其包含在内以保证完整性。

答案 2 :(得分:-1)

我远不是Ruby的专家,但是this给出了以下内容:

def length_utf8
  count = 0
  scan(/./mu) { count += 1 }
  count
end