I have the following regex:
/([A-Za-z0-9]+)([A-Za-z0-9\-\_]+)([A-Za-z0-9]+)/
It is not working according to my needs, which are:
a--b
is invalid).a__b
is invalid)Valid examples:
a1_b_2_hello
2b-ffg-er2
abs
123a
Invalid examples:
_a1_b_2_hello
2b-ffg_er2-
__
--
a__
b--2
I find it convenient to put all the special conditions at the beginning in positive and negative lookaheads and follow these (which consume no characters) with the general requirement, here [a-z\d_-]+\z
.
r = /
\A # match start of string
(?!.* # begin negative lookahead and match >= 0 characters
(?:--|__) # match -- or __ in a non-capture group
) # end negative lookahead
(?![-_]) # do not match - or _ at the beginning of the string
(?!.*[-_]\z) # do not match - or _ at the end of the string
(?! # begin negative lookahead
.*-.*_ # match - followed by _
| # or
.*_.*- # match _ followed by -
) # end negative lookahead
(?=.*[a-z]) # match at least one letter
[a-z\d_-]+ # match one or more English letters, digits, _ or -
\z # match end of string
/ix # case indifference and free-spacing modes
"a".match? r #=> true
"aB32-41".match? r #=> true
"".match? r #=> false (must match a letter)
"123-4_5".match? r #=> false (must match a letter)
"-aB32-4_1".match? r #=> false (cannot begin with -)
"aB32-4_1-".match? r #=> false (cannot end with -)
"_aB32-4_1".match? r #=> false (cannot begin with _)
"aB32-4_1_".match? r #=> false (cannot end with _)
"aB32--4_1".match? r #=> false (cannot contain --)
"aB32-4__1".match? r #=> false (cannot contain __)
"aB32-4_1".match? r #=> false (cannot contain both - and _)
"123-4_5$".match? r #=> false ($ is not a permitted character)
This regular expression is conventionally written:
/\A(?!.*(?:--|__))(?![-_])(?!.*[-_]\z)(?!.*-.*_|.*_.*-)(?=.*[a-z])[a-z\d_-]+\z/i
You could add the a-zA-Z in a character class, and in the repetition of 0+ times match either a hyphen or an underscore [-_]
followed by 1+ times what is listed in the character class [A-Za-z0-9]+
.
Use a capturing group with a backreference to get a consistent using of -
or _
\A[A-Za-z0-9]*[A-Za-z][A-Za-z0-9]*(?:([-_])[A-Za-z0-9]+(?:\1[A-Za-z0-9]+)*)?\z
About the pattern
\A
Start of string[A-Za-z0-9]*[A-Za-z][A-Za-z0-9]*
Match at least 1 a-zA-Z(?:
Non capturing group
([-_])
Capturing group 1, match either -
or _
[A-Za-z0-9]+
Match 1+ times what is listed(?:
\1[A-Za-z0-9]+
Backreference \1
to what is captured in group 1 to get consistent delimiters (to prevent matching a-b_c
) and match 1+ times what is listed)*
Close non capturing group and make it optional)?
Close non capturing group and make it optional\z
End of stringRegex demo
See this page for a detailed explanation about the anchors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With