Example strings :
2222
333333
12345
111
123456789
12345678
Expected result:
2#222
333#333
12#345
111
123#456#789
12#345#678
i.e. '#' should be inserted at the 4th,8th,12th etc last position from the end of the string.
I believe this can be done using replace and some other methods in JavaScript.
for validation of output string i have made the regex :
^(\d{1,3})(\.\d{3})*?$
You can use this regular expression:
/(\d)(\d{3})$/
this will match and group the first digit \d and group the last three \d{3} which are then grouped in their own group. Using the matched groups, you can then reference them in your replacement string using $1 and $2.
See example below:
const transform = str => str.replace(/(\d)(\d{3})$/, '$1#$2');
console.log(transform("2222")); // 2#222
console.log(transform("333333")); // 333#333
console.log(transform("12345")); // 12#345
console.log(transform("111")); // 111
For larger strings of size N, you could use other methods such as .match() and reverse the string like so:
const reverse = str => Array.from(str).reverse().join('');
const transform = str => {
return reverse(reverse(str).match(/(\d{1,3})/g).join('#'));
}
console.log(transform("2222")); // 2#222
console.log(transform("333333")); // 333#333
console.log(transform("12345")); // 12#345
console.log(transform("111")); // 111
console.log(transform("123456789")); // 123#456#789
console.log(transform("12345678")); // 12#345#678
var test = [
'111',
'2222',
'333333',
'12345',
'123456789',
'1234567890123456'
];
console.log(test.map(function (a) {
return a.replace(/(?=(?:\B\d{3})+$)/g, '#');
}));
You could match all the digits. In the replacement insert an # after every third digit from the right using a positive lookahead.
(?=(?:\B\d{3})+$)
(?= Positive lookahead, what is on the right is
(?:\B\d{3})+ Repeat 1+ times not a word boundary and 3 digits
$ Assert end of string
) Close lookahead
Regex demo
const regex = /^\d+$/;
["2222",
"333333",
"12345",
"111",
"123456789",
"12345678"
].forEach(s => console.log(
s.replace(/(?=(?:\B\d{3})+$)/g, "#")
));
Related
I have the test string
ti: harry Potter OR kw: magic AND sprint: title OR ti: HARRY
and want the output as
["ti: harry Potter OR kw:", "kw: magic AND sprint:", "sprint: title OR ti:", "ti: HARRY"]
but the output I am getting is
["ti: harry Potter OR kw:", "kw: magic AND sprint:", "nt: title OR ti:", "ti: HARRY"]
It is taking only 2 characters before the colon
The regex I am using is
const match = /[a-z0-9]{2}:.*?($|[a-z0-9]{2}:)/g;
and I am extracting it and putting it in an array
I tried replacing it with /[a-z0-9]+:.*?($|[a-z0-9]+:)/g; but when I increase index and add the strings to parsed, it does it weirdly (This is included in code as well)
I tried changing the {2} to n and that is also not working as expected.
const parsed = [];
const match = /[a-z0-9]{2}:.*?($|[a-z0-9]{2}:)/g;
const message = "ti: harry Potter OR kw: magic AND sprint: title OR ti: HARRY";
let next = match.exec(message);
while (next) {
parsed.push(next[0]);
match.lastIndex = next.index + 1;
next = match.exec(message);
console.log("next again", next);
}
console.log("parsed", parsed);
https://codesandbox.io/s/regex-forked-6op514?file=/src/index.js
For the desired matches, you might use a pattern where you would also optionally match AND or OR and get the match in capture group 1, which is denoted be m[1] in the example code.
\b(?=([a-z0-9]+:.*?(?: (?:AND|OR) [a-z0-9]+:|$)))
In parts, the pattern matches:
\b A word boundary to prevent a partial match
(?= Positive lookahead to assert what is on the right is
( Capture group 1
[a-z0-9]+:
.*? Match any char except a newline as least as possible
(?: Non capture group
(?:AND|OR) [a-z0-9]+: Match either AND or OR followed by a space and 1+ times a char a-z0-9 and :
| Or
$ Assert the end of the string
) Close non capture group
) Close group 1
) Close the lookahead
See a regex demo.
const regex = /\b(?=([a-z0-9]+:.*?(?: (?:AND|OR) [a-z0-9]+:|$)))/gm;
const str = `ti: harry Potter OR kw: magic AND sprint: title OR ti: HARRY`;
const result = Array.from(str.matchAll(regex), m => m[1]);
console.log(result);
I'm trying to write a regex function that return all of the digits in a comma separated string:
function printDigits() {
var result = sentence.replace(/[^0-9]/g, '').split(",")
console.log(result)
}
But it just prints out a string instead of digits being separated by comma. Are there any ways I can fix this?
Input: "5om3 wr173 w0rd5 u51n9 numb3r5."
Expected output: "5,3,1,7,3,0,5,5,1,9,3,5"
split doesn't work this way. It splits by the separator that is already in the input. To split string to individual characters use split(''), and then join individual characters with comma:
var result = sentence.replace(/[^0-9]/g, '').split('').join(',');
You can use
sentence.match(/\d/g).join(",")
Here,
sentence.match(/\d/g) - extracts each separate digit from string
.join(",") - join the array items into a single comma-delimited string.
See the JavaScript demo:
var sentence = "5om3 wr173 w0rd5 u51n9 numb3r5.";
console.log(sentence.match(/\d/g).join(","));
// -> 5,3,1,7,3,0,5,5,1,9,3,5
Here's another variation that uses pure regex and does not require a .join() call:
sentence.replace(/\D+|(\d)(?=\d)/g, '$1,');
This replaces any string of non-digit characters with a comma. And it also locates the position between two digits and adds a comma between them.
Pattern breakdown:
\D+ - Match one or more non-digit characters.
| - OR...
(\d) - Match one digit and capture it in group 1.
(?=\d) - Followed by another digit.
Substition:
$1, - Replace with whatever was captured in group 1, plus a comma.
Here's a full demo:
var sentence = "5om3 wr173 w0rd5 u51n9 numb3r5";
var result = sentence.replace(/\D+|(\d)(?=\d)/g, '$1,');
console.log(result); // 5,3,1,7,3,0,5,5,1,9,3,5
A reducer solution
const x = `5om3 wr173 w0rd5 u51n9 numb3r5`
.split('')
.reduce((acc, val) =>
val.trim().length && !isNaN(+val) ? [...acc, +val] : acc, []);
console.log(`${x}`);
Or simply
console.log(`${`5om3 wr173 w0rd5 u51n9 numb3r5`.match(/\d/g)}`);
I need to get everything but the first 6 digits and last 4 of a card number without special chars, which is a string that can be as follow:
4500 1234 5678 7654
Or
4500-1234-5678-7654
So I would need to get: 345678
So far I was able to get the inverse values out using this:
^(\d[\- ]?){6}|[\- ]|(\d[\- ]?){4}$
Note: I'm using match() instead of replace() due to the business-specific use case in Nodejs.
UPDATE:
Thanks, everyone for your help so far! It actually needs to be in one function if possible. Also, credit cards' length variate from 13 to 18 digits, which makes problematic to rely on its length or position to get mid value.
You need to do it in two steps. First, remove all the non-digits with a regexp replacement. Then use substring() to get the desired substring.
function middle_digits(cardnum) {
let nondigits = cardnum.replace(/\D/g, '');
return nondigits.substring(6, nondigits.length-4);
}
console.log(middle_digits('4500 1234 5678 7654'));
console.log(middle_digits('4500-1234-5678-7654'))
You can use the second group of (\d{4}[ -]+\d{2})(\d{2}[ -]*\d{4})
See https://regex101.com/r/CFoh7m/1
I think the requirement to match numbers excluding fillers (spaces and dashes) as stated is not possible with a single regex. You can match multiple groups, then combine them. Or, you can match the required range, and then filter out the fillers. here is the latter approach:
const input = [
'4500 1234 5678 7654',
'4500-1234-5678-9012',
'1234-5678-9012-3',
'1234-5678-9012-3456-78'
];
const regex = /(?<=^(\d(?:[^\d]?)){6})((?:\d[^\d]?){3,})(?=(?:\d[^\d]?){4}$)/;
input.forEach(str => {
let matched = str.match(regex);
let cleaned = matched[0].replace(/[^\d]/g, '');
console.log(str);
console.log('=> matched: ' +matched);
console.log('=> cleaned: ' +cleaned);
});
Output:
4500 1234 5678 7654
=> matched: 34 5678 ,4,34 5678
=> cleaned: 345678
4500-1234-5678-9012
=> matched: 34-5678-,4,34-5678-
=> cleaned: 345678
1234-5678-9012-3
=> matched: 78-9,1,78-9
=> cleaned: 789
1234-5678-9012-3456-78
=> matched: 78-9012-34,1,78-9012-34
=> cleaned: 78901234
Explanation:
(?<=^(\d(?:[^\d]?)){6}) - positive lookbehind scanning from start over 6 numbers, each followed by optional filler
((?:\d[^\d]?){3,}) - capture group, expect 3+ numbers, each followed by optional filler
(?=(?:\d[^\d]?){4}$) - positive lookahead scanning over 4 numbers, each followed by optional filler, up to end of string
I have the text
var text = (hello) world this is (hi) text
I want to write a regex function so I can get
parseText(text) // returns ['hello', 'hi']
I tried this but not work:
'(hello) world this is (hi) text'.match('((.*?))')
Thanks for your help
you can try with:
/\([^\)]+\)/g
\(: escaped char
[^\)]+: one or more character(including symbols) until ) char.
\): escaped char
g flag: search all coincidences
const regex = /\([^\)]+\)/g;
const str = `(hello) world this is (hi) text`;
console.log(
str.match(regex) // this returns an string array
.map(i => i.slice(1, -1)) // remove first and last char
);
TIPS:
About point #2, you can change to [\)]* to take effect over zero
or more character.
If you need only string, you can use \w+ or \w*.
If you need only words you can use /\(\b\w+\b\)/g
You can find several options in this post.
Apart from using groups or postprocessing of the match results, you can use single regex match using lookahead / lookbehind:
var text = " (hello) world this is (hi) text"
var output = text.match(/(?<=\().*?(?=\))/g)
console.log(output)
output:
[ 'hello', 'hi' ]
Explanation:
(?<=...) ... positive lookbehind. The match is preceded be ..., but the ... is not included in the match
(?<=\() ... positive lookbehind for ( character
.* ... zero or more times of any character
.*? ... nongreedy version of .*
(?=...) ... positive lookahead, the match is followed by ... but the ... is not included in the match
(?=\)) ... positive lookahead for ) character
/.../g ... g is global flag, match finds all, not only the first, occurrence
do not forget to escape "special characters", e.g. parentheses
'(hello) world this is (hi) text'.match(/\([\w]*\)/g)
This returns [ "(hello)", "(hi)" ] and you can run another parse function to remove that extra parenthesis.
const text = '(hello) world this is (hi) text';
const list = text.match(/\([\w]*\)/g);
const parsed = list.map(item => item.replace(/\(|\)/g, ''));
console.log(parsed);
I need to parse a string that comes like this:
-38419-indices-foo-7119-attributes-10073-bar
Where there are numbers followed by one or more words all joined by dashes. I need to get this:
[
0 => '38419-indices-foo',
1 => '7119-attributes',
2 => '10073-bar',
]
I had thought of attempting to replace only the dash before a number with a : and then using .split(':') - how would I do this? I don't want to replace the other dashes.
Imo, the pattern is straight-forward:
\d+\D+
To even get rid of the trailing -, you could go for
(\d+\D+)(?:-|$)
Or
\d+(?:(?!-\d|$).)+
You can see it here:
var myString = "-38419-indices-foo-7119-attributes-10073-bar";
var myRegexp = /(\d+\D+)(?:-|$)/g;
var result = [];
match = myRegexp.exec(myString);
while (match != null) {
// matched text: match[0]
// match start: match.index
// capturing group n: match[n]
result.push(match[1]);
match = myRegexp.exec(myString);
}
console.log(result);
// alternative 2
let alternative_results = myString.match(/\d+(?:(?!-\d|$).)+/g);
console.log(alternative_results);
Or a demo on regex101.com.
Logic
lazy matching using quantifier .*?
Regex
.*?((\d+)\D*)(?!-)
https://regex101.com/r/WeTzF0/1
Test string
-38419-indices-foo-7119-attributes-10073-bar-333333-dfdfdfdf-dfdfdfdf-dfdfdfdfdfdf-123232323-dfsdfsfsdfdf
Matches
Further steps
You need to split from the matches and insert into your desired array.