最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

JavaScript Regex to capture repeating part of decimal - Stack Overflow

programmeradmin3浏览0评论

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 ments):

1.3333 // result: { "pattern": 3, index: 0}

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 ments):

1.3333 // result: { "pattern": 3, index: 0}
Share Improve this question edited Oct 14, 2014 at 18:20 mtyson asked Oct 14, 2014 at 14:29 mtysonmtyson 8,56017 gold badges76 silver badges113 bronze badges 5
  • 3 You should add at least one additional case to your list of examples: 1.3333 // result: { "pattern": 3, index: 0} because a lot of the answers below are failing on this case. (I'm assuming you want a general solution and not just one that will work for some numbers.) – Louis Commented Oct 14, 2014 at 15:47
  • 4 Do you care that this approach will incorrectly claim that the decimal representations of non-repeating fractions (like 133/100 - exactly 1.33) are repeating? – nobody Commented Oct 14, 2014 at 15:52
  • @AndrewMedico: A really good point. – Matt Burland Commented Oct 14, 2014 at 15:54
  • 5 How would a number like 5/3 be represented? 1.66666667? – Jonathan S. Commented Oct 14, 2014 at 16:26
  • @AndrewMedico - No, its really just a display function, so if the client passes in a number to it, they know what they are getting back. – mtyson Commented Oct 14, 2014 at 17:11
Add a ment  | 

5 Answers 5

Reset to default 8
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).

You could try something like this:

(\d+?)\1+$

http://regex101./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.

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

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

Try this.See demo.

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

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.

发布评论

评论列表(0)

  1. 暂无评论