Eval没有字符串插值的字符串

时间:2013-05-22 15:32:44

标签: ruby regex eval

AKA如何使用正则表达式找到未转义的字符序列?

给定环境设置:

@secret = "OH NO!"
$secret = "OH NO!"
@@secret = "OH NO!"

并从一个看起来像这样的文件中读取字符串:

some_str = '"\"#{:NOT&&:very}\" bad. \u262E\n#@secret \\#$secret \\\\#@@secret"'

我想将此评估为Ruby字符串,但没有插值。因此,结果应该是:

puts safe_eval(some_str)
#=> "#{:NOT&&:very}" bad. ☮
#=> #@secret #$secret \#@@secret

相比之下,eval - 仅解决方案产生

puts eval(some_str)
#=> "very" bad. ☮
#=> OH NO! #$secret \OH NO!

起初我试过了:

def safe_eval(str)
  eval str.gsub(/#(?=[{@$])/,'\\#')
end

但是在上面的恶意中间案例中失败了,产生了:

#=> "#{:NOT&&:very}" bad. ☮
#=> #@secret \OH NO! \#@@secret

2 个答案:

答案 0 :(得分:1)

你可以通过regex来做到这一点,确保在你想要逃脱的角色之前有一个偶数个反斜杠:

def safe_eval(str)
  eval str.gsub( /([^\\](?:\\\\)*)#(?=[{@$])/, '\1\#' )
end

...说:

  • 找一个不是反斜杠的字符[^\\]
  • 后跟两个反斜杠(?:\\\\)
    • 重复零次或多次*
  • 后跟文字#字符
  • 并确保在此之后您可以看到{@$字符。
  • 并将其替换为
    • 非反斜杠 - 可能跟随偶数个反斜杠
    • 然后是反斜杠,然后是#

答案 1 :(得分:1)

根本不使用eval怎么样?根据聊天中的this评论,所有必要的内容都是转义引号,换行符和unicode字符。这是我的解决方案:

ESCAPE_TABLE = {
  /\\n/ => "\n",
  /\\"/ => "\"",
}
def expand_escapes(str)
  str = str.dup
  ESCAPE_TABLE.each {|k, v| str.gsub!(k, v)}
  #Deal with Unicode
  str.gsub!(/\\u([0-9A-Z]{4})/) {|m| [m[2..5].hex].pack("U") }
  str
end

当你的字符串被调用时,结果是(在你的变量环境中):

"\"\"\#{:NOT&&:very}\" bad. ☮\n\#@secret \\\#$secret \\\\\#@@secret\""

虽然我宁愿不必特别处理unicode,但这是唯一不用eval的方法。