0

我有一个表格,我在其中放入带有正则表达式值的散列。我的问题是,当从我的视野出发,通过我的控制器并使用 Mongoid 进入 MongoDB 时,它们会变得一团糟。如何保留正则表达式?

输入示例:

{:regex1 => "^Something \(#\d*\)$"}
{:regex2 => "\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z"}

我的表单视图表单如下所示:

= semantic_form_for resource, :html => {:class => "form-vertical"} do |r|
  = r.inputs do
    = r.input :value, :as => :text
  = r.actions do
    = r.action :submit

我的控制器创建操作接受参数并像这样处理它:

class EmailTypesController < InheritedResources::Base

  def create
    puts params[:email_type][:value]          # =>  {:regex1 => "^Something \(#\d*\)$"} and
                                              #     {:regex2 => "\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z"}
    puts params[:email_type][:value].inspect  # =>  "{:regex1 => \"^Something \\(#\\d*\\)$\"}" and
                                              #     "{:regex2 => \"\\A[\\w+\\-.]+@[a-z\\d\\-.]+\\.[a-z]+\\z\"}"

    params[:email_type][:value] = convert_to_hash(params[:email_type][:value])

    puts params[:email_type][:value]          # =>  {"regex1"=>"^Something (#d*)$"} and
                                              #     {"regex2"=>"A[w+-.]+@[a-zd-.]+.[a-z]+z"}
    create! do |success, failure|

      success.html {
        redirect_to resource
      }

      failure.html {
        render :action => :new
      }
    end    
  end

  def convert_to_hash(string)
    if string.match(/(.*?)=>(.*)\n*/)
      string = eval(string)
    else
      string = string_to_hash(string)
    end
  end

  def string_to_hash(string)
    values = string.split("\r\n")
    output = {}
    values.each do |v|
      val = v.split("=")
      output[val[0].to_sym] = val[1]
    end
    output
  end
end

启动控制台并检查通过 Mongoid 输入的值:

Loading development environment (Rails 3.2.12)
1.9.3p385 :001 > EmailType.all.each do |email_type|
1.9.3p385 :002 >     puts email_type.value
1.9.3p385 :003?>   end
{"regex1"=>"^Something (#d*)$"}
{"regex2"=>"A[w+-.]+@[a-zd-.]+.[a-z]+z"}
 => true 
1.9.3p385 :004 > 
4

1 回答 1

1

问题在于 ruby​​ 对字符串的评估,它忽略了无用的转义:

puts "^Something \(#\d*\)$".inspect
=>"^Something (#d*)$"

也就是说 eval 只是忽略了反斜杠。请注意,通常在 ruby​​ 中,正则表达式不是使用字符串创建的,而是通过它们自己的正则表达式文字创建的,因此

/^Something \(#\d*\)$/.inspect
=>"/^Something \\(#\\d*\\)$/"

注意双反斜杠而不是单反斜杠。这意味着 eval 必须在字符串中接收两个反斜杠而不是一个,因为它必须被评估为单个反斜杠字符。

一种快速简便的方法是在 convert_to_hash 调用之前简单地运行 sub ob 字符串:

# A little confusing due to escapes, but single backslashes are replaced with double.
# The second parameter is confusing, but it appears that String#sub requires a few
# extra escapes due to backslashes also being used to backreference.
# i.e. \n is replaced with the nth regex group, so to replace something with the string
# "\n" yet another escape for backslash is required, so "\\n" is replaced with "\n".
# Therefore the input of 8 blackslashes is eval'd to a string of 4 backslashes, which
# sub interprets as 2 backslashes.
params[:email_type][:value].gsub!('\\', '\\\\\\\\')

这应该不是问题,除非您在某个时候在哈希键中使用反斜杠,在这种情况下,需要更高级的匹配来仅提取正则表达式并对其执行替换。

于 2013-05-02T14:39:43.037 回答