Reputation: 8550
Looking for the best way to take an arbitrary number with potentially repeating decimal part, and discover the repeating part (if present).
Ultimately, I need to decorate the number with overline notation (either with css text-decoration or MathML mline), so I need to know the index of where the repetition begins also.
So I need regex that will get me (or can be used in an algorithm to get) the following results:
1.333 // result: {"pattern": 3, index: 0}
1.5444 // result: {"pattern": 4, index: 1}
1.123123 // result: {"pattern": 123, index: 0}
1.5432121212 // result: {"pattern": 12, index: 4}
1.321 // result: null
1.44212 // result: null
Additional Example (from comments):
1.3333 // result: { "pattern": 3, index: 0}
Upvotes: 3
Views: 1267
Reputation: 26161
The accepeted answer is OKish as per the given examples in the question are concerned. However if one day you find yourself here what you probably need is exactly what the topic says.
/(\d+)\1+(?=\d*$)/g
Now this is not a silver bullet. It's helpful but won't protect you from vampires like 3.1941070707811985
which happens to have no repetend at all. In order to feel it you have to develop deeper mechanisms. However in most cases it's just fine in percieving the repend like in
3.1941070707811985 // 07 which is wrong so prove it later
7.16666666810468 // 666 but reduce it to 6 later
3.00000000000001 // 000000 but reduce it to "" later
0.008928571428571428 // 285714 just fine, do nothing
It is not an easy task to find if the floating part of a decimal has repetends or not in this environment. Most possibly you need to do further processing on the given string and the result of the regex for futher reduction / decision.
Upvotes: 0
Reputation: 288020
function getRepetend(num) {
var m = (num+'').match(/\.(\d*?)(\d+?)\2+$/);
return m && {pattern: +m[2], index: m[1].length};
}
It works like this:
/\.(\d*?)(\d+)\2+$/
:
\.
matches the decimal dot.(\d*?)
matches the digits between the decimal dot and the repetend, and captures the result into backreference number 1.(\d+?)
matches the repetend, and captures it into backreference number 2.\2+
matches repetitions of the repetend.$
matches end of string.null
(i.e. there is no match), return null
.Upvotes: 8
Reputation: 784998
You can use this regex with RexExp#exec
and use result.index
in the resulting object:
var re = /(\d+)\1$/;
var s = '.5439876543212211211';
var result = re.exec( s );
console.log ( result.index );
//=> 14
console.log ( result[1] );
//=> 211
Upvotes: 3
Reputation: 45135
You could try something like this:
(\d+?)\1+$
http://regex101.com/r/eX8eC3/3
It matched some number of digits and then uses a backreference to try and match the same set immediately afterwards 1 or more times. It's anchored at the end of the string because otherwise it'll be tripped up by, for example:
1.5432121212
It would see the 21
repeating instead of the 12
.
Adding ?
to the first group to make it non-greedy should fix the problem with 1.3333
as raised by Louis.
Upvotes: 7