Phone number validation - excluding non repeating separators - javascript

I have the following regex for phone number validation
function validatePhonenumber(phoneNum) {
var regex = /^[1-9]{3}[-\s\.]{0,1}[0-9]{3}[-\s\.]{0,1}[0-9]{4}$/;
return regex.test(phoneNum);
}
However, I would liek to make sure it doesn;t pass for different separators such as in
111-222.3333
Any ideas how to make sure the separators are the same always?

Just make sure beforehand that there is at most one kind of separator, then pass the string through the regex as you were doing.
function validatePhonenumber(phoneNum) {
var separators = extractSeparators(phoneNum);
if(separators.length > 1) return false;
var regex = /^[1-9]{3}[-\s\.]{0,1}[0-9]{3}[-\s\.]{0,1}[0-9]{3}$/;
return regex.test(phoneNum);
}
function extractSeparators(str){
// Return an array with all the distinct chars
// that are present in the passed string
// and are not numeric (0-9)
}

You can use the following regex instead:
\d{3}([-\s\.])?\d{3}\1?\d{4}
Here is a working example:
http://regex101.com/r/nN9nT7/1
As result it will match the following result:
111-222-3333 --> ok
111.222.3333 --> ok
111 222 3333 --> ok
111-222.3333
111.222-3333
111-222 3333
111 222-3333
EDIT: after Alan Moore's suggestion:
Also matches 111-2223333. That's because you made the \1 optional,
which isn't necessary. One of JavaScript's stranger quirks is that a
backreference to a group that did not participate in the match,
succeeds anyway. So if there's no first separator, ([-\s.])? succeeds
because the ? made it optional, and \1 succeeds because it's
JavaScript. But I would have used ([-\s.]?) to capture the first
separator (which might be nothing), and \1 to match the same thing
again. This works in any flavor, including JavaScript.
We can improve the regex to:
^\d{3}([-\s\.]?)\d{3}\1\d{4}$

