Ruby是否有任何内置方法可以转义和 unescaping字符串?在过去,我使用正则表达式;但是,我发现Ruby可能一直在内部进行这样的转换。也许这个功能在某个地方暴露出来。
到目前为止,我已经提出了这些功能。他们工作,但他们似乎有点hacky:
def escape(s)
s.inspect[1..-2]
end
def unescape(s)
eval %Q{"#{s}"}
end
有更好的方法吗?
答案 0 :(得分:15)
有一堆逃避方法,其中一些:
# Regexp escapings
>> Regexp.escape('\*?{}.')
=> \\\*\?\{\}\.
>> URI.escape("test=100%")
=> "test=100%25"
>> CGI.escape("test=100%")
=> "test%3D100%25"
所以,它真的取决于你需要解决的问题。但我会避免使用inspect来逃避。
更新 - 有一个转储,检查使用它,它看起来就像你需要的那样:
>> "\n\t".dump
=> "\"\\n\\t\""
答案 1 :(得分:15)
Caleb函数是我能找到的字符串#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
答案 2 :(得分:12)
更新:我不再同意我自己的答案,但我不想删除它,因为我怀疑其他人可能会走错路,而且已经有很多讨论了这个答案和它的替代方案,所以我认为它仍然有助于对话,但请不要在实际代码中使用这个答案。
如果您不想使用eval
,但愿意使用YAML
模块,则可以使用它:
require 'yaml'
def unescape(s)
YAML.load(%Q(---\n"#{s}"\n))
end
YAML
优于eval
的优势在于它可能更安全。 cane
不允许eval
的所有使用。我已经看到了使用$SAFE
和eval
的建议,但目前无法通过JRuby使用。
对于它的价值,Python确实支持unescaping backslashes。
答案 3 :(得分:11)
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
我真的不喜欢这样做。这更像是一种好奇心,而不是我在实践中所做的事情。
答案 4 :(得分:10)
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
答案 5 :(得分:7)
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 \" \\"
答案 6 :(得分:4)
我怀疑Shellwords.escape
会做你正在寻找的事情
https://ruby-doc.org/stdlib-1.9.3/libdoc/shellwords/rdoc/Shellwords.html#method-c-shellescape