Test for n digits in a string - javascript

I am trying to solve 'JavaScript Algorithms and Data Structures Projects: Telephone Number Validator' #freeCodeCamp.
I need to test if string contains 10 digits and what I've come up with returns false and I don't understand why.
console.log(/\d{10}/g.test("555-555-5555"))

If you want to do this with a single regular expression, you can use:
console.log(/^(?:\D*\d){10}\D*$/g.test("555-555-5555"))
console.log(/^(?:\D*\d){10}\D*$/g.test("555-555-55555"))
requiring the input to be composed of exactly 10 digits in addition to any number of other non-digit characters - but replacing non-digits with the empty string first would be a more intuitive and readable solution.

Here \d{10} means ten consecutive digits, not "ten digits with whatever in the middle, that's cool".
If want just 10 digits, you may want to strip non-digit data first:
let number = "555-555-5555";
// Remove all non-digit values (\D) which leaves only digits
let digits = number.replace(/\D/g, '').length;

It seems that your idea is correct, but this specific challenge has so many options for dashes [-] and parentheses [()] as inputs that there is a more efficient way to pass this.
function telephoneCheck(str) {
let phoneRegex = /^(1\s?)?(\d{3}|\(\d{3}\))[\s\-]?\d{3}[\s\-]?\d{4}$/
return phoneRegex.test(str);
}
The above is a way to complete the challenge in a single line of Regex, which can save you (or anyone else reading this in the future) a lot of time and space! Cheers

Related

Regex to match exactly 5 numbers and one optional space

