Formatting a phone number in specific way? - javascript

This is not a duplicate, the linked thread does not explain how to achieve this.
I'm looking to get a phone number in a specific format.
+xx (x) xxx xxx xxxx
Country code.
Space.
Zero in brackets.
Space.
3 digits.
Space.
3 digits.
Space.
4 digits.
The user could type anything in (but should always be a +61 number). So far I have tried the below.
Removing spaces and non numeric characters.
If starting with a zero, remove.
If starting with 610, remove.
If starting with 61, remove.
Re add country code in specific format and format rest of phone number is a 3,3,4 format.
My question, is - is there a way to simply the below to perhaps one expression?
value = value.replace(/\D/g,'');
value = value.startsWith(0) ? value.substring(1) : value;
value = value.startsWith('610') ? value.substring(3) : value;
value = value.startsWith('61') ? value.substring(2) : value;
value = '+61 (0) ' + value.replace(/\d{3,4}?(?=...)/g, '$& ');

To expand and explain on #splash58's comment they propose using two regular expressions to do the full replacement you desire. The first(/\D|(0+|610|61)/gi) will remove all unwanted characters within the string. The second (/(\d{3})(\d{3})(\d{4})/gi) will take the remaining digits and capture the desired groupings so you can format them as desired. I highly suggest looking at the regex101 links they provided as that site will fully explain how and why a given expressions matches what it does on the right.
Short version:
/\D|(0+|610|61)/gi will match any NON-digit character OR a string of 0s, "610" or "61". Replace this with nothing to remove
/(\d{3})(\d{3})(\d{4})/gi will match a string of 10 digits and capture groups, that's what the parentheses are, of 3 digits, 3 digits and 4 digits. These can be referenced in the replacement as identifiers $1, $2 and $3 according to their position.
Putting it all together:
// look in a string and return formatted phone number only
function phone(str) {
str = str.replace(/\D|(0+|610|61)/gi, '');
str = str.replace(/(\d{3})(\d{3})(\d{4})/gi, '+61 (0) $1 $2 $3');
return str;
}
console.log(phone('xgsh6101231231234vvajx'));
console.log(phone('+6101231231234'));
I would also recommend first doing a search on the entire input string for a series of numbers or whitespace so that you end up with less false positives. This can be done with a regular expression like /[\d\s]+/

You might match the number using:
^.*?\+?0*610?(\d{3})(\d{3})(\d{4})(?!\d).*$
Regex demo
And replace with:
+61 (0) $1 $2 $3
Explanation
^ Assert the start of the string
.*? Match 0+ characters non greedy
\+? Match an optional plus sign
0*610? Match 0+ times a zero, 61 with optional zero
(\d{3})(\d{3})(\d{4}) match 3 groups with 3, 3, and 4 digits
(?!\d) Negative lookahead to assert what follows is not a digit
.* Match 0+ characters
$ Assert the end of the string
const strings = [
"xgsh6101231231234vvajx",
"xgsh06101231231234vvajx",
"xgsh000006101231231234vvajx",
"+6101231231234",
"xgsh61012312312345vvajx",
"xgsh5101231231234vvajx",
"xgsh00000101231231234vvajx",
"xgsh6143545626455345601231231234vvajx"
];
let pattern = /^.*?\+?0*610?(\d{3})(\d{3})(\d{4})(?!\d).*$/;
strings.forEach((s) => {
console.log(s.replace(pattern, "+61 (0) $1 $2 $3"));
});

Related

Javascript Regular Expressions - Replace non-numeric characters