You'll need at least two passes to keep this maintainable and extensible.
JS' RegEx doesn't allow for creating variables for use later in the RegEx, if you want to support older browsers.
If you are only supporting modern browsers, Fede's answer is just fine...
As such, with ghetto-support, you aren't going to be able to reliably check that one separator is the same value every time, without writing a really, really, really, stupidly-long RegEx, using | to basically write out the RegEx 3 times.
A better way might be to grab all of the separators, and use a reduction or a filter to check that they all have the same value.
var userEnteredNumber = "999.231 3055";
var validNumber = numRegEx.test(userEnteredNumber);
var separators = userEnteredNumber.replace(/\d+/g, "").split("");
var firstSeparator = separators[0];
var uniformSeparators = separators.every(function (separator) { return separator === firstSeparator; });
if (!uniformSeparators) { /* also not valid */ }
You could make that a little neater, using closures and some applied functions, but that's the idea.
Alternatively, here's the big, ugly RegEx that would allow you to test exactly what the user entered.
var separatorTest = /^([0-9]{3}\.[0-9]{3}\.[0-9]{3,4})|([0-9]{3}-[0-9]{3}-[0-9]{3,4})|([0-9]{3} [0-9]{3} [0-9]{3,4})|([0-9]{9,10})$/;
Notice I had to include the exact same number-test three times, wrap each one in parens (to be treated as a single group), and then separate each group with an | to check each group, like an if, else if, else... ...and then plug in a separate special case for having no separator at all...
...not pretty.
I'm also not using \d, just because it's easy to forget that - and . are both accepted "digit"s, when trying to maintain one of these abominations.
Now, a word or two of warning:
People are liable to enter all kinds of crap; if this is for a commercial site, it's likely better to just strip separators entirely and validate the number is the right size, and conforms to some specifics (eg: doesn't start with /^555555/).
If not given any instruction about number format, people will happily use either no separator or a formal number, like (555) 555-5555 (or +1 (555) 555-5555 for the really pedantic), which is obviously going to fail hard, in this system (see point #1).
Be prepared to trim what you get, before validating.
Depending on your country/region/etc laws about data-security and consumer-vs-transaction record-keeping (again, may or may not be more important in a commercial setting), it's likely better to store both a "user-given" ugly number, and a system-usable number, which you either clean on the back-end, or submit along with the user-entered text.
From a user-interaction perspective, either forcing the number to conform, explicitly (placeholders showing them xxx-xxx-xxxx right above the input, in bold), or accepting any text, and prepping it yourself, is going to be 1000x better than accepting certain forms, but not bothering to tell the user up-front, and instead telling them what they did was wrong, after they try.
It's not cool for relationships; it's equally not cool, here.
You've got 9-digit and 10-digit numbers, so if you're trying for an international solution, be prepared to deal with all international separators (, \.\-\(\)\+) etc... again, why stripping is more useful, because THAT RegEx would be insane.

Related

How do i allow only one (dash or dot or underscore) in a user form input using regular expression in javascript?

I'm trying to implement a username form validation in javascript where the username
can't start with numbers
can't have whitespaces
can't have any symbols but only One dot or One underscore or One dash
example of a valid username: the_user-one.123
example of invalid username: 1----- user
i've been trying to implement this for awhile but i couldn't figure out how to have only one of each allowed symbol:-
const usernameValidation = /(?=^[\w.-]+$)^\D/g
console.log(usernameValidation.test('1username')) //false
console.log(usernameValidation.test('username-One')) //true
How about using a negative lookahead at the start:
^(?!\d|.*?([_.-]).*\1)[\w.-]+$
This will check if the string
neither starts with digit
nor contains two [_.-] by use of capture and backreference
See this demo at regex101 (more explanation on the right side)
Preface: Due to my severe carelessness, I assumed the context was usage of the HTML pattern attribute instead of JavaScript input validation. I leave this answer here for posterity in case anyone really wants to do this with regex.
Although regex does have functionality to represent a pattern occuring consecutively within a certain number of times (via {<lower-bound>,<upper-bound>}), I'm not aware of regex having "elegant" functionality to enforce a set of patterns each occuring within a range of number of times but in any order and with other patterns possibly in between.
Some workarounds I can think of:
Make a regex that allows for one of each permutation of ordering of special characters (note: newlines added for readability):
^(?:
(?:(?:(?:[A-Za-z][A-Za-z0-9]*\.?)|\.)[A-Za-z0-9]*-?[A-Za-z0-9]*_?)|
(?:(?:(?:[A-Za-z][A-Za-z0-9]*\.?)|\.)[A-Za-z0-9]*_?[A-Za-z0-9]*-?)|
(?:(?:(?:[A-Za-z][A-Za-z0-9]*-?)|-)[A-Za-z0-9]*\.?[A-Za-z0-9]*_?)|
(?:(?:(?:[A-Za-z][A-Za-z0-9]*-?)|-)[A-Za-z0-9]*_?[A-Za-z0-9]*\.?)|
(?:(?:(?:[A-Za-z][A-Za-z0-9]*_?)|_)[A-Za-z0-9]*\.?[A-Za-z0-9]*-?)|
(?:(?:(?:[A-Za-z][A-Za-z0-9]*_?)|_)[A-Za-z0-9]*-?[A-Za-z0-9]*\.?)
)[A-Za-z0-9]*$
Note that the above regex can be simplified if you don't want usernames to start with special characters either.
Friendly reminder to also make sure you use the HTML attributes to enforce a minimum and maximum input character length where appropriate.
If you feel that regex isn't well suited to your use-case, know that you can do custom validation logic using javascript, which gives you much more control and can be much more readable compared to regex, but may require more lines of code to implement. Seeing the regex above, I would personally seriously consider the custom javascript route.
Note: I find https://regex101.com/ very helpful in learning, writing, and testing regex. Make sure to set the "flavour" to "JavaScript" in your case.
I have to admit that Bobble bubble's solution is the better fit. Here ia a comparison of the different cases:
console.log("Comparison between mine and Bobble Bubble's solution:\n\nusername mine,BobbleBubble");
["valid-usrId1","1nvalidUsrId","An0therVal1d-One","inva-lid.userId","anot-her.one","test.-case"].forEach(u=>console.log(u.padEnd(20," "),chck(u)));
function chck(s){
return [!!s.match(/^[a-zA-Z][a-zA-Z0-9._-]*$/) && ( s.match(/[._-]/g) || []).length<2, // mine
!!s.match(/^(?!\d|.*?([_.-]).*\1)[\w.-]+$/)].join(","); // Bobble bulle
}
The differences can be seen in the last three test cases.

Remove all parentheses, commas etc from a string and then extract the first 5 words

I have a string, eg:
Lenovo K6 Power (Silver, 32 GB)(4 GB RAM), smart phone
I want to remove all parentheses and contents within the parentheses, commas etc and then extract the first five words only so that I get the result as
Lenovo K6 Power smart phone
Is there any method to apply regex to get this result?
Here's one way of doing it:
var str = 'Lenovo K6 Power (Silver, 32 GB)(4 GB RAM)';
document.write(str.match(/\w+/g).slice(0,5).join(' '));
It gets all words into an array (match(/\w+/g)), then gets the first five (slice(0,5)), to join then back to a string separated by space (join(' ')).
(And... Considering the question is tagged with regex, I believe a word could be defined as consisting of regex word characters, i.e. \w.)
Edit
The question has changed so the answer isn't correct anymore. Here's an update snippet that works with the new criteria:
var str = 'Lenovo K6 Power (Silver, 32 GB)(4 GB RAM), smart phone';
document.write(str.split(/(?:\W*\([^)]*\))*\W+/).slice(0,5).join(' '));
This one split's the string instead, using the regex (?:\W*\([^)]*\))*\W+ which will match everything but word characters (\W), unless they're inside parentheses (everything inside parentheses is matched).
spliting on that will give an array with only the desired words. Therefrom the logic is the same.
var s1 = "Lenovo K6 Power (Silver, 32 GB)(4 GB RAM), smart phone";
var s2 = s1.replace(/\([^)]*\)|, /g,'')
console.log(s2) //Output : "Lenovo K6 Power smart phone"
var myString = "Lenovo K6 Power (Silver, 32 GB)(4 GB RAM), smart phone";
while (/\(.*\)/.test(myString)) {
myString = myString.replace(/\(.*?\)/.exec(myString)[0],'');
}
console.log(myString.match(/\w+/g));
The first snippet matches all parentheses pairs as long as there are some and removes them, them it matches all remaining words.
Output: Obj... ["Lenovo", "K6", "Power", "smart", "phone"]
This is a general solution, to always only get the first 5 Elements change the console log to
var obj = myString.match(/\w+/g);
for (var i = 0; i < 5; i ++)
{
console.log(obj[i]);
}
Your question is extremely trivial and can be answered with the most basic JavaScript skills. I strongly suggest you go back and review your tutorials and intros, and try solving your problem yourself.
To remove something, you simply do
string.replace(WHAT, '')
In other words, you replace something with nothing (the empty string ''). In the case you mentioned, this, a simple Google search for something like "javascript remove regexp" will give you plenty of pointers. In this case, one of the first results actually is about removing parentheses.
In your case, I guess you finally decided you want to remove parentheses and what's inside them. In about the first five minutes of learning regexp, you should have learned to write
/\(.*?\)/g
^^ an actual left paren
^^^ any number of characters
^^ an actual right paren
^ match this over and over again
If you need help with this, try an online regexp tester such as regex101.com. It will also give you a readable version of your regexp.
The only thing moderately advanced about this is the .*?, where the ? means "non-greedy"--in other words, take characters up only to the next right paren.
I'm sure you already learned why you have to write \( to match a left parenthesis, right? The \ escapes the parentheses, because by itself the parentheses would have a special meaning to regexp. You know the g flag too, right? That means replace all the matches.
To find the first five tokens, you first need to split your string into tokens. I'm sure you recall from your studies the basic Array methods, including--drum roll--split! Split your string with string.split(' '). That will split on single spaces. If you want to split on any whitespace, you could try string.split(/\s+/).
Now go back and read the documentation for split real carefully, although I know you already have. Look carefully at the second argument, called limit. It does exactly what you want. It splits into segments, but no more than specified by limit.
The solution to your problem, which you could easily have come up with if you had spent about five minutes studying the documentation and experimenting, is
input.replace(/\(.*?\)/g, '').split(/\s+/, 5)
Unfortunately, your approach of posting on Stack Overflow is not going to scale well at all. You can't post here every time there is some minor problem you cannot figure out yourself. To be perfectly frank, if you cannot learn how to learn, then you better give up on being a programmer and try brick-laying instead. You need to learn how to figure out things yourself. Before anything else, you need to learn how to read (and digest) the documentation. Very early in your career, you're also going to need to learn how to debug your programs, since Stack Overflow is no better a way to get your programs debugged than it is to get them written for you in the first place. If you simply cannot bring yourself to read documents or learn by yourself, and can only work by asking other people how to do every little thing, then find a chat room or forum where there are people with nothing better to do than answer such questions. That is not what Stack Overflow is.
console.log('Lenovo K6 Power (Silver, 32 GB)(4 GB RAM), smart phone'.replace(/\(.*?\)/g, '').split(/\s+/, 5));
Fixing this code so as to remove the comma is left as an exercise for you to use your new-found learning powers on. Hint: you may want to use the regexp feature called "alternation", which is represented by the vertical bar or pipe |. You may also find yourself needing to use character classes, which is another thing you should have learned about very early in your regexp studies.
None of this has anything to do with TypeScript, or Angular, as you seem to have thought when you initially posted the question. It's a little concerning that you seem to think that doing basic regexp or string or array manipulation would somehow be a TypeScript or Angular issue. TypeScript is merely a typing layer on top of JavaScript. Angular is a framework for building web apps. Neither replaces JavaScript, or provides any new basic language capability. In fact, to use either effectively, you must know JavaScript well.

