如何在Ruby中转义Unicode字符串?

15

我需要将Unicode字符串转换为带反斜杠的转义形式。 有谁知道该怎么做吗?


什么样的Unicode编码?UTF-8吗? - Kelvin
6个回答

26
在Ruby 1.8.x中,String#inspect可能是你要找的东西,例如:
>> multi_byte_str = "hello\330\271!"
=> "hello\330\271!"

>> multi_byte_str.inspect
=> "\"hello\\330\\271!\""

>> puts multi_byte_str.inspect
"hello\330\271!"
=> nil

如果你想在 Ruby 1.9 中对多字节字符进行组件字节转义,你可能需要这么说:

>> multi_byte_str.bytes.to_a.map(&:chr).join.inspect
=> "\"hello\\xD8\\xB9!\""

如果你想获取已转义的unicode码点,无论是在Ruby 1.8还是1.9中,你都可以使用这种方法(尽管它也会转义可打印的内容):

>> multi_byte_str.unpack('U*').map{ |i| "\\u" + i.to_s(16).rjust(4, '0') }.join
=> "\\u0068\\u0065\\u006c\\u006c\\u006f\\u0639\\u0021"

这真的非常有帮助!我本来要自己写,但这节省了我的时间。你的代码构成优雅,先生。我用它来编码一些提示,为我在Codepen上制作的CSS教程,这样用户在将其解析为JSON之前是看不到它们的!快去看看吧!http://cdpn.io/oznaH - Steve Benner
我点赞了这个答案,因为其中的一些部分对我很有帮助,但值得指出的是,#inspect并不总是能给你所需的结果。#dump应该可以解决问题。另外,请参考一个新的回答,我感到很有灵感写下了它。 - lindes
1
这会在U+FFFF以上的代码点上中断,例如U+1F92E,语法应该是"\u{1f92e}"而不是"\u1f92e"(这会得到ᾒe)。 - Shelvacu

15

