2

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-only 解决方案产生

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
4

2 回答 2

1

根本不使用 eval 怎么样?根据聊天中的这条评论,所有必要的只是转义引号、换行符和 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.

于 2013-05-22T16:46:58.147 回答
1

您可以通过正则表达式执行此操作,方法是确保在要转义的字符之前有偶数个反斜杠:

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

…它说:

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