Restrict Possible Usernames - what is wrong?

Restrict Possible Usernames - what is wrong?
0

#11

Please read the remaining 95% of my post, then Google the resources I mentioned.


#12

This one was trickier than I thought, probably because I suck at Regexp. After solving it, I think you will benefit more from just by looking at walkthrough rather than pulling your hair out for couple of hours. So, here we go.

First, I’ll present the working solution that also passes edge cases that FCC doesn’t check.

/^[a-zA-Z]{2,}[\d]*|[a-zA-Z][\d]{2,}$/

This consists of two parts
^[a-zA-Z]{2,}[\d]*$ and ^[a-zA-Z][\d]{2,}$
You might notice this seems totally unrelated to the exercise, but bear with me.

^[a-zA-Z]{2,}[\d]+$
This one checks:
the string beginning with at least two alphabets , ^[a-zA-Z]{2,}
followed by at least one digit towards the end, [\d]+$
So, it matches with things like

"aa"
"aaa"
"a12"
"aa123"
"aaa123"
...

Now the second part, ^[a-zA-Z][\d]{2,}$
This one checks:
the string starts with one alphabet, ^[a-zA-Z]
followed by at least two digits towards the end, [\d]{2,}$
It matches with things like:

"a12"
"a123"
...

If a username matches with either of the condition, it conforms to the given constraints.

  1. The only numbers in the username have to be at the end. There can be zero or more of them at the end.

  2. Username letters can be lowercase and uppercase.

  3. Usernames have to be at least two characters long. A two-letter username can only use alphabet letter characters.

Now, the whole reason I did this is because of the constraint #3, “Two letter username can only use alphabets”

The first two cases are straight forward:
^[a-zA-Z]+[\d]*$
At least one alphabet followed by optional digits. This also conforms to the first half of the constraint #3, minimum length = 2.

But as soon as you add the second half of the constraint #3, things get really messy.
You might think you can just use alternate match with | with [a-zA-Z]{2}
Like ^[a-zA-Z]+[\d]*|[a-zA-Z]{2}$
We just check for the special case where username is length 2, easy right? nope.
This gives false positive for things like "a1", which clearly violates constraint#3.

Now this “a1” becomes the new special case, that we should avoid. The root of problem is our first Regex
^[a-zA-Z]+[\d]*$
One obvious way to avoid our new special case is
^[a-zA-Z]{2,}[\d]*$
Now, "a1" fails, which is good, but we can’t have things like "a12".
Let’s fix that by adding alternative case ^[a-zA-Z][\d]{2,}$
We can concatenate alternative pattern with |

Finally, we arrive at

/^[a-zA-Z]{2,}[\d]*|[a-zA-Z][\d]{2,}$/

Username Exercise RegExp
Regular Expressions: Restrict Possible Usernames
#13

Wow regex is confusing.

The challenges only teach you what each thing means, in no way does it show you how to put them together correctly.

But how? I thought it matched not made it optional.

What does the +$ mean that seems to be random.

Where did you learn regex?


#14

There’s another typo there it should be [\d]+$ :frowning: sorry for the confusion. (I was editing back and forth)

So, [\d] matches any single digit. + further specifies quantity, and $ checks if previous pattern is true at the end. Together, they read as match a sequence that ends with at least one digit. In general, anything inside [] is treated as a literal character and anything else have speical meaning depending on some context.

I learned Regex from MDN and a couple of chapters from the book “Mastering Regular Expression”. This source is good as well, http://www.grymoire.com/Unix/Regular.html

I don’t really think the exercise was fair for someone just learning Regex.


#15

So i had my crack at some Coding train videos and i am trying to do this problem for myself, so i can learn.

First i am just trying to match anything that has 3 or more letters characters, and has a optional ending of a number.

Here is my code: /\w{3,}\d?/i

\w\s means one character means one letter one space? https://youtu.be/YTocEnDsMNw?t=294

Using that i tried to say 3 or more \w with a optional \d

Now its failing to check for letters. Ja1 works, but so does 1ac.


#16

\w does not just match letters. It includes 0-9 and the underscore character.

Just to clarify, based on your description above, ‘Ja1’ should not be a match.


#17

So i do /\[a-zA-Z]{2,}\d+?/i so i can have two letter characters and a optional number(s) ?

Now everything seems to be false --> https://repl.it/@John_Nicole/Regular-Expression-Restrict-Possible-Usernames


#18

If you are trying to solve the username challenge, how are you accounting for the fact that the username must start with a letter and only a number at the end (if used)? Also, why do you have a \ character before [a-zA-Z]?

FYI, since you are using the i flag, you only need to write [a-z], because the i flag ignores case.


#19

Okay so i removed the slash and it works with numbers. I tried using the question mark to make it optional from all the documentation i read but it isn’t working.

I used the idea of \w\s meaning one letter one space, so i said 2 or more letters with a 0 or more numbers.


#20

In general, \<lowercase_char> expands to a predefined character set. In this case, \w expands to [a-zA-Z0-9_].
As a side note, \<uppercase_char> often expands to the complement, \W := [^a-zA-Z0-9_]. Notice [^...] this form is negation.
In any other cases, \ usually escapes special symbol to literal. e.g) \[] If you do this, the [] no longer means character set. Because [ is treated literally, like '['].

If you want just the alphabets, [a-zA-Z] is the way to go, or [a-z] with i modifier.

Assuming you already know range specifier and quantifier, +3 alphabets with optional 1 digit would be.
/[a-z]{3,}\d?/i


#21

So this is my code now:

/[a-zA-Z]{2,}\d*?/i

How come it still passes a string with a number at the front?

@gunhoo93


#22

Again, you do not need the A-Z because you are using the i flag at the end of the regular expression.

Hint: To solve your dilemma, think about a special character you learned about which defines the beginning. Also, do you really need both the * and the ?


#23

I got it :smiley:

The ^ was what i needed, and a $ at the end.

/^[a-z]{2,}\d*?$/i


#24

Hello,

This is my first post but I felt like I wanted to share my solution.

I have not praticed Regular Expressions before FreeCodeCamp.

I just skimmed most of the posts in this thread but the solutions look quite long to me.

My solution:

let userCheck = /^\D\D/i;

The solution checks that the two first characters in the string are not numbers and is also case insensitive.

Please feel free to give me feedback on this solution.

Edit: When I look at my solution again I think that it might match non-alphabetical characters in the first two characters (but still passes the test). There might be room for improvement in checking the answer.


#25

It might have passed all the tests given by FCC, but yours is not a solution to the given problem. All the previous posts here had dealt with this issue.

Let me give you a counter example.
a123 should match because it ends with a number and has more than 2 characters. However, your regex fails to match with this one.

The minimum requirement for this regex must have the form /^...$/, otherwise there will be incorrect matches.

If you have any question, consider opening another post because this one is already solved.


#26

My solution and it works

/[a-z][\d]{2,}$|[a-z]/ig


#27

Your code has been blurred out to avoid spoiling a full working solution for other campers who may not yet want to see a complete solution. In the future, try to just give hints and examples of other code which will help the camper instead of the final solution.

Thank you.


#28

How will yours handle when input is 123abc?


#29

Here is a hint i gave someone else on this same problem:


#30

Thanks for the nice posts. After reading this helped figure out the solution. I broke the reasoning down to this, if this helps anyone else:

must be alphabet letters: [a-z],
alphabet letters must be a minimum of first 2 characters: {2,},
only numbers at the end of the string, any amount allowed: \d*$,
not case sensitive: /i

This solution worked, took a while :slight_smile:

let userCheck = /^[a-z]{2,}\d*$/i;