I have this line:
val = val.replace(/[^0-9\.]/g, '')
and it replaces anything that is not a number, but I need a regular expression that limits val to be 2 numbers, period and then 2 numbers, like this:
- 11.33
- 12.34
- 54.65
I've already tried something like this but it didn't work:
val = val.replace(/^[^0-9\.]{1,2}/g, '')
Normally with replace you scan the entire string and keep the middle part. So start with beginning (^), scan some stuff you don't care about (.), then scan your number ([0-9]{1,2}(?:.[0-9]{0-2})?), then scan the rest which you don't care about (.), then you're at the end ($).
Then you replace with the middle capture group.
val.replace(/^(.*)([0-9]{1,2}(?:\.[0-9]{0-2})?)(.*)$/gm,'\2');
Use the m flag to process line by line.
Sometimes it is easier to use multiple regexes instead of one. Here is a solution that uses a first regex to strip the string from anything but number digits, then a second regex that reduces the number string to the proper length:
const regex1 = /[^\d\.]/g;
const regex2 = /^.*(\d\d\.\d\d).*$/;
[
'aaa11.33zzz',
'aaa123.456zzz',
'-54.65',
'12xtra.34'
].forEach(str => {
let result = str.replace(regex1, '').replace(regex2, '$1');
console.log(str, '==>', result);
});
Output:
aaa11.33zzz ==> 11.33
aaa123.456zzz ==> 23.45
-54.65 ==> 54.65
12xtra.34 ==> 12.34
Explanation of regex1:
[^\d\.] -- anything not 0-9 and .
g -- flag to replace pattern multiple times
Explanation of regex2:
^ -- anchor at start of string
.* -- greedy scan
(\d\d\.\d\d) -- expect 2 digits, a dot, and 2 digits
.* -- greedy scan
$ -- anchor at end of string
You did not specify what should happen if the input string has less than the 2digits, dot, 2 digits pattern. So this solution does not address that case.

Regular expression that matches 5 (exactly) comma separated currency values

