Reputation: 8127
General question
How do you prevent a regex match if that pattern has been matched N number of times previously?
Specific example
I have a 13 digit record identifier the user will type into a text field, such as "123-456-7891011".
The behavior I'm attempting to encapsulate is to add a dash before the 4th and 7th digits as they are typed. I have all the javascript around handling the event with no issues.
It will always be numeric - I handle that before this particular step.
I'm able to get the regex down well enough to insert the dash when I type the n+4th digit every time. What I need is for it to not do that any time after the second "-"
The closest I have in my event handler (oninput
) so far is:
var addDash = /([^\-\d{3}]*\d{3})(\d+)/;
this.value = this.value.replace(addDash, "$1-$2");
For example, typing "1234567891011" results in "123-456-789-101-1", where what I want is "123-456-7891011".
There are probably other ways to handle this situation (like split
and join
) but for purposes of this question let's stick to answering with correct regex pattern, if such a pattern is possible. There are other things happening that would make having this pattern very useful - I just haven't had luck fathoming it out.
For clarity, this pattern will be run oninput
on the text field - the match should work for any length of characters between 1 and 13:
"123456" -> "123-456"
"123456789" -> "123-456-789"
"1234567891011" -> 123-456-7891011"
Upvotes: 1
Views: 1269
Reputation: 1
$(function() {
var txt='1232';
var addDash = /^(\d{3})-?(\d?\d?\d?)-?(\d*)/;
$("#test").html(txt.replace(addDash, function(match, capture1, capture2, capture3) {
var firstDelimiter = (capture1.length == 3 && capture2.length > 0) ? '-' : '';
var secondDelimiter = (capture2.length == 3 && capture3.length > 0) ? '-' : '';
return capture1 + firstDelimiter + capture2 + secondDelimiter + capture3;
}));
})
Upvotes: -3
Reputation: 8127
Using regex without additional JS:
var addDash = /^((\d{3}\-?)(\d{3}\-?)?)(\d)$|^(\d{3})(\d)$/;
this.value = this.value.replace(addDash, "$1$5-$4$6");
Starting as the beginning of the string, match 3 digits with an optional "-", and optionally 3 more digits, followed immediately by a final digit at the end of the string. If that doesn't match, see if the string starts with 3 digits followed immediately by a final digit at the end of the string.
Get a little funky with the capture groups in the replace string to accomplish the desired format.
Upvotes: 0
Reputation: 1162
You can use a callback within replace with some logic on how to handle the delimiters. This will make it easier to get the behavior you are expecting.
var values = ['12', '123', '123-4', '123-45', '123-456', '123-456-7', '123-456-7891011'];
var addDash = /^(\d{3})-?(\d?\d?\d?)-?(\d*)/;
values.forEach(function(value) {
value = value.replace(addDash, function(match, capture1, capture2, capture3) {
var secondDelimiter = capture2.length == 3 ? '-' : '';
return capture1 + '-' + capture2 + secondDelimiter + capture3;
});
})
console.log(values)
Upvotes: 1
Reputation: 51330
Use callbacks.
You can specify a function as the second parameter. In this case, the function will be invoked after the match has been performed. The function's result (return value) will be used as the replacement string.
A solution specific to your current need would be to alter the pattern and always go for a full match:
this.value = this.value.replace(/^(\d{3})-?(\d{3})?-?(\d*)$/, function (m, a, b, c) {
return b ? a + "-" + b + "-" + c : a + "-" + c;
});
Job done.
If you want a more generic solution, you could use a counter variable:
var count = 0;
this.value = this.value.replace(/(\d{3})-?/g, function (m, a) {
return ++count <= 2 ? a + "-" : m;
});
This one uses a pattern that is less accurate for what you need, but it's there to demonstrate how you could generalize to different situations where you really need to limit the number of replacements.
By the way, you have a syntax misunderstanding: [^\-\d{3}]
does not mean what you think. It will match a single character that is not a digit or either of those: -
, {
or }
. Everything inside [
...]
brackets defines a character class, therefore quantifiers such as {n}
are meaningless there.
Upvotes: 3