mtyson
mtyson

Reputation: 8550

JavaScript Regex to capture repeating part of decimal

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

Answers (5)

Redu
Redu

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.

JavaScript Regex to capture repeating part of decimal

So you have the floating part of a string and you want to know if it is repeating or not. The accepted answer fails in practice. You can never guarantee that the string ends when the repeating part ends. Most of the time the string ends with a portion of the repeating part or sometimes *thanks* to the double precision errors jumps to irrelevant figures towards the end. So my suggestion is
/(\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

Oriol
Oriol

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:

  • First, convert the number to string in order to be able to use regular expressions.
  • Then, match this regex: /\.(\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.
  • Finally, if the match is null (i.e. there is no match), return null.
  • Otherwise, return an object that contains the repetend (backreference 2) converted to number, and the number of digits between the dot and the repetend (backreference 1).

Upvotes: 8

anubhava
anubhava

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

JsFiddle Demo

Upvotes: 3

Matt Burland
Matt Burland

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

vks
vks

Reputation: 67968

(.+)(?:\1)+$

Try this.See demo.

http://regex101.com/r/uH3tP3/10

Upvotes: 1

Related Questions