2

我需要使用 ActiveRecord 在数据库表中存储与其他字段相关的正则表达式。

我在 Regexp 类中找到了to_s方法,该方法指出

返回包含正则表达式及其选项的字符串(使用 (?opts:source) 表示法。此字符串可以反馈到 Regexp::new 到具有与原始语义相同的正则表达式。(但是,Regexp# == 在比较两者时可能不会返回 true,因为正则表达式本身的来源可能不同,如示例所示)。Regexp#inspect 生成通常更易读的 rxp 版本。

所以这似乎是一个可行的解决方案,但它会以不寻常的语法存储 exp,为了获取要存储的字符串,我需要使用/my-exp/.to_s. 此外,我可能无法直接编辑为正则表达式。例如一个简单的正则表达式产生:

/foo/i.to_s # => "(?i-mx:foo)" 

另一种选择是评估字段内容,因此我可以将纯表达式存储在 db 列中,然后执行eval(record.pattern)以获得实际的正则表达式。这是有效的,因为我是唯一负责管理正则表达式记录的人,所以除了应用程序错误之外,这样做应该没有问题;-)

我还有其他选择吗?我宁愿不在 db 字段上执行 eval,但另一方面我不想使用我不知道的语法。

4

3 回答 3

5

用于serialize存储您的正则表达式“原样”

class Foo < ActiveRecord::Base
  serialize :my_regex, Regexp
end

请参阅API 文档以了解有关此内容的更多信息。

于 2012-10-25T12:00:17.617 回答
3

不确定我是否完全理解您的限制。

如果你在 db 中存储一个字符串,你可以从中创建一个正则表达式:

a = 'foo'
=> "foo" 
/#{a}/
=> /foo/
Regexp.new('dog', Regexp::EXTENDED + Regexp::MULTILINE + Regexp::IGNORECASE) 
=> /dog/mix

还有其他构造函数,请参阅 doc

不使用 eval'd 代码的最佳解决方案是将正则表达式部分存储在字符串列中,并将标志存储在单独的整数列中。通过这种方式,可以使用以下方式构建正则表达式:

record = Record.new pattern: 'foo', flags: Regexp::IGNORECASE
Regexp.new record.pattern, record.flags # => /foo/i
于 2012-10-25T11:30:53.227 回答
2

您可以在正则表达式中使用 #{} 来插入变量,因此您可以通过将“foo”作为字符串存储在 record.pattern 下的数据库中来插入经过仔细清理的正则表达式,然后使用以下命令对其进行评估:

/#{record.pattern}/

因此,在数据库中,您将存储:

"pattern"

在您的代码中,您可以执行以下操作:

if record.other_field =~ /#{record.pattern}/
  # do something
end

这会从数据库中您可以更改的动态字符串编译正则表达式,并允许您在代码中使用它。出于安全原因,我不推荐它,请参见下文:

显然这可能很危险,因为正则表达式可以包含 ruby​​ 代码,所以这更简单,但就危险而言,它类似于 eval:

a = "foo"
puts a
=> foo
b = "#{a = 'bar'}"
a =~ /#{b}/ 
puts a 
=> bar

您可能会更好地考虑是否值得将您的正则表达式测试分解为您可以映射到您在代码中编写的方法的东西,这样您就可以将键存储在数据库中以进行约束,例如:

'字母,数字'等

然后根据存储的密钥进行硬编码测试。也许在这里查看 rails 验证以获取提示,尽管它们存储在代码中,但这可能是最好的方法(概括您的要求,并将代码保留在数据库之外)。即使您认为现在不需要安全性,您也可能会在以后需要它,或者忘记这一点并授予恶意人员访问权限。

于 2012-10-25T11:38:00.467 回答