如何迭代 Crystal 中的字素簇?

How to iterate over grapheme clusters in Crystal?

Unicode 标准将 grapheme cluster 定义为“用户感知字符”的算法近似值。字素簇或多或少对应于人们认为的文本中的单个“字符”。因此,在编程中能够将字符串作为字素簇序列进行操作是一个自然而重要的要求。

最好的通用字素簇定义是扩展字素簇;还有其他字素聚类算法(定制的字素聚类)用于特定的本地化用法。

在 Crystal 中,我如何迭代(或以其他方式操作)作为字素簇序列的 String

此答案基于 Crystal forum.

中的一个话题

Crystal 从 1.0.0 开始没有内置的方法来执行此操作(不幸的是)。

但是,Crystal 中的 regex 引擎可以,\X 模式匹配单个扩展字素簇:

"\u0067\u0308\u1100\u1161\u11A8".scan(/\X/) do |match|
  grapheme = match[0]
  puts grapheme
end

# Output:
# g̈
# 각

Run it online

您可以将其包装成更好的API,如下所示:

def each_grapheme(s : String, &)
  s.scan(/\X/) do |match|
    yield match[0]
  end
end

def graphemes(s : String) : Array(String)
  result = Array(String).new
  each_grapheme(s) do |g|
    result << g
  end
  return result
end

# Example from https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html
s = "\u{E9}\u{65}\u{301}\u{D55C}\u{1112}\u{1161}\u{11AB}"
each_grapheme(s) do |g|
  puts "#{g}\t#{g.codepoints}"
end

# Output:
# é [233]
# é    [101, 769]
# 한 [54620]
# 한   [4370, 4449, 4523]

Run it online