Ruby on rails 如何根据模式检查用户输入?

Ruby on rails 如何根据模式检查用户输入?,ruby-on-rails,ruby,Ruby On Rails,Ruby,在我的RubyonRails应用程序中,我需要根据由字母、数字和一些特殊字符(如破折号和下划线)组成的模式检查用户输入,但我不知道如何做 例如,如果模式为LL-NNNN,并且用户提交字符串AB-0001,则该模式有效 如果模式为NN-LL,且用户提交77-ABC,则该模式无效 我曾考虑将每个模式转换为正则表达式,但由于每个用户都可以定义自己的模式(这意味着会有很多模式),我担心这可能会导致意外的结果 有谁能告诉我解决这个问题的最佳方法吗?您可以在我们的模型中使用这个方法 validates_fo

在我的RubyonRails应用程序中,我需要根据由字母、数字和一些特殊字符(如破折号和下划线)组成的模式检查用户输入,但我不知道如何做

例如,如果模式为
LL-NNNN
,并且用户提交字符串
AB-0001
,则该模式有效

如果模式为
NN-LL
,且用户提交
77-ABC
,则该模式无效

我曾考虑将每个模式转换为正则表达式,但由于每个用户都可以定义自己的模式(这意味着会有很多模式),我担心这可能会导致意外的结果


有谁能告诉我解决这个问题的最佳方法吗?

您可以在我们的模型中使用这个方法

validates_format_of :your_field_name, with: /(your regex)/i, on: :create

在循环中,检查输入字符串中的每个字符是否满足相应的模式字符

def match?(pattern, input)
  return false if pattern.length != input.length
  pattern.each_char.with_index.all? do |char, i|
    case char
    when 'L' then input[i] =~ /[A-Z]/
    when 'N' then input[i] =~ /[0-9]/
    when '-' then input[i] == '-'
    else raise 'invalid pattern'
    end
  end
end

match?('LL-NNNN', 'AB-1234') #=> true
match?('NN-LL', '77-ABC')    #=> false
match?('NN-LL', '77-99')     #=> false
match?('NN-LL', '77-AB')     #=> true

因为我们非常喜欢Ruby中的一行程序,这里有一个快速的破解

用相应的模式字符替换输入字符:

'AB-1234'.gsub(/[A-Z]/, 'N') #=> "NN-1234"
         .gsub(/[0-9]/, 'L') #=> "NN-LLLL"
并将结果与模式进行比较:

'AB-1234'.gsub(/[A-Z]/, 'N').gsub(/[0-9]/, 'L') == 'NN-LLLL'
#=> true

如果模式总是由字母、
N=>number
-
组合而成,则可以使用
regex.new(value)
将其转换为正则表达式

无论哪种情况,整个事情都是这样

def match(pattern, value)
  /\A#{pattern.gsub(/[LN]/, 'L' => '[a-zA-Z]', 'N' => '\d')}\z/.match(value)
end
这只适用于大写字母

def match(pattern, value)
  /\A#{pattern.gsub(/[LN]/, 'L' => '[A-Z]', 'N' => '\d')}\z/.match(value)
end
您甚至可以尽早将正则表达式转换为正则表达式格式,并将正则表达式存储在数据库中,而不是存储在模式中,以优化处理时间

def regex_from_pattern(pattern)
  "\\A#{pattern.gsub(/[LN]/, 'L' => '[a-zA-Z]', 'N' => '\d')}\\z"
end

def match(regex_string, value)
  Regexp.new(regex_string).match(value)
end

您可以创建regexp生成器和
regexp.escape
将对您有所帮助。 假设您已经设置了用户定义的模式字母表:

ALPHABET = 'LN-_:=.\\'
然后,您可以检查用户的模式是否正确:

PATTERN_REGEXP = Regexp.new('\A[%s]+\z' % Regexp.escape(ALPHABET))
def is_pattern_ok?(pattern)
  PATTERN_REGEXP =~ pattern
end
下一步是根据他的模式创建用户定义的输入regexp字符串:

def regexp_str_from(pattern)
  ('\A%s\z' % Regexp.escape(pattern))
    .gsub('N', '\d')
    .gsub('L', '[a-zA-Z]'))
end
并将其保存在数据库的用户设置中的某个位置。 因此,您可以使用用户定义的模式验证用户输入:

Regexp.new(regexp_str) =~ user_input

已编辑:注意:
Regexp.escape
是必需的,以避免“意外结果”。

模式是否特定于用户?每个用户都有自己的模式?@SergioTulentsev:是的。好吧,但是你如何用
'LL-NNNN'
构造
/(你的正则表达式)/i
?你想根据用户输入的内容创建正则表达式吗?模式也是用户定义的:“每个用户都可以定义自己的模式”,我试图用
'AB-0001.tr(“A-z”,“L”)做一些不同的事情.tr(“0-9”,“N”)
。或者
/\A#{pattern.gsub(/[LN]/,'L'=>'[A-Z]','N'=>'\d')}\Z/
@Stefan,对于运行时转换选项,它看起来更干净。更新这些。谢谢。
\w
匹配包含字母但也包含数字和下划线的单词字符,您需要在
regexp\u stru from(pattern)函数中用
[a-zA-Z]
[a-Z]
替换
\w
,以适应所描述的模式