Regular expression for validating complicated username - regex

So, the conditions are:
At least 1 character, max 20 characters
Starts with [a-zA-Z]
Contains [a-zA-Z0-9.-]
Ends with [a-zA-Z0-9]
My expression is:
^(?=[a-zA-Z])+[a-zA-Z0-9.-]*[a-zA-Z0-9]{1,20}$
It works nicely. However, it doesn't work properly with a username's length. I can enter a thirty-character username and still find a match. What's wrong with it?

I tend to find complicated regexps a poor choice when wanting to validate a string against multiple rules. They cause unreadable code that's difficult to maintain.
How about (in pseudocode)
.length >= 1 && .length <= 20
&& /^[a-z0-9.-]+$/i
&& /^[a-z]/i
&& /[a-z0-9]$/i
i.e. check the length, then check the legal character validity, then check the opening and closing characters, exactly as described in your question text.
You could also combine the first two lines so that you're only using regexps:
/^[a-z0-9.-]{1,20}$/i
&& /^[a-z]/i
&& /[a-z0-9]$/i
I'd be surprised if this was slower than a one-liner regexp, but it's certainly more readable.

If it contains only [a-zA-Z0-9.-], starts with [a-zA-Z] and ends with [a-zA-Z0-9], it doesn't start with [-0-9.] and doesn't end with [.-]
^(?![-0-9.])[a-zA-Z0-9.-]{1,20}(?<![.-])$
Note: Works only in regex flavors, that support negative lookbehind.
Test at regex101

Try this:
^[a-zA-Z]$|^(?=.{2,20}$)[a-zA-Z][a-zA-Z0-9.-]*[a-zA-Z0-9]$

You could use the below regex,
^(?=.{1,20}$)[a-zA-Z][a-zA-Z0-9.-]*[a-zA-Z0-9]$
DEMO

If the string does not start with [a-zA-Z] the regex will fail. The rest is easier to understand.
^(?=[a-zA-Z])[a-zA-Z0-9.-]{0,19}[a-zA-Z0-9]$
DEMO

The following is a fairly simple solution:
^[a-zA-Z]$|^[a-zA-Z]{1}[a-zA-Z0-9.-]{0,18}[a-zA-Z0-9]{1}$
Broken down:
Either: a single character in the group [a-zA-Z]
Or: Exactly one character in group [a-zA-Z], up to 18 characters in the group [a-zA-Z0-9.-] and finally 1 character from the group [a-zA-Z0-9].
Matches correctly against the following:
Valid
Valid.UserName
Valid1-1UserName
0-Invalid
Invalid.
Invalid-ThisIsTooLong
V

Related

Regex to match(extract) string between dot(.)

