Ruby中将Unicode转纯ASCII的无gem兼容方案(适配Ruby 2.x)
Unicode转纯ASCII(兼容Ruby 2.x)
问题场景
需要将一段特殊Unicode字符串转换为纯ASCII格式,示例字符串:
t = "\xf0\x9d\x97\x94\xf0\x9d\x98\x82\xf0\x9d\x97\xb4\xf0\x9d\x98\x82\xf0\x9d\x98\x80\xf0\x9d\x98\x81"
直接使用encode方法无法得到有效结果:
t.encode('ASCII', invalid: :replace, undef: :replace, replace: '') => ""
Ruby 2.2+版本可用unicode_normalize(:nfkd)得到正确结果"August",但需兼容Ruby 2.1及更早版本(无String#unicode_normalize方法),且不能依赖第三方gem。
兼容实现方案
以下是完全基于Ruby内置功能的实现,无需额外依赖:
def unicode_to_ascii(str) str.chars.map do |char| code = char.ord # 处理数学风格Unicode字母(U+1D400-U+1D7FF范围) if code >= 0x1D400 && code <= 0x1D7FF # 大写数学字母映射:U+1D400对应ASCII A(65) if code.between?(0x1D400, 0x1D433) (code - 0x1D400 + 65).chr # 小写数学字母映射:U+1D41A对应ASCII a(97) elsif code.between?(0x1D41A, 0x1D44D) (code - 0x1D41A + 97).chr else '' end else # 兼容不同Ruby版本的字符分解处理 if String.method_defined?(:unicode_normalize) # Ruby 2.2+使用NFKD分解后过滤非ASCII字符 char.unicode_normalize(:nfkd).gsub(/[^\x00-\x7F]/, '') else # Ruby 2.1及以下直接保留可打印ASCII字符 char.match?(/[\x00-\x7F]/) ? char : '' end end end.join end # 测试示例 t = "\xf0\x9d\x97\x94\xf0\x9d\x98\x82\xf0\x9d\x97\xb4\xf0\x9d\x98\x82\xf0\x9d\x98\x80\xf0\x9d\x98\x81" puts unicode_to_ascii(t) # 输出 "August"
方案说明
- 针对示例中的数学风格Unicode字母,直接通过编码点偏移映射到对应ASCII字母,无需依赖归一化方法。
- 对其他字符,根据Ruby版本自动适配:Ruby 2.2+利用内置
unicode_normalize(:nfkd)分解字符后过滤非ASCII内容;Ruby 2.1及以下直接保留ASCII范围内的字符。 - 全程使用Ruby内置API,不依赖任何第三方gem,完美兼容Ruby 2.x全版本。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

