I'm trying to insert dash into numbers but it is so hard to me...
What I want to do is that insert dash into after 3 and 4 digits, for example,
replacing 123123412345 to 123-1234-12345.
The additional condition is that I replace it in input element. So I replace the number for every input event, i.e., I need to replace like
1 to 1
12 to 12
123 to 123
1231 to 123-1
...
1231234 to 123-1234
12312341 to 123-1234-1
...
123123412345 to 123-1234-12345
How can I do this using regex ??
You may try this regex:
Regex
(?<=^\d{3}|^\d{7})(?=\d)
Substitution
-
Check the proof
const list = [
1,
12,
123,
1231,
1231234,
12312341,
123123412345
];
const regex = /(?<=^\d{3}|^\d{7})(?=\d)/g;
const result = list.map(e => regex[Symbol.replace](e, '-'));
console.log(result);
Suppose it needs to split the first 3 next 4 digits only, it can be done with following regexp replacement
str.replace(/((?<!\d)\d{3}(?!\b)|(?<=^\d{3})\d{4}(?!\b))/g, '$1-')
Input string has to be all digits
document.getElementById('input').addEventListener('keyup', (e) => {
e.target.value = e.target.value.split('-').join('').replace(/((?<!\d)\d{3}(?!\b)|(?<=^\d{3})\d{4}(?!\b))/g, '$1-');
});
['1', '12', '123', '1231', '12312', '123123', '1231234', '12312341', '123123412', '1231234123', '12312341234', '123123412345']
.forEach(t => console.log(t.replace(/((?<!\d)\d{3}(?!\b)|(?<=^\d{3})\d{4}(?!\b))/g, '$1-')));
<input id="input" type="text" size="20">
Related
Having a string like this
str = "word 12 otherword(s) 2000 19"
or like this
str = "word word 12 otherword(s) 2000 19"
I need to split the string in two, in order to have an array like this:
newstr[0] = first part of the string (i.e. "word" in the first case, "word word" in the second case);
newstr[1] = rest of the string (i.e. "12 otherword(s) 2000 19" in both cases).
I've tried to accomplish this using split and regex, without success:
str.split(/\d.*/) returns Array [ "word ", "" ] or Array [ "word word ", "" ]
while str.split(/^\D*/gm) returns Array [ "", "12 otherword(s) 2000 19" ]
Would you give me a suggestion? Even without using split and regex - if there's a better/faster (Vanilla JavaScript) solution.
There's 3 things going on here.
String.split usually doesn't includes the matched delimiter in the return array. So splitting abc.split('b') would return ['a', 'c']. This behavior can be changed by using a matching regex group; i.e. adding parens 'abc'.split(/(b)/) will return ['a', 'b', 'c'].
String.split will keep the delimter seperate from the other elements. I.e. 'abc'.split(/(b)/) will return 3 elements ['a', 'b', 'c']. Suffix the regex with .* to combine the last 2 elements: 'abc'.split(/(b.*)/) will return ['a', 'bc', ''].
Lastly, to ignore the last empty element, we send the 2nd param of 2.
let str = "word word 12 otherword(s) 2000 19";
let splitStr = str.split(/(\d.*)/, 2);
console.log(splitStr);
You can match these parts:
const strs = ["word 12 otherword(s) 2000 19", "word word 12 otherword(s) 2000 19"];
for (var s of strs) {
const [_, part1, part2] = s.match(/^(\D*)(\d+[\w\W]*)/)
console.log([part1, part2])
}
See the regex demo.
Regex details:
^ - start of a string
(\D*) - Group 1: any zero or more chars other than digits
(\d+[\w\W]*) - Group 2: one or more digits, and then any zero or more chars as many as possible.
Note you may .trim() the resulting parts when using them (print them with console.log([part1.trim(), part2.trim()])).
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
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, "#")
));
I am trying to make a regex to matches all the combinations of a given string. For example of the string is "1234", answers would include:
"1"
"123"
"4321"
"4312"
Nonexamples would include:
"11"
"11234"
"44132"
If it matters, the programming language I am using is javascript.
Thank you for any help.
You may use this lookahead based assertions in your regex:
^(?!(?:[^1]*1){2})(?!(?:[^2]*2){2})(?!(?:[^3]*3){2})(?!(?:[^4]*4){2})[1234]+$
RegEx Demo
Here we have 4 lookahead assertions:
(?!(?:[^1]*1){2}): Assert that we don't have more than one instance of 1
(?!(?:[^2]*2){2}): Assert that we don't have more than one instance of 2
(?!(?:[^3]*3){2}): Assert that we don't have more than one instance of 3
(?!(?:[^4]*4){2}): Assert that we don't have more than one instance of 4
We use [1234]+ to match any string with these 4 characters.
A combination of group captures using character classes and negative look-ahead assertions using back-references would do the trick.
Let's begin with simply matching any combination of 1, 2, 3, and 4 using a character class,[1-4], and allowing any length from 1 to 4 characters. {1,4}.
const regex = /^[1-4]{1,4}$/;
// Create set of inputs from 0 to 4322
const inputs = Array.from(new Array(4323), (v, i) => i.toString());
// Output only values that match criteria
console.log(inputs.filter((input) => regex.test(input)));
When that code is run, it's easy to see that although only numbers consisting of some combination of 1, 2, 3, and 4 are matched, it also is matching numbers with repeating combinations (e.g. 11, 22, 33, 112, etc). Obviously, this was not what was desired.
To prevent repeating characters requires a reference to previously matched characters and then a negation of them from any following matched characters. Negative look-aheads, (?!...) using a back-reference, \1-9, can accomplish this.
Building on the previous example with a subset of the inputs (limiting to a max length of two characters for the moment) would now incorporate a group match surrounding the first character, ([1-4]), followed by a negative look-ahead with a back-reference to the first capture, (?!\1), and finally a second optional character class.
const regex = /^([1-4])(?!\1)[1-4]?$/;
// Create set of inputs from 0 to 44
const inputs = Array.from(new Array(45), (v, i) => i.toString());
// Output only values that match criteria
console.log(inputs.filter((input) => regex.test(input)));
This matches the desired characters with no repetition!
Expanding this pattern to include back-references for each of the previously matched characters up to the desired max length of 4 yields the following expression.
const regex = /^([1-4])((?!\1)[1-4])?((?!\1|\2)[1-4])?((?!\1|\2|\3)[1-4])?$/;
// Create set of inputs from 0 to 4322
const inputs = Array.from(new Array(4323), (v, i) => i.toString());
// Output only values that match criteria
console.log(inputs.filter((input) => regex.test(input)));
Hope this helps!
You don't need to use regex for this. The snippet below does the following:
Loop over possible combinations (a => s) (1, 123, 4321, etc.)
Copy the current combination so as not to overwrite it (s2 = s)
Loop over the characters of test string (x => ch) (1234 => 1, 2, 3, 4)
Replace common characters in the combination string shared with the test string (s2.replace)
For example in the combination 1, the 1 will be replaced when the loop gets to the character 1 in 1234 resulting in an empty string
If the combination string's length reaches 0 (s2.length == 0) write the result to the console and break out of the loop (no point in continuing to attempt to replace on an empty string)
const x = "1234"
const a = ["1","123","4321","4312","11","11234","44132"]
a.forEach(function(s) {
var s2 = s
for(var ch of x) {
s2 = s2.replace(ch, '')
if(s2.length == 0) {
console.log(s);
break;
}
}
})
Results:
1
123
4321
4312
I want all the proper natural numbers from a given string,
var a = "#1234abc 12 34 5 67 sta5ck over # numbrs ."
numbers = a.match(/d+/gi)
in the above string I should only match the numbers 12, 34, 5, 67, not 1234 from the first word 5 etc..
so numbers should be equal to [12,34,5,67]
Use word boundaries,
> var a = "#1234abc 12 34 5 67 sta5ck over # numbrs ."
undefined
> numbers = a.match(/\b\d+\b/g)
[ '12', '34', '5', '67' ]
Explanation:
\b Word boundary which matches between a word charcter(\w) and a non-word charcter(\W).
\d+ One or more numbers.
\b Word boundary which matches between a word charcter and a non-word charcter.
OR
> var myString = '#1234abc 12 34 5 67 sta5ck over # numbrs .';
undefined
> var myRegEx = /(?:^| )(\d+)(?= |$)/g;
undefined
> function getMatches(string, regex, index) {
... index || (index = 1); // default to the first capturing group
... var matches = [];
... var match;
... while (match = regex.exec(string)) {
..... matches.push(match[index]);
..... }
... return matches;
... }
undefined
> var matches = getMatches(myString, myRegEx, 1);
undefined
> matches
[ '12', '34', '5', '67' ]
Code stolen from here.
If anyone is interested in a proper regex solution to match digits surrounded by space characters, it is simple for languages that support lookbehind (like Perl and Python, but not JavaScript at the time of writing):
(?<=^|\s)\d+(?=\s|$)
Debuggex PCRE Demo
As illustrated in the accepted answer, in languages that don't support lookbehind, it is necessary to use a hack, e.g. to include the 1st space in the match, while keepting the important stuff in a capturing group:
(?:^|\s)(\d+)(?=\s|$)
Debuggex JavaScript Demo
Then you just need to extract that capturing group from the matches, see e.g. this answer to How do you access the matched groups in a JavaScript regular expression?