I need to match 5 occurrences of comma separated currency values.
I do have this reg ex that does the job but I think that's not the great way to do it.
^(\$[0-9]{1,3}(?:[,.]?[0-9]{3})*(?:\.[0-9]{2})?,\s?){4}(\$[0-9]{1,3}(?:[,.]?[0-9]{3})*(?:\.[0-9]{2})?)$
P.S. I had to split the expression into matching, 4 comma separated occurrences and 1 to sniff out trailing comma (I don't think that's the way to do it)
Some of the valid matching inputs could be,
$200,000,$525,$60000,$120,000,$65,456 (space between currency values is optional)
$200,000, $525, $60000,$120,000, $65,456
Some of the invalid input values,
$200,000,$525,$60000,$120,000,$65,456, (Trailing comma)
$200,000,,$525,$60000.$120,000,$65,456,, etc
Any pointers would be greatly appreciated.
Edit: The solution I am looking at is a pure reg ex solution (better than what I have written above), so that I can fire validations as soon as erroneous inputs are entered by the user.
Update
If you want to match while validating prices you could do this which follows:
Including both dot and comma for formatting prices
Max one space character between prices
^\$\d+([,.]\d{3})*( ?, ?\$\d+([,.]\d{3})*){4}$
Live demo
Breakdown:
^ Match start of input string (or line if m flag is set)
\$\d+ Match a $ that preceds a number of digits
( Start of grouping (#1)
[,.]\d{3} Match a period or comma that preceds 3 digits
)* End of grouping (#1), match at least zero time
( Start of grouping (#2)
?, ? Match a comma surrounded by optional spaces (one space at either side)
\$\d+ Match a $ that preceds a number of digits
([,.]\d{3})* Match a period or comma that preceds 3 digits (thousand separator), match at least zero time
){4} End of grouping (#2), repeat exactly 4 times
$ End of input string (or line if m flag is set)
JS code:
var re = /^\$\d+([,.]\d{3})*( ?, ?\$\d+([,.]\d{3})*){4}$/g;
var prices = ['$200,000,$525,$60000,$120,000,$65,456',
'$200,000, $525, $60000,$120,000, $65,456',
'$200,000,$525,$60000,$120,000,$65,456, ',
'$200,000,,$525,$60000.$120,000,$65,456,,'];
prices.forEach(function(s) {
console.log(s + " => " + Boolean(s.match(re)))
})
This regex is a simpler version of what you're trying to achieve:
^(?:\$\d{1,3}(?:,?\d{3})*[,.] ?){4}\$\d{1,3}(?:,?\d{3})*$
-------------------------------
The underlined part matches 4 "prices" as you've defined, followed by a dot/comma and an optional space.
The rest matches the last "price".
Please let me know if something is unclear
The most prevalent character to base the pattern on is \$ (escaped), whether it is the first character of the string or preceded by a comma (optionally followed by whitespace), that is done using (?:^|,)\s*. After that you want any number of digits, which is \d+, optionally followed by a comma which is immediately followed by digits again; ,\d+.
Combining these, you'd get; /(?:^|,)\s*(\$\d+(?:,\d+)?)/g
const pattern = /(?:^|,|\.)\s*(\$\d+(?:,\d+)?)/g;
const test = [
'$200,000,$525,$60000,$120,000,$65,456',
'$200,000, $525, $60000,$120,000, $65,456',
'$200,000,$525,$60000,$120,000,$65,456,',
'$200,000,,$525,$60000.$120,000,$65,456,,',
];
const matches = test.reduce((carry, string) => {
let match = null;
while (match = pattern.exec(string)) {
carry.push(match[1]);
}
return carry;
}, []);
console.log(matches);
Added the extra examples from the modified question, including the . which now appeared as separator ($200,000,,$525,$60000.$120,000,$65,456,,) and modified the pattern in the example to account for this.

How does the following code mean two consecutive numbers?

This is from an exercise on FCC beta and i can not understand how the following code means two consecutive numbers seeing how \D* means NOT 0 or more numbers and \d means number, so how does this accumulate to two numbers in a regexp?
let checkPass = /(?=\w{5,})(?=\D*\d)/;
This does not match two numbers. It doesn't really match anything except an empty string, as there is nothing preceding the lookup.
If you want to match two digits, you can do something like this:
(\d)(\d)
Or if you really want to do a positive lookup with the (?=\D*\d) section, you will have to do something like this:
\d(?=\D*\d)
This will match against the last digit which is followed by a bunch of non-digits and a single digit. A few examples (matched numbers highlighted):
2 hhebuehi3
^
245673
^^^^^
2v jugn45
^ ^
To also capture the second digit, you will have to put brackets around both numbers. Ie:
(\d)(?=\D*(\d))
Here it is in action.
In order to do what your original example wants, ie:
number
5+ \w characters
a non-number character
a number
... you will need to precede your original example with a \d character. This means that your lookups will actually match something which isn't just an empty string:
\d(?=\w{5,})(?=\D*\d)
IMPORTANT EDIT
After playing around a bit more with a JavaScript online console, I have worked out the problem with your original Regex.
This matches a string with 5 or more characters, including at least 1 number. This can match two numbers, but it can also match 1 number, 3 numbers, 12 numbers, etc. In order to match exactly two numbers in a string of 5-or-more characters, you should specify the number of digits you want in the second half of your lookup:
let regex = /(?=\w{5,})(?=\D*\d{2})/;
let string1 = "abcd2";
let regex1 = /(?=\w{5,})(?=\D*\d)/;
console.log("string 1 & regex 1: " + regex1.test(string1));
let regex2 = /(?=\w{5,})(?=\D*\d{2})/;
console.log("string 1 & regex 2: " + regex2.test(string1));
let string2 = "abcd23";
console.log("string 2 & regex 2: " + regex2.test(string2));
My original answer was about Regex in a vacuum and I glossed over the fact that you were using Regex in conjunction with JavaScript, which works a little differently when comparing Regex to a string. I still don't know why your original answer was supposed to match two numbers, but I hope this is a bit more helpful.
?= Positive lookahead
w{5,} matches any word character (equal to [a-zA-Z0-9_])
{5,}. matches between 5 and unlimited
\D* matches any character that\'s not a digit (equal to [^0-9])
* matches between zero and unlimited
\d matches a digit (equal to [0-9])
This expression is global - so tries to match all
You can always check your expression using regex101

How to match digit in middle of a string efficiently in javascript?

I have strings like
XXX-1234
XXXX-1234
XX - 4321
ABCDE - 4321
AB -5677
So there will be letters at the beginning. then there will be hyphen. and then 4 digits. Number of letters may vary but number of digits are same = 4
Now I need to match the first 2 positions from the digits. So I tried a long process.
temp_digit=mystring;
temp_digit=temp_digit.replace(/ /g,'');
temp_digit=temp_digit.split("-");
if(temp_digit[1].substring(0,2)=='12') {}
Now is there any process using regex / pattern matching so that I can do it in an efficient way. Something like string.match(regexp) I'm dumb in regex patterns. How can I find the first two digits from 4 digits from above strings ? Also it would be great it the solution can match digits without hyphens like XXX 1234 But this is optional.
Try a regular expression that finds at least one letter [a-zA-Z]+, followed by some space if necessary \s*, followed by a hyphen -, followed by some more space if necessary \s*. It then matches the first two digits \d{2} after the pattern.:
[a-zA-Z]+\s*-\s*(\d{2})
may vary but number of digits are same = 4
Now I need to match the first 2 positions from the digits.
Also it would be great it the solution can match digits without hyphens like XXX 1234 But this is optional.
Do you really need to check it starts with letters? How about matching ANY 4 digit number, and capturing only the first 2 digits?
Regex
/\b(\d{2})\d{2}\b/
Matches:
\b a word boundary
(\d{2}) 2 digits, captured in group 1, and assigned to match[1].
\d{2} 2 more digits (not captured).
\b a word boundary
Code
var regex = /\b(\d{2})\d{2}\b/;
var str = 'ABCDE 4321';
var result = str.match(regex)[1];
document.body.innerText += result;
If there are always 4 digits at the end, you can simply slice it:
str.trim().slice(-4,-2);
here's a jsfiddle with the example strings:
https://jsfiddle.net/mckinleymedia/6suffmmm/

matching any characters but a number (negative, decimal)

I need your help as I'm stuck on a regular expression.
The regular expression needs to match any characters but the first number.
This first number can be an integer, negative, decimal.
so I have the RegExp for that:
var b = /[-]?[0-9]+([\.][0-9]+)?/;
but when I do that in JavaScript:
var a = 'ab123ab45',
b = /[-]?[0-9]+([\.][0-9]+)?/;
a.replace(b, '');
it obviously return: abab45
But what I need, as you may understood, is the other way around.
Here are some examples.
123 -> 123
123a -> 123
a123a -> 123
123ab45 -> 123
ab123ab45 -> 123
a1b2c3 -> 1
a1.2b -> 1.2
a1,2b -> 1
And I need to get that using only 1 regular expression with the replace function.
If you need it with replace (not with match):
var a = 'ab123ab45',
b = /.*?([-]?[0-9]+([\.][0-9]+)?).*/;
a.replace(b, '$1');
Try:
m = a.match(b);
console.log(m[0]);
Try this;
var a = "a1b2c3";
a = a.replace(/^.*?([.,\d]+).*?$/, "$1");
alert(a);
LIVE DEMO
Regex Explanation
^.*?([.,\d]+).*?$
Assert position at the beginning of the string «^»
Match any single character that is not a line break character «.*?»
Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
Match the regular expression below and capture its match into backreference number 1 «([.,\d]+)»
Match a single character present in the list below «[.,\d]+»
Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
One of the characters “.,” «.,»
A single digit 0..9 «\d»
Match any single character that is not a line break character «.*?»
Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
Assert position at the end of the string (or before the line break at the end of the string, if any) «$»

Categories