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_hello2b-ffg-er2abs123aInvalid examples:
_a1_b_2_hello2b-ffg_er2-__--a__b--2I 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