7
针对 Ruby 1.8 版本,您可以使用 ["XXXX".to_i(16)].pack("U*") 这行代码。该代码的作用是将十六进制字符串"XXXX"转为整数后,再打包成 Unicode 字符。 - Dave
1
@Trejkaz:我有同样的问题。链接的文档实际上展示了一个例子:在代码周围使用 {},例如 \u{1f60d} 表达了我发现如何表达这些事情的感觉。:D - lindes
2
@lindes 是的,值得注意的是,pack函数也适用于["1f60d".to_i(16)].pack("U*")。这一点并不是显而易见的。 :) - Hakanai
啊,是的。这样做很有道理,因为它只获取整数。所以这里的关键是,@Dave评论中的“XXXX”并没有被限制为4位数字(可能更少或更多),而这个答案中的“XXXX”则是。 - lindes
请注意,在 Ruby 中,与其他逃逸字符一样,这仅适用于双引号字符串,而不适用于单引号字符串。(https://ruby-doc.org/core-2.0.0/doc/syntax/literals_rdoc.html#label-Strings) - Jon Schneider

10
如果您有Rails,您可以使用JSON编码器来实现此功能:
require 'active_support'
x = ActiveSupport::JSON.encode('µ')
# x is now "\u00b5"

通常的非Rails JSON编码器不会将Unicode转换为"\u"。


5
我理解您的问题有两个部分:找到字符的数值和在Ruby中将这些值表示为转义序列。此外,前者取决于您的起点。

查找数值:

方法1a:使用String#dump在Ruby中:

如果您已经将字符存储在 Ruby String 对象中(或者可以轻松地将其放入其中),则只需在 repl 中显示字符串即可(取决于您的 Ruby 环境中 特定设置)。如果没有,您可以调用 #dump 方法。例如,有一个名为 unicode.txt 的文件,其中包含一些 UTF-8 编码的数据 - 比如货币符号 €£¥$(加上换行符) - 运行以下代码(在 irb 中执行或作为脚本执行):
s = File.read("unicode.txt", :encoding => "utf-8") # this may be enough, from irb
puts s.dump # this will definitely do it.

...应该打印出:

"\u20AC\u00A3\u00A5$\n"

因此,您可以看到U+20AC£U+00A3¥U+00A5$未转换,因为它是纯ASCII,尽管技术上它是U+0024。如果您确实需要该信息,则可以修改下面的代码。或者只需在ASCII表中添加前导零 - 或引用已经这样做的表格。) (注:上一个回答建议使用#inspect而非#dump。这种方法有时有效,但并非总是如此。例如,对于我来说,运行ruby -E UTF-8 -e 'puts "\u{1F61E}".inspect'会打印出不高兴的脸,而不是转义序列。然而,将inspect更改为dump可以使我重新获得转义序列。)

方法1b:使用Ruby的String#encoderescue

现在,如果您正在尝试对较大的输入文件进行上述操作,则以上内容可能会变得难以处理-在大多数ASCII文本中查找转义序列可能很困难,或者很难确定哪些序列与哪些字符相对应。在这种情况下,可以将上面的第二行替换为以下内容:

encodings = {} # hash to store mappings in
s.split("").each do |c| # loop through each "character"
  begin
    c.encode("ASCII") # try to encode it to ASCII
  rescue Encoding::UndefinedConversionError # but if that fails
    encodings[c] = $!.error_char.dump # capture a dump, mapped to the source character
  end
end
# And then print out all the captured non-ASCII characters:
encodings.each do |char, dumped|
  puts "#{char} encodes to #{dumped}."
end

使用与上述相同的输入,这将打印出:
€ encodes to "\u20AC".
£ encodes to "\u00A3".
¥ encodes to "\u00A5".

请注意,这可能会有些误导。如果输入中存在组合字符,输出将单独打印每个组成部分。例如,对于输入 ў ў,输出将是:
 encodes to "\u{1F64B}".
 encodes to "\u{1F3FE}".
ў encodes to "\u045E".
у encodes to "\u0443".                                                                                                      ̆
 encodes to "\u0306".

这是因为实际上被编码为两个码点:一个基本字符(- U+1F64B),带有一个修饰符(, U+1F3FE; 参见)。同样的,对于其中之一的字母:ў是单个预组合码点(U+045E),而第二个字母ў - 尽管看起来相同 - 是通过将у(U+0443)与修饰符 ̆(U+0306)组合而成的,这可能无法正确呈现,包括在此页面上,因为它不是独立存在的。所以根据你的需求,你可能需要注意这些问题(我把它留给读者作为练习)。

方法二a:使用基于Web的工具:特定字符:

或者,如果您有一封包含字符的电子邮件,并且您想查找编码的代码点值,如果您简单地搜索该字符,您通常会找到许多页面,其中列出了特定字符的unicode详细信息。例如,如果我做一个对进行谷歌搜索, 我会得到,除其他外,一个wiktionary词条, 一个wikipedia页面关于fileformat.info的页面,我发现这是一个获取特定unicode字符详细信息的有用网站。每个页面都列出了该勾选标记由unicode代码点U+2713表示的事实。(顺便说一句,在那个方向上搜索也很有效。)

方法2b:通过名称/概念从基于Web的工具获取:

同样地,可以搜索Unicode符号以匹配特定概念。例如,我以上搜索unicode check marks,即使在Google片段中也有几个代码点及其对应的图形列表,尽管我还发现了this list包含几个勾号符号,甚至有一个"list of useful symbols",其中包括各种勾号。

这同样适用于重音字符、表情符号等。只需搜索单词"unicode"以及您要查找的任何其他内容,您将倾向于获得包括列出代码点的页面的结果。然后,我们将把它放回到Ruby中:


一旦你掌握了价值,如何表达它:

Ruby字符串字面量文档介绍了两种将Unicode字符表示为转义序列的方法:

\unnnn 表示Unicode字符,其中nnnn是4个十六进制数字([0-9a-fA-F])

\u{nnnn ...} 表示Unicode字符,每个nnnn都是1-6个十六进制数字([0-9a-fA-F])

对于具有4位表示的码点,例如上面的U+2713,您可以将其输入为\u2713(在字符串文字中,该文字用单引号)。对于任何Unicode字符(无论是否适合4位数),您都可以使用大括号({})括起来的完整十六进制值来编码代码点,例如\u{1f60d}表示。此形式还可用于在单个转义序列中编码多个代码点,使用空格分隔字符。例如,\u{1F64B 1F3FE}会产生基本字符和修饰符 ,从而最终生成抽象字符(如上所示)。
这也适用于较短的代码点。例如,上面的货币字符字符串(€£¥$)可以用\u{20AC A3 A5 24}表示 - 对于其中三个字符仅需要2个数字。

3

如果在文件的顶部添加#Encoding: UTF-8,则可以直接使用unicode字符。然后您可以在源代码中自由地使用ä,ǹ,ú等字符。


-3

2
这是你自己的存储库(或者你是主要贡献者之一)。你没有透露这一点。所以基本上它是垃圾信息。并且它没有回答问题。 - David Makogon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接