Ruby是否有内置方法来转义和反转义字符串?过去,我使用正则表达式实现此功能;然而,我认为Ruby可能一直在内部执行此类转换。也许这个功能被某个地方公开了。
到目前为止,我已经想出了以下这些函数。它们能够工作,但看起来有点不正规:
def escape(s)
s.inspect[1..-2]
end
def unescape(s)
eval %Q{"#{s}"}
end
有更好的方法吗?
Ruby是否有内置方法来转义和反转义字符串?过去,我使用正则表达式实现此功能;然而,我认为Ruby可能一直在内部执行此类转换。也许这个功能被某个地方公开了。
到目前为止,我已经想出了以下这些函数。它们能够工作,但看起来有点不正规:
def escape(s)
s.inspect[1..-2]
end
def unescape(s)
eval %Q{"#{s}"}
end
有更好的方法吗?
Ruby 2.5新增了String#undump
方法,作为String#dump
方法的补充:
$ irb
irb(main):001:0> dumped_newline = "\n".dump
=> "\"\\n\""
irb(main):002:0> undumped_newline = dumped_newline.undump
=> "\n"
使用它:
def escape(s)
s.dump[1..-2]
end
def unescape(s)
"\"#{s}\"".undump
end
$irb
irb(main):001:0> escape("\n \" \\")
=> "\\n \\\" \\\\"
irb(main):002:0> unescape("\\n \\\" \\\\")
=> "\n \" \\"
有很多转义方法,其中一些如下:
# Regexp escapings
>> Regexp.escape('\*?{}.')
=> \\\*\?\{\}\.
>> URI.escape("test=100%")
=> "test=100%25"
>> CGI.escape("test=100%")
=> "test%3D100%25"
所以,这取决于您需要解决的问题。但我建议避免使用inspect进行转义。
更新-有一个转储,inspect使用它,看起来这就是您需要的:
>> "\n\t".dump
=> "\"\\n\\t\""
inspect
。我希望能够使用 Ruby 自己的字符串转义代码。例如 Ruby.escape("\t") => "\\t"
和 Ruby.unescape("\\t") => "\t"
。 - jwfearnCaleb函数是我能找到的最接近反向String#inspect的东西,不过它包含两个错误:
我已经修复了上述错误,这是更新后的版本:
UNESCAPES = {
'a' => "\x07", 'b' => "\x08", 't' => "\x09",
'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c",
'r' => "\x0d", 'e' => "\x1b", "\\\\" => "\x5c",
"\"" => "\x22", "'" => "\x27"
}
def unescape(str)
# Escape all the things
str.gsub(/\\(?:([#{UNESCAPES.keys.join}])|u([\da-fA-F]{4}))|\\0?x([\da-fA-F]{2})/) {
if $1
if $1 == '\\' then '\\' else UNESCAPES[$1] end
elsif $2 # escape \u0000 unicode
["#$2".hex].pack('U*')
elsif $3 # escape \0xff or \xff
[$3].pack('H2')
end
}
end
# To test it
while true
line = STDIN.gets
puts unescape(line)
end
"\n"
代替"\x0a"
。我认为这更清晰明了。 - rigon更新:我不再同意我的回答,但我宁愿不删除它,因为我怀疑其他人可能会走上这条错误的道路,并且对这个答案及其替代方案已经进行了很多讨论,所以我认为它仍然对对话做出了贡献,但请不要在实际代码中使用这个答案。
如果您不想使用eval
,但愿意使用YAML
模块,您可以使用它来代替:
require 'yaml'
def unescape(s)
YAML.load(%Q(---\n"#{s}"\n))
end
YAML
相对于 eval
的优势在于其更安全,cane
禁止所有使用 eval
的方法。我曾经看到建议使用 $SAFE
和 eval
,但目前 JRuby 不支持该功能。JSON.parse("[#{s}]").first
。 - akuhn可以使用 Ruby 的 inspect
方法:
"a\nb".inspect
=> "\"a\\nb\""
通常情况下,如果我们打印一个包含换行符的字符串,会得到如下输出:
puts "a\nb"
a
b
如果我们打印检查的版本:
puts "a\nb".inspect
"a\nb"
将检查后的版本分配给一个变量,您将获得字符串的转义版本。
要撤消转义,请使用eval
函数对字符串进行求值:
puts eval("a\nb".inspect)
a
b
我不是很喜欢这么做,这更像是我的好奇心,而不是我实践中会使用的方法。YAML的::unescape
似乎不会转义引号字符,例如'
和"
。我猜这是设计上的考虑,但这让我感到难过。
绝对不要在任意或由客户提供的数据上使用eval
。
这是我使用的方法。处理了我所看到的一切,并且不会引入任何依赖项。
UNESCAPES = {
'a' => "\x07", 'b' => "\x08", 't' => "\x09",
'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c",
'r' => "\x0d", 'e' => "\x1b", "\\\\" => "\x5c",
"\"" => "\x22", "'" => "\x27"
}
def unescape(str)
# Escape all the things
str.gsub(/\\(?:([#{UNESCAPES.keys.join}])|u([\da-fA-F]{4}))|\\0?x([\da-fA-F]{2})/) {
if $1
if $1 == '\\' then '\\' else UNESCAPES[$1] end
elsif $2 # escape \u0000 unicode
["#$2".hex].pack('U*')
elsif $3 # escape \0xff or \xff
[$3].pack('H2')
end
}
end
"\u{12345}"
类型编码,我在正则表达式中添加了|u{([\da-fA-F]+)}
,例如/\\(?:([#{keys}])|u([\da-fA-F]{4})|u{([\da-fA-F]+)})|\\0?x([\da-fA-F]{2})/
,将$3
引用更改为$4
,并在$2和$4部分之间插入了elsif $3; ["#$3".hex].pack('U*')
。 - Grant NeufeldShellwords.escape
可以完成您所需的功能。
https://ruby-doc.org/stdlib-1.9.3/libdoc/shellwords/rdoc/Shellwords.html#method-c-shellescape 可以提供更多信息。