Regex for parsing some medical data

I have been looking for a few hours how to do this particular regular expression magic with little to no luck.
I have been playing around with parsing some of my own medical data (why not?) which unfortunately comes in the form of a very unstructured text document with no tags (XML or HTML).
Specifically, as a prototype, I only want to match what my LDL delta (cholesterol change) is as a percentage.
In the form it shows up in a few different ways:
LDL change since last visit: 10%
or
LDL change since last visit:
10%
or
LDL change since last visit:
10%
I have been trying to do this in JavaScript using the native RegExp engine for a few hours (more than I want to admit) with little success. I am by no means a RegExp expert but I have been looking at an expression like such:
(?<=LDL change since last visit)*(0*(100\.00|[0-9]?[0-9]\.[0-9]{0,2})%)
Which I know does not work in JS because the lack support for ?<=. I tested these in Ruby but even then they were not successful. Could anybody work me through some ways of doing this?
EDIT:
Since this particular metric shows up a few times in different areas, I would like the regex to match them all and have them be accessible in multiple groups. Say matching group 0 corresponds to the Lipid Profile section and matching group 1 corresponds to the Summary.
Lipid profile
...
LDL change since last visit:
10%
...
Summary of Important Metrics
...
LDL change since last visit: 10%
...
A lookbehind solution is complicated because most languages only support fixed or finite length lookbehind assertions. Therefore it's easier to use a capturing group instead. (Also, the * quantifier after the lookbehind that you used makes no sense).
And since you don't really need to validate the number (right?), I would simply do
regexp = /LDL change since last visit:\s*([\d.]+)%/
match = regexp.match(subject)
if match
match = match[1]
else
match = nil
end
If you expect multiple matches per string, use .scan():
subject.scan(/LDL change since last visit:\s*([\d.]+)%/)

