Eval a string without string interpolation

徘徊边缘 提交于 2019-12-08 02:11:17

问题


AKA How do I find an unescaped character sequence with regex?

Given an environment set up with:

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

and given string read in from a file that looks like this:

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

I want to evaluate this as a Ruby string, but without interpolation. Thus, the result should be:

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

By contrast, the eval-only solution produces

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

At first I tried:

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

but this fails in the malicious middle case above, producing:

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

回答1:


You can do this via regex by ensuring that there are an even number of backslashes before the character you want to escape:

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

…which says:

  • Find a character that is not a backslash [^\\]
  • followed by two backslashes (?:\\\\)
    • repeated zero or more times *
  • followed by a literal # character
  • and ensure that after that you can see either a {, @, or $ character.
  • and replace that with
    • the non-backslash-maybe-followed-by-even-number-of-backslashes
    • and then a backslash and then a #



回答2:


How about not using eval at all? As per this comment in chat, all that's necessary are escaping quotes, newlines, and unicode characters. Here's my solution:

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

When called on your string the result is (in your variable environment):

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

Although I would have preferred not to have to treat unicode specially, it is the only way to do it without eval.



来源:https://stackoverflow.com/questions/16695890/eval-a-string-without-string-interpolation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!