I recently needed to create a regular expression to check input in JavaScript. The input could be 5 or 6 characters long and had to contain exactly 5 numbers and one optional space, which could be anywhere in the string. I am not regex-savvy at all and even though I tried looking for a better way, I ended up with this:
(^\d{5}$)|(^ \d{5}$)|(^\d{5} $)|(^\d{1} \d{4}$)|(^\d{2} \d{3}$)|(^\d{3} \d{2}$)|(^\d{4} \d{1}$)
This does what I need, so the allowed inputs are (if 0 is any number)
'00000'
' 00000'
'0 0000'
'00 000'
'000 00'
'0000 0'
'00000 '
I doubt that this is the only way to achieve such matching with regex, but I haven't found a way to do it in a cleaner way. So my question is, how can this be written better?
Thank you.
Edit:
So, it is possible! Tom Lord's answer does what I needed with regular expressions, so I marked it as a correct answer to my question.
However, soon after I posted this question, I realized that I wasn't thinking right, since every other input in the project was easily 'validatable' with regex, I was immediately assuming I could validate this one with it as well.
Turns out I could just do this:
const validate = function(value) {
const v = value.replace(/\s/g, '')
const regex = new RegExp('^\\d{5}$');
return regex.test(v);
}
Thank you all for the cool answers and ideas! :)
Edit2: I forgot to mention a possibly quite important detail, which is that the input is limited, so the user can only enter up to 6 characters. My apologies.
Note: Using a regular expression to solve this problem might not be
the best answer. As answered
below, it may be
easier to just count the digits and spaces with a simple function!
However, since the question was asking for a regex answer, and in some
scenarios you may be forced to solve this with a regex (e.g. if
you're tied down to a certain library's implementation), the following
answer may be helpful:
This regex matches lines containing exactly 5 digits:
^(?=(\D*\d){5}\D*$)
This regex matches lines containing one optional space:
^(?=[^ ]* ?[^ ]*$)
If we put them together, and also ensure that the string contains only digits and spaces ([\d ]*$), we get:
^(?=(\D*\d){5}\D*$)(?=[^ ]* ?[^ ]*$)[\d ]*$
You could also use [\d ]{5,6} instead of [\d ]* on the end of that pattern, to the same effect.
Demo
Explanation:
This regular expression is using lookaheads. These are zero-width pattern matchers, which means both parts of the pattern are "anchored" to the start of the string.
\d means "any digit", and \D means "any non-digit".
means "space", and [^ ] means "any non-space".
The \D*\d is being repeated 5 times, to ensure exactly 5 digits are in the string.
Here is a visualisation of the regex in action:
Note that if you actually wanted the "optional space" to include things like tabs, then you could instead use \s and \S.
Update: Since this question appears to have gotten quite a bit of traction, I wanted to clarify something about this answer.
There are several "simpler" variant solutions to my answer above, such as:
// Only look for digits and spaces, not "non-digits" and "non-spaces":
^(?=( ?\d){5} *$)(?=\d* ?\d*$)
// Like above, but also simplifying the second lookahead:
^(?=( ?\d){5} *$)\d* ?\d*
// Or even splitting it into two, simpler, problems with an "or" operator:
^(?:\d{5}|(?=\d* \d*$).{6})$
Demos of each line above: 1 2 3
Or even, if we can assume that the string is no more than 6 characters then even just this is sufficient:
^(?:\d{5}|\d* \d*)$
So with that in mind, why might you want to use the original solution, for similar problems? Because it's generic. Look again at my original answer, re-written with free-spacing:
^
(?=(\D*\d){5}\D*$) # Must contain exactly 5 digits
(?=[^ ]* ?[^ ]*$) # Must contain 0 or 1 spaces
[\d ]*$ # Must contain ONLY digits and spaces
This pattern of using successive look-aheads can be used in various scenarios, to write patterns that are highly structured and (perhaps surprisingly) easy to extend.
For example, suppose the rules changed and you now wanted to match 2-3 spaces, 1 . and any number of hyphens. It's actually very easy to update the regex:
^
(?=(\D*\d){5}\D*$) # Must contain exactly 5 digits
(?=([^ ]* ){2,3}[^ ]*$) # Must contain 2 or 3 spaces
(?=[^.]*\.[^.]*$) # Must contain 1 period
[\d .-]*$ # Must contain ONLY digits, spaces, periods and hyphens
...So in summary, there are "simpler" regex solutions, and quite possibly a better non-regex solution to OP's specific problem. But what I have provided is a generic, extensible design pattern for matching patterns of this nature.
I suggest to first check for exactly five numbers ^\d{5}$ OR look ahead for a single space between numbers ^(?=\d* \d*$) among six characters .{6}$.
Combining those partial expressions yields ^\d{5}$|^(?=\d* \d*$).{6}$:
let regex = /^\d{5}$|^(?=\d* \d*$).{6}$/;
console.log(regex.test('00000')); // true
console.log(regex.test(' 00000')); // true
console.log(regex.test('00000 ')); // true
console.log(regex.test('00 000')); // true
console.log(regex.test(' 00000')); // false
console.log(regex.test('00000 ')); // false
console.log(regex.test('00 000')); // false
console.log(regex.test('00 0 00')); // false
console.log(regex.test('000 000')); // false
console.log(regex.test('0000')); // false
console.log(regex.test('000000')); // false
console.log(regex.test('000 0')); // false
console.log(regex.test('000 0x')); // false
console.log(regex.test('0000x0')); // false
console.log(regex.test('x00000')); // false
Alternatively match the partial expressions separately via e.g.:
/^\d{5}$/.test(input) || input.length == 6 && /^\d* \d*$/.test(input)
This seems more intuitive to me and is O(n)
function isInputValid(input) {
const length = input.length;
if (length != 5 && length != 6) {
return false;
}
let spaceSeen = false;
let digitsSeen = 0;
for (let character of input) {
if (character === ' ') {
if (spaceSeen) {
return false;
}
spaceSeen = true;
}
else if (/^\d$/.test(character)) {
digitsSeen++;
}
else {
return false;
}
}
return digitsSeen == 5;
}
You can split it in half:
var input = '0000 ';
if(/^[^ ]* [^ ]*$/.test(input) && /^\d{5,6}$/.test(input.replace(/ /, '')))
console.log('Match');
Here's a simple regex to do the job:
^(?=[\d ]{5,6}$)\d*\s?\d*$
Explanation:
^ asserts position at start of the string
Positive Lookahead (?=[\d ]{5,6}$)
Assert that the Regex below matches
Match a single character present in the list below [\d ]{5,6}
{5,6} Quantifier — Matches between 5 and 6 times, as many times as possible, giving back as needed (greedy)
\d matches a digit (equal to [0-9])
matches the character literally (case sensitive)
$ asserts position at the end of the string
\d* matches a digit (equal to [0-9])
Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed (greedy)
\s matches any whitespace character (equal to [\r\n\t\f\v ])
\d* matches a digit (equal to [0-9])
Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed (greedy)
$ asserts position at the end of the string
string="12345 ";
if(string.length<=6 && string.replace(/\s/g, '').length<=5 && parseInt(string,10)){
alert("valid");
}
You could simply check the length and if its a valid number...
This is how I would do it without regex:
string => [...string].reduce(
([spaces,digits], char) =>
[spaces += char == ' ', digits += /\d/.test(char)],
[0,0]
).join(",") == "1,5";

