How do I validate user input into a template?

In my Ruby on Rails application, I need to validate user input for patterns consisting of letters, numbers, and a few special characters (such as dashes and underscores), and I don't know how.

For example, if the template is relevant LL-NNNN

and the user submits a string AB-0001

, this will be valid.

If the template NN-LL

and the user submits 77-ABC

, it will be invalid.

I thought about converting each pattern to a regex, but since each user can define their own pattern (which means there will be many), I am concerned that this might lead to unexpected results.

Can anyone tell me what is the best way to solve this?

+3


source to share


5 answers


In the loop, check to see if each character from the input string matches the corresponding character in the pattern.



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

      

+4


source


If the pattern will always be a combination L => Letter

, N => number

and -

, you can convert it to a regular expression withRegex.new(value)

It will all look like this for any occasion.

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

      

and this is for uppercase only



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

      

You can even do the conversion to regex earlier and store the regex in the DB instead of a pattern to optimize processing time.

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

      

+4


source


Because we love Ruby's one-liner so much, here's a quick hack.

Replace the input characters with the appropriate wildcard character:

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

      

And compare the result with the pattern:

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

      

+3


source


You can create a regexp builder and Regexp.escape

will help you. Let's say you've installed a custom template alphabet:

ALPHABET = 'LN-_:=.\\'

      

Then you can check if the user template is correct:

PATTERN_REGEXP = Regexp.new('\A[%s]+\z' % Regexp.escape(ALPHABET))
def is_pattern_ok?(pattern)
  PATTERN_REGEXP =~ pattern
end

      

The next step is to create a custom regex input string from its template:

def regexp_str_from(pattern)
  ('\A%s\z' % Regexp.escape(pattern))
    .gsub('N', '\d')
    .gsub('L', '[a-zA-Z]'))
end

      

And save it somewhere in user preferences in the DB. This way you can validate user input with a custom template:

Regexp.new(regexp_str) =~ user_input

      

Edited: Note: Regexp.escape

Required to avoid "unexpected results".

0


source


You can use this in our model

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

      

-1


source







All Articles