JavaScript regex valid name

I want to make a JavaScript regular expression that checks for valid names.
minimum 2 chars (space can't count)
space en some special chars allowed (éàëä...)
I know how to write some seperatly but not combined.
If I use /^([A-Za-z éàë]{2,40})$/, the user could input 2 spaces as a name
If I use /^([A-Za-z]{2,40}[ éàë]{0,40})$/, the user must use 2 letters first and after using space or special char, can't use letters again.
Searched around a bit, but hard to formulate search string for my problem. Any ideas?
Please, please pretty please, don't do this. You will only end up upsetting people by telling them their name is not valid. Several examples of surnames that would be rejected by your scheme: O'Neill, Sørensen, Юдович, 李. Trying to cover all these cases and more is doomed to failure.
Just do something like this:
strip leading and trailing blanks
collapse consecutive blanks into one space
check if the result is not empty
In JavaScript, that would look like:
name = name.replace(/^\s+/, "").replace(/\s+$/, "").replace(/\s+/, " ");
if (name == "") {
// show error
} else {
// valid: maybe put trimmed name back into form
}
Most solutions don't consider the many different names there might be. There can be names with only two character like Al or Bo or someone that writes his name like F. Middlename Lastname.
This RegExp will validate most names but you can optimize it to whatever you want:
/^[a-z\u00C0-\u02AB'´`]+\.?\s([a-z\u00C0-\u02AB'´`]+\.?\s?)+$/i
This will allow:
Li Huang Wu
Cevahir Özgür
Yiğit Aydın
Finlay Þunor Boivin
Josué Mikko Norris
Tatiana Zlata Zdravkov
Ariadna Eliisabet O'Taidhg
sergej lisette rijnders
BRIANA NORMINA HAUPT
BihOtZ AmON PavLOv
Eoghan Murdo Stanek
Filimena J. Van Der Veen
D. Blair Wallace
But will not allow:
Shirley24
66Bryant Hunt88
http://stackoverflow.com
laoise_ibtihaj
hippolyte#example.com
Cy4n 4ur0r4 Blyth3 3ll1
Justisne
Danny
If the name needs to be capitalized, uppercase, lowercase, trimmed or single spaced, that's a task a formatter should do, not the user.
I would like to propose a RegEx that would match all latin based languages with their special characters:
/\A([ áàíóúéëöüñÄĞİŞȘØøğışÐÝÞðýþA-Za-z-']*)\z/
P.S. I've included all characters I could find, but please feel free to edit the answer in case I've missed any.
Why not
var reg= /^([A-Za-z]{2}[ éàëA-Za-z]*)$/;
2 letters, then as many spaces, letters or special characters as you want.
I wouldn't allow spaces in usernames though - it's begging for trouble when you have usernames like
ab ba
who's going to remember how many spaces they used?
You could do this:
/^([A-Za-zéàë]{2,40} ?)+$/
2-40 characters, and then optionally a space, repeated at least once. This will allow a space at the end, but you could trim it off separately.
After 'trim' the input value, The following will math your request only for Latin surnames.
rn = new RegExp("([\w\u00C0-\u02AB']+ ?)+","gi");
m = ln.match(rn);
valid = (m && m.length)? true: false;
Note that I am using '+', instead of '{2,}', that is because some surnames uses just one letter in a separated word like "Ortega y Gasset"
You can see I am not using RegExp.test, this is because that method don't work properly (I don't know why, but it has a high fail-rate, you may see it here:.
In my country, people from non-latin-language countries usually do some translation of their names so the previous RegExp would be enough. However, if you attempt to match any surname in the world, you may add more range of \u#### characters, avoiding to include symbols, numbers or other type. Or perhaps the xregexp library may help you.
And, please, do not forget to test the input in server side, and escaping it before using it in the sql sentences (if you have them)

How to modify regex for phone numbers and accept only digits

I have this following regex method for the jquery validate plugin.
jQuery.validator.addMethod("phoneUS", function(phone_number, element) {
phone_number = phone_number.replace(/\s+/g, "");
return this.optional(element) || phone_number.length > 9 &&
phone_number.match(/^(1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/);
}, "Please specify a valid phone number");
Currently, its validating against phone numbers in this format : 203-123-1234
I need to change to validate like this: 2031231234
Does anyone have a quick and easy solution for me?
You can replace
phone_number.match(/^(1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/);
with this
phone_number.match(/\d{10}/);
\d means match any digit
and
{10} means 10 times
Getting rid of all those -? sequences is probably the quickest way - they mean zero or one - characters.
That will reduce it to:
/^(1)?(\([2-9]\d{2}\)|[2-9]\d{2})[2-9]\d{2}\d{4}$/
whih can be further simplified to:
/^1?(\([2-9]\d{2}\)|[2-9]\d{2})[2-9]\d{6}$/
If you also want to disallow the brackets around area codes, you can further simplify it to:
/^1?[2-9]\d{2}[2-9]\d{6}$/
(and, technically, it won't match the literal 203-123-1234 since the character immediately after that first - has to be 2 thru 9, so I'm assuming you were just talking about the format rather than the values there).
I think better approach would be changing the whole expression with simpler version, something like this:
/^[0-9]{10}$/
Edited, Note (see comments):
This is just a limited example of how to validate a format: 111-222-3333 vs 1112223333, not proper US phone number validation.
If you just want ten digits, then
phone_number.match(/\d{10}/)
will do it. If you want to match any of the other conditions in there (eg match both 1-2031231234 and 2031231234), you will need to add more.
As a side note, what you currently have doesn't match 203-123-1234 because the first digit after the first hyphen is a 1, and it is looking for 2-9 in that spot.
([0-9]{10}) this will match with 10 digit number.
You can use if you want to match all formats, including 203-123-1234 and 2031231234
EDIT : I'm no regex expert, but I added "1-" support
/^(?:1-?)?[(]?\d{3}[)]?\s?-?\s?\d{3}\s?-?\s?\d{4}$/
By the way, there's a really nice AIR tool for regex, it's called RegExr and you can get the desktop version here http://www.gskinner.com/RegExr/desktop/ or use the online version http://gskinner.com/RegExr/ . There's also a "community" section that contains a lot of useful working regex. That's where I took that one.

Categories

Resources