Javascript RegEx - Enforcing two max-lengths

It's been a while that I am juggling around this. Hope you can give me
some pointers.
All I want to achieve is, the string should contain EXACTLY 4 '-' and 10 digits in any giver order.
I created this regex : ^(-\d-){10}$
It does enforce max-length of 10 on digits but I am not getting a way to implement max-length of 4 for '-'
Thanks
Ok, here's a pattern:
^(?=(?:\d*?-){4}\d*$)(?=(?:-*?\d){10}-*$).{14}$
Demo
Explanation:
The main part is ^.{14}$ which simply checks there are 14 characters in the string.
Then, there are two lookaheads at the start:
(?=(?:\d*?-){4}\d*$)
(?=(?:-*?\d){10}-*$)
The first one checks the hyphens, and the second one checks the digits and make sure the count is correct. Both match the entire input string and are very similar so let's just take a look at the first one.
(?:\d*?-){4} matches any number of digits (or none) followed by a hyphen, four times. After this match, we know there are four hyphens. (I used an ungreedy quantifier (*?) just to prevent useless backtracking, as an optimization)
\d*$ just makes sure the rest of the string is only made of digits.

Regular expression for numbers and one decimal

I can't seem to get a simple regular expression to work. Here's what I have at the moment:
$(".Hours").on('input', function (e) {
var regex = /^\d+(\.\d{0,2})?$/g;
if (!regex.test(this.value)) {
if (!regex.test(this.value[0]))
this.value = this.value.substring(1, this.value.length);
else
this.value = this.value.substring(0, this.value.length - 1);
}
});
I need the user to be able to only enter numbers and one decimal (with only two numbers after the decimal). It's working properly now, with the exception that a user cannot start with a decimal.
Acceptable:
23.53
0.43
1111.43
54335.34
235.23
.53 <--- Not working
Unacceptable:
0234.32 <--- The user can currently do this
23.453
1.343
.234.23
1.453.23
Any help on this?
Updated answer:
RegExp -
^(?:0|[1-9]\d+|)?(?:.?\d{0,2})?$
Explanation at regex101:
Original answer:
fiddle Demo
RegExp -
^(\d+)?([.]?\d{0,2})?$
Explanation
Assert position at the beginning of the string «^»
Match the regular expression below and capture its match into backreference number 1 «(\d+)?»
Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
Match a single digit 0..9 «\d+»
Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
Match the regular expression below and capture its match into backreference number 2 «([.]?\d{0,2})?»
Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
Match the character “.” «[.]?»
Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
Match a single digit 0..9 «\d{0,2}»
Between zero and 2 times, as many times as possible, giving back as needed (greedy) «{0,2}»
Assert position at the end of the string (or before the line break at the end of the string, if any) «$»
Here is a suggestion : /^((\d|[1-9]\d+)(\.\d{1,2})?|\.\d{1,2})$/.
Allows : 0, 0.00, 100, 100.1, 100.10, .1, .10...
Rejects : 01, 01.1, 100., .100, ....
Would this meet your needs:
var regex = /^\d+([.]?\d{0,2})?$/g;
Your regex:
var regex = /^\d+(\.\d{0,2})?$/g;
What you need:
var regex = /^\d*(\.\d{1,2})?$/;
You were requiring at least one digit before the decimal (\d+). I have also changed it so if you include a decimal, there must be at least one digit after it.
This one will force you to add digit after decimal separator :
^\d+([.]\d)?$
Example :
123 => true
=> false
123.1 => true
123.12 => false
123.. => false
if you want more digit; 3 for ex; make sure you fix min to "1" for digit after dicimal
^\d+([.]\d{1,3)?$

Javascript Regex: validating a double/float

Here's the pattern I'm working on:
var re = /(\d{1,2}\.(?=\d{1,2}))/;
What I would like for this to return is a one or two digit number (which will never be greater than 24, since it is for a time mgmt app), which may or may not be followed by a decimal point with either one or two trailing digits, but not more than two.
I'm not sure about the parenthetical substring match mixed with the lookahead. I just guessed and nested them. Ultimately, if my syntax is okay, I think the only thing I am missing is how to suggest that the pattern may or may not have leading digits, and may or may not contain a decimal with trialing digits.
Let me know if you need more info.
Update, Examples:
We are only dealing with time, and no more time than can occur in a single day. 24 would be the highest input.
Valid:
23.75
1.4
1
0.5
0
.2
Invalid:
1.897
%#$##$#
Words
other characters
Newest Update:
Since this is a decimal, 23.75 works. We are not counting minutes, but rather fractions of hours.
Also, for the record, I tried validating using methods and conditionals, and it was letting letters pass through after the decimals. I have made the decision to go with regex.
If "any number given will be less than 24", so that doesn't need to be separately tested for, then the following expression will work.
^\d{0,2}(\.\d{0,2}){0,1}$
See http://rubular.com/r/YDfHr5T5sQ
Tested against:
23.75 pass
1.4 pass
1 pass
0.5 pass
0 pass
.2 pass
1.897 fail
%#$##$# fail
Words fail
other characters fail
Explanation:
^ start matching at the start of the string
\d{0,2} look for zero to two digits
( ){0,1}$ look for this next thing zero or one time, then the end of the string
\.\d{0,2} match exactly one decimal followed by up to two digits
Note - this regex does match the "empty string". You might want to test for that separately if there's a chance that will somehow make its way to this expression...
Simple code to test in your javascript:
var str = "12.345";
var m = str.match(/^\d{0,2}(?:\.\d{0,2}){0,1}$/);
var goodTime;
if (!m) {
alert(str + " is not a good time");
}
else {
goodTime = m[0];
alert("found a good time: " + goodTime);
}
Note - I made a tweak to the regex - adding ?: in the "bit after the decimal" group. This just means "match but don't capture" so the result will return only the match m[0] and not the group .34 in m[1]. It doesn't actually matter since I assign goodTime the value in m[0] (but only if it's a good time). You can see this in action here
Well you can try this regex
^(?![3-9]\d|[2][5-9]|24[.])\d{1,2}([.]\d{1,2})?$
But you don't need to use regex here,just parse the string to number and check if it's less than or equal to 24
What about this one:
([1]?[0-9])|((20)|(21)|(22)|(23)|(24)){0,1}([.][0-9]{0,2})?
Edit: I would advise you to do only simple checks in RegEx and test semantic correctness (eg. less than 24) somewhere else as it gets really complicated. Time would also not allow 23:74 but 23:59...

JavaScript regex to validate complicated string

Could you please help me to provide a RegEx pattern to validate a string which satisfy:
length from 4 to 10 (strictly)
first 3 characters must be string (A-Z a-z)
the remain characters must be number without 00 as prefix, I mean ABC15 is passed but ABC0015 is not.
This problem took me so much time and I have tried so many regex patterns, but I still have no solution for it.
Thank you so much.
Use this one:
/^[a-z]{3}(?!00)\d{1,7}$/i
Explanation:
/
^ Start
[a-z]{3} Three letters.
(?!00) Must NOT be followed by two zeros.
\d{1,7} One to seven digits.
$ End.
/i ignore case flag.
Easy.
/^[a-z]{3}[1-9][0-9]{0,6}$/i
Matches three letters (case insensitive flag at the end), followed by one digit that is not zero, followed by up to six more digits (which may be zero).

Categories