I want to create a regex in Ruby to restrict my email input to follow the below rules:
[user name]@[domain name].[top-level domain name]
User name may only contain English letters, numbers, plus signs, hyphens, underscores, dots. The plus sign and dot may not appear consecutively.
User name must contain at least one English letter.
Domain name may only contain English letters, numbers, and hyphens.
Top-level domain name may only contain English letters, numbers, and hyphens. Must end with an English letter.
Domain name and top-level domain name must be separated with dots, and the email must contain at least 1 top-level domain name.
here is my regex so far:
/\A[a-zA-Z0-9]((?!\.\.)(?!\ \ )[\w\- .])*[\w\-]@[a-zA-Z0-9\-] (?:\.[a-zA-Z0-9\-]*) [a-zA-Z]\z/
I couldn't find a way to make the user name contain at least one English letter. Is there any way to restrict part of the string before the "@" to follow certain rules?
CodePudding user response:
In fact, you would like to get something like "and" condition here: the part before @ can include some valid symbols only AND must contain certain symbols at the same time.
With regular expressions, the way to model this is positive lookahead:
s1 = "[email protected]"
s2 = "[email protected]"
s3 = "[email protected]"
s1.match?(/(?=[a-zA-Z])\w @/) # => false
s2.match?(/(?=[a-zA-Z])\w @/) # => true
s3.match?(/(?=[a-zA-Z])\w @/) # => true
I simplified the pattern dramatically for simplicity, but the part that is important here is (?=[a-zA-Z]) - we check that there is at least one letter before @ without "consuming" the input stream so that the following pattern could be checked starting from the very same position...
CodePudding user response:
Yeah, that's probably not exactly what you wanted :)
But such email validation is not a good idea. People may have an email that doesn't contain English letters, may contain characters that you haven't even thought about.
By regexp limiting, you create inconvenience to your users.
Therefore, I believe that the main criterion is the presence of @. If this is valid email, then the user will receive email. If not, then will not. It's quite simple :)
The only way to validate email is to send message and receive confirmation.
Look at what regular expression can be used for email validation:
https://emailregex.com/#crayon-5dcf0d9dc15ec916764848
Or you can use the built-in Ruby regexp, just call the constant
URI::MailTo::EMAIL_REGEXP
But perhaps it's enough just @
CodePudding user response:
Suppose
str = "a1 -_.@2$b&.c3-d"
It would be easiest to first split this into the three parts of interest and then test each:
rgx = /@|\.(?!.*\.)/
uname, dname, tname = str.split(/@|\.(?!.*\.)/)
#=> ["a1 -_.", "2$b&", "c3-d"]
so
uname #=> "a1 -_."
dname #=> "2$b&"
tname #=> "c3-d"
rgx may made self-documenting by expressing it in free-spacing mode:
\A #
/
@ # match '@'
| # or
\. # match '.'
(?!.*\.) # negative lookahead asserts that '.' is not
# followed later in the string by '.'
/x # invoke free-spacing mode
We may now test each part.
urgx = /\A(?!.*(?:\ \.|\.\ ))[a-z\d _.-] \z/i
uvalid = uname.match?(urgx)
#=> true
drgx = /[a-z]/i
dvalid = dname.match?(drgx)
#=> true
trgx = /\A[a-z\d-]*[a-z]\z/i
tvalid = tname.match?()trgx
#=> true
uvalid && dvalid && tvalid
#=> true
urgx can be written in free-spacing mode as follows.
/
\A # match beginning of string
(?! # begin negative look-ahead
.* # match zero or more characters
(?: # begin non-capture group
\ \. # match ' .'
| # or
\.\ # match '. '
) # end non-capture group
) # end negative lookahead
[a-z\d _.-] # match one or more chars from char class
\z # match end of string
/ix # invoke case-indifferent and free-spacing modes
drgx merely matches a letter in the string
trgx can be written in free-spacing mode as follows.
/
\A # match beginning of string
[a-z\d-]* # match one or more chars from char class
[a-z] # match a letter
\z # match end of string
/ix # invoke case-indifferent and free-spacing modes
