在Ruby中逃脱和转换字符串的最佳方法是什么?

jwf*_*arn 27 ruby escaping

Ruby有没有任何内置的转义转义字符串的方法?在过去,我使用正则表达式; 但是,我发现Ruby可能一直在内部进行这样的转换.也许这个功能在某处暴露.

到目前为止,我已经提出了这些功能.他们工作,但他们似乎有点hacky:

def escape(s)
  s.inspect[1..-2]
end

def unescape(s)
  eval %Q{"#{s}"}
end
Run Code Online (Sandbox Code Playgroud)

有没有更好的办法?

Sta*_*yak 16

有一堆转义方法,其中一些:

# Regexp escapings
>> Regexp.escape('\*?{}.')   
=> \\\*\?\{\}\. 
>> URI.escape("test=100%")
=> "test=100%25"
>> CGI.escape("test=100%")
=> "test%3D100%25"
Run Code Online (Sandbox Code Playgroud)

所以,它真的取决于你需要解决的问题.但我会避免使用检查来逃避.

更新 - 有一个转储,检查使用它,它看起来像你需要的:

>> "\n\t".dump
=> "\"\\n\\t\""
Run Code Online (Sandbox Code Playgroud)

  • 我也想避免`检查'.我希望Ruby自己的字符串转义代码可用.类似于`Ruby.escape("\ t")=>"\\ t"和`Ruby.unescape("\\ t")=>"\ t"的东西 (5认同)

ant*_*rez 15

Caleb函数是我能找到的字符串#inspect反向最接近的东西,但它包含两个错误:

  • \\未正确处理.
  • \ x ..保留了反斜杠.

我修复了上面的错误,这是更新版本:

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
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的更新!不过,如果你发表评论,我会修复它。 (2认同)

b4h*_*and 13

更新:我不再同意我自己的答案,但我不想删除它,因为我怀疑其他人可能走错了路,并且已经有很多关于这个答案的讨论,而且它是替代品,所以我认为它仍然有助于对话,但请不要在实际代码中使用此答案.

如果您不想使用eval,但愿意使用该YAML模块,您可以使用它:

require 'yaml'

def unescape(s)
  YAML.load(%Q(---\n"#{s}"\n))
end
Run Code Online (Sandbox Code Playgroud)

以优势YAMLeval是它大概比较安全.cane不允许使用eval.我见过的建议使用$SAFE沿eval,但通过JRuby是不可当前.

对于它的价值,Python确实支持unescaping反斜杠.

  • 谢谢.我接受了你的想法并将其应用于JSON,`JSON.parse("[#{s}]"). (3认同)

the*_*Man 11

Ruby inspect可以帮助:

    "a\nb".inspect
=> "\"a\\nb\""
Run Code Online (Sandbox Code Playgroud)

通常,如果我们打印带有嵌入式换行符的字符串,我们会得到:

puts "a\nb"
a
b
Run Code Online (Sandbox Code Playgroud)

如果我们打印检查版本:

puts "a\nb".inspect
"a\nb"
Run Code Online (Sandbox Code Playgroud)

将检查的版本分配给变量,您将拥有该字符串的转义版本.

要撤消转义,eval字符串:

puts eval("a\nb".inspect)
a
b
Run Code Online (Sandbox Code Playgroud)

我真的不喜欢这样做.这更像是一种好奇心,而不是我在实践中所做的事情.

  • 危险将罗宾逊,危险!如果字符串碰巧是用户输入的话,使用eval来转换字符串是非常危险的!它将允许用户有效地运行任何东西. (4认同)

Cal*_*ton 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
Run Code Online (Sandbox Code Playgroud)


小智 8

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"
Run Code Online (Sandbox Code Playgroud)

用它:

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 \" \\"
Run Code Online (Sandbox Code Playgroud)