I want to select some string combination (with dots(.)) from a very long string (sql). The full string could be a single line or multiple line with new line separator, and this combination could be in start (at first line) or a next line (new line) or at both place.
I need help in writing a regex for it.
Examples:
String s = I am testing something like test.test.test in sentence.
Expected output: test.test.test
Example2 (real usecase):
UPDATE test.table
SET access = 01
WHERE access IN (
SELECT name FROM project.dataset.tablename WHERE name = 'test' GROUP BY 1 )
Expected output: test.table and project.dataset.tablename
, can I also add some prefix or suffix words or space which should be present where ever this logic gets checked. In above case if its update regex should pick test.table, but if the statement is like select test.table regex should not pick it up this combinations and same applies for suffix.
Example3: This is to illustrate the above theory.
INS INTO test.table
SEL 'abcscsc', wu_id.Item_Nbr ,1
FROM test.table as_t
WHERE as_t.old <> 0 AND as_t.date = 11
AND (as_t.numb IN ('11') )
Expected Output: test.table, test.table (Key words are INTO and FROM)
Things Not Needed in selection:as_t.numb, as_t.old, as_t.date
If I get the regex I can use in program to extract this word.
Note: Before and after string words to the combination could be anything like update, select { or(, so we have to find the occurrence of words which are joined together with .(dot) and all the number of such occurrence.
I tried something like this:
(?<=.)(.?)(?=.)(.?) -: This only selected the word between two .dot and not all.
.(?<=.)(.?)(?=.)(.?). - This everything before and after.
To solve your initial problem, we can just use some negation. Here's the pattern I came up with:
[^\s]+\.[^\s]+
[^ ... ] Means to make a character class including everything except for what's between the brackets. In this case, I put \s in there, which matches any whitespace. So [^\s] matches anything that isn't whitespace.
+ Is a quantifier. It means to find as many of the preceding construct as you can without breaking the match. This would happily match everything that's not whitespace, but I follow it with a \., which matches a literal .. The \ is necessary because . means to match any character in regex, so we need to escape it so it only has its literal meaning. This means there has to be a . in this group of non-whitespace characters.
I end the pattern with another [^\s]+, which matches everything after the . until the next whitespace.
Now, to solve your secondary problem, you want to make this match only work if it is preceded by a given keyword. Luckily, regex has a construct almost specifically for this case. It's called a lookbehind. The syntax is (?<= ... ) where the ... is the pattern you want to look for. Using your example, this will only match after the keywords INTO and FROM:
(?<=(?:INTO|FROM)\s)[^\s]+\.[^\s]+
Here (?:INTO|FROM) means to match either the text INTO or the text FROM. I then specify that it should be followed by a whitespace character with \s. One possible problem here is that it will only match if the keywords are written in all upper case. You can change this behavior by specifying the case insensitive flag i to your regex parser. If your regex parser doesn't have a way to specify flags, you can usually still specify it inline by putting (?i) in front of the pattern, like so:
(?i)(?<=(?:INTO|FROM)\s)[^\s]+\.[^\s]+
If you are new to regex, I highly recommend using the www.regex101.com website to generate regex and learn how it works. Don't forget to check out the code generator part for getting the regex code based on the programming language you are using, that's a cool feature.
For your question, you need a regex that understands any word character \w that matches between 0 and unlimited times, followed by a dot, followed by another series of word character that repeats between 0 and unlimited times.
So here is my solution to your question:
Your regex in JavaScript:
const regex = /([\w][.][\w])+/gm;
in Java:
final String regex = "([\w][.][\w])+";
in Python:
regex = r"([\w][.][\w])+"
in PHP:
$re = '/([\w][.][\w])+/m';
Note that: this solution is written for your use case (to be used for SQL strings), because now if you have something like '.word' or 'word..word', it will still catch it which I assume you don't have a string like that.
See this screenshot for more details

Regular Expression to exclude numerical emailids

I have below set of sample emailids
EmailAddress
1123
123.123
123_123
123#123.123
123#123.com
123#abc.com
123mbc#abc.com
123mbc#123abc.com
123mbc#123abc.123com
123mbc123#cc123abc.c123com
Need to eliminate mailids if they contain entirely numericals before #
Expected output:
123mbc#abc.com
123mbc#123abc.com
123mbc#123abc.123com
123mbc123#cc123abc.c123com
I used below Java Rex. But its eliminating everything. I have basic knowledge in writing these expressions. Please help me in correcting below one. Thanks in advance.
[^0-9]*#.*
do you mean something like this ? (.*[a-zA-Z].*[#]\w*\.\w*)
breakdown .* = 0 or more characters [a-zA-Z] = one
letter .* = 0 or more characters #
\w*\.\w* endless times a-zA-Z0-9 with a single . in between
this way you have the emails that contains at least one letter
see the test at https://regex101.com/r/qV1bU4/3
edited as suggest by ccf with updated breakdown
The following regex only lets email adresses pass that meet your specs:
(?m)^.*[^0-9#\r\n].*#
Observe that you have to specify multi-line matching ( m flag. See the live demo. The solution employs the embedded flag syntax m flag. You can also call Pattern.compile with the Pattern.MULTILINE argument. ).
Live demo at regex101.
Explanation
Strategy: Define a basically sound email address as a single-line string containing a #, exclude strictly numerical prefixes.
^: start-of-line anchor
#: a basically sound email address must match the at-sign
[^...]: before the at sign, one character must neither be a digit nor a CR/LF. # is also included, the non-digit character tested for must not be the first at-sign !
.*: before and after the non-digit tested for, arbitrary strings are permitted ( well, actually they aren't, but true syntactic validation of the email address should probably not happen here and should definitely not be regex based for reasons of reliability and code maintainability ). The strings need to be represented in the pattern, because the pattern is anchored.
Try this one:
[^\d\s].*#.+
it will match emails that have at least one letter or symbol before the # sign.

Get all matches for a certain pattern using RegEx

I am not really a RegEx expert and hence asking a simple question.
I have a few parameters that I need to use which are in a particular pattern
For example
$$DATA_START_TIME
$$DATA_END_TIME
$$MIN_POID_ID_DLAY
$$MAX_POID_ID_DLAY
$$MIN_POID_ID_RELTM
$$MAX_POID_ID_RELTM
And these will be replaced at runtime in a string with their values (a SQL statement).
For example I have a simple query
select * from asdf where asdf.starttime = $$DATA_START_TIME and asdf.endtime = $$DATA_END_TIME
Now when I try to use the RegEx pattern
\$\$[^\W+]\w+$
I do not get all the matches(I get only a the last match).
I am trying to test my usage here https://regex101.com/r/xR9dG0/2
If someone could correct my mistake, I would really appreciate it.
Thanks!
This will do the job:
\$\$\w+/g
See Demo
Just Some clarifications why your regex is doing what is doing:
\$\$[^\W+]\w+$
Unescaped $ char means end of string, so, your pattern is matching something that must be on the end of the string, that's why its getting only the last match.
This group [^\W+] doesn't really makes sense, groups starting with [^..] means negate the chars inside here, and \W is the negation of words, and + inside the group means literally the char +, so you are saying match everything that is Not a Not word and that is not a + sign, i guess that was not what you wanted.
To match the next word just \w+ will do it. And the global modifier /g ensures that you will not stop on the first match.
This should work - Based on what you said you wanted to match this should work . Also it won't match $$lower_case_strings if that's what you wanted. If not, add the "i" flag also.
\${2}[A-Z_]+/g

Interesting easy looking Regex

I am re-phrasing my question to clear confusions!
I want to match if a string has certain letters for this I use the character class:
[ACD]
and it works perfectly!
but I want to match if the string has those letter(s) 2 or more times either repeated or 2 separate letters
For example:
[AKL] should match:
ABCVL
AAGHF
KKUI
AKL
But the above should not match the following:
ABCD
KHID
LOVE
because those are there but only once!
that's why I was trying to use:
[ACD]{2,}
But it's not working, probably it's not the right Regex.. can somebody a Regex guru can help me solve this puzzle?
Thanks
PS: I will use it on MYSQL - a differnt approach can also welcome! but I like to use regex for smarter and shorter query!
To ensure that a string contains at least two occurencies in a set of letters (lets say A K L as in your example), you can write something like this:
[AKL].*[AKL]
Since the MySQL regex engine is a DFA, there is no need to use a negated character class like [^AKL] in place of the dot to avoid backtracking, or a lazy quantifier that is not supported at all.
example:
SELECT 'KKUI' REGEXP '[AKL].*[AKL]';
will return 1
You can follow this link that speaks on the particular subject of the LIKE and the REGEXP features in MySQL.
If I understood you correctly, this is quite simple:
[A-Z].*?[A-Z]
This looks for your something in your set, [A-Z], and then lazily matches characters until it (potentially) comes across the set, [A-Z], again.
As #Enigmadan pointed out, a lazy match is not necessary here: [A-Z].*[A-Z]
The expression you are using searches for characters between 2 and unlimited times with these characters ACDFGHIJKMNOPQRSTUVWXZ.
However, your RegEx expression is excluding Y (UVWXZ])) therefore Z cannot be found since it is not surrounded by another character in your expression and the same principle applies to B ([ACD) also excluded in you RegEx expression. For example Z and A would match in an expression like ZABCDEFGHIJKLMNOPQRSTUVWXYZA
If those were not excluded on purpose probably better can be to use ranges like [A-Z]
If you want 2 or more of a match on [AKL], then you may use just [AKL] and may have match >= 2.
I am not good at SQL regex, but may be something like this?
check (dbo.RegexMatch( ['ABCVL'], '[AKL]' ) >= 2)
To put it in simple English, use [AKL] as your regex, and check the match on the string to be greater than 2. Here's how I would do in Java:
private boolean search2orMore(String string) {
Matcher matcher = Pattern.compile("[ACD]").matcher(string);
int counter = 0;
while (matcher.find())
{
counter++;
}
return (counter >= 2);
}
You can't use [ACD]{2,} because it always wants to match 2 or more of each characters and will fail if you have 2 or more matching single characters.
your question is not very clear, but here is my trial pattern
\b(\S*[AKL]\S*[AKL]\S*)\b
Demo
pretty sure this should work in any case
(?<l>[^AKL\n]*[AKL]+[^AKL\n]*[AKL]+[^AKL\n]*)[\n\r]
replace AKL for letters you need can be done very easily dynamicly tell me if you need it
Is this what you are looking for?
".*(.*[AKL].*){2,}.*" (without quotes)
It matches if there are at least two occurences of your charactes sorrounded by anything.
It is .NET regex, but should be same for anything else
Edit
Overall, MySQL regular expression support is pretty weak.
If you only need to match your capture group a minimum of two times, then you can simply use:
select * from ... where ... regexp('([ACD].*){2,}') #could be `2,` or just `2`
If you need to match your capture group more than two times, then just change the number:
select * from ... where ... regexp('([ACD].*){3}')
#This number should match the number of matches you need
If you needed a minimum of 7 matches and you were using your previous capture group [ACDF-KM-XZ]
e.g.
select * from ... where ... regexp('([ACDF-KM-XZ].*){7,}')
Response before edit:
Your regex is trying to find at least two characters from the set[ACDFGHIJKMNOPQRSTUVWXZ].
([ACDFGHIJKMNOPQRSTUVWXZ]){2,}
The reason A and Z are not being matched in your example string (ABCDEFGHIJKLMNOPQRSTUVWXYZ) is because you are looking for two or more characters that are together that match your set. A is a single character followed by a character that does not match your set. Thus, A is not matched.
Similarly, Z is a single character preceded by a character that does not match your set. Thus, Z is not matched.
The bolded characters below do not match your set
ABCDEFGHIJKLMNOPQRSTUVWXYZ
If you were to do a global search in the string, only the italicized characters would be matched:
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Lookaround assertions in Perl

im confused what is the use of these lookaround assertions in perl?
example this one:
(?=pattern)
or the positive lookahead. So here's my questions:
How are these useful? what sort of instances they are used?
And related to question 1, why would i want to look ahead of the regex pattern? isnt it more work? looking ahead and then executing the pattern matching again.
I need a very clear example if possible. Thanks
To uppercase what's in between commas, you could use:
(my $x = 'a,b,c,d,e') =~ s/(?<=,)([^,]*)(?=,)/ uc($1) /eg; # a,B,C,D,e
a,b,c,d,e
Pass 1 matches -
Pass 2 matches -
Pass 3 matches -
If you didn't use lookarounds, this is what you'd get,
(my $x = 'a,b,c,d,e') =~ s/,([^,]*),/ ','.uc($1).',' /eg; # a,B,c,D,e
a,b,c,d,e
Pass 1 matches ---
Pass 2 matches ---
Not only does the lookahead avoid repetition, it doesn't work without it!
Another somewhat common use is as part of a string equivalent to [^CHAR].
foo(?:(?!foo|bar).)*bar # foo..bar, with no nested foo or bar
You can use it to narrow down character classes.
\w(?<!\d) # A word char that's not a digit.
Although this can now be done using (?[ ... ]).
It's also useful in more esoteric patterns.
/a/ && /b/ && /c/
can be written as
/^(?=.*?a)(?=.*?b).*?c/s
lookahead lets you check for a pattern without actually matching it.
When you do a(?=b) ,you would match a if its followed by b. Note:it doesn't match b.
So,
1>You can extract hello(without #) from #hello# using
(?<=#)hello(?=#)
2>You can validate passwords with requirements such as a password must have 2 digits,2 letters or more with any other character
^(?=(.*\d){2})(?=(.*[a-z]){2}).*$
Try doing above without lookahead ,you would realize it's importance
I have found lookaheads especially useful for checking multiple conditions. For example, consider a regex that checks that a password has at least one lowercase, one uppercase, one numeric, and one symbol character, and is at least 8 characters in length:
^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9]).{8,}$
Try to devise a regex to do the same thing without lookahead assertions! It's possible, but it's extremely cumbersome.
Meanwhile, I've found lookbehinds especially useful for checking boundary conditions—that is, for example, matching a string of 0's, unless it's preceded by another number, like 1000067.
These are my experiences but certainly there are many more practical uses and the way everyone uses a tool can vary from person to person.
There are many reasons to use lookarounds, e.g.
limiting the substring that is considered to be matched: s/(?<=[0-9])+(?=[0-9])/-/ instead of s/([0-9])+([0-9])/$1-$2/.
and-ing various conditions together: /(?=\p{Uppercase}\p{Lowercase})\p{InBasicLatin}{2,}/.
Lookaround assertions is useful when you need a pattern to help locate the match but you don't want the pattern to be part of what is captured.
Here's a simple scenario with lookahead assertion:
Let's say I have
my $text = '98 degrees, 99 Red Balloons, 101 Dalmatians'
and I want to change the number of red balloons from its previous value to 9001, so I use
$text =~ s/\d+(?=Red Balloons)/9001/;