在循环小数中找到模式的正则表达式

时间:2022-09-13 12:15:42

How can I form a regular expression that match the unique numbers that repeat in a repeating decimals?

如何形成一个正则表达式来匹配重复小数中的唯一数字?

Currently my regular expressions is the following.

目前我的正则表达式如下。

var re = /(?:[^\.]+\.\d*)(\d+)+(?:\1)$/;

Example:

例子:

// Pass
deepEqual( func(1/111), [ "0.009009009009009009", "009" ] );

// Fails, since func(11/111) returns [ "0.099099099099099", "9" ]
deepEqual( func(11/111), [ "0.099099099099099", "099" ] );


Live demo here: http://jsfiddle.net/9dGsw/

现场演示:http://jsfiddle.net/9dGsw/

Here's my code.

这是我的代码。

// Goal: Find the pattern within repeating decimals.
// Problem from: Ratio.js <https://github.com/LarryBattle/Ratio.js>

var func = function( val ){
    var re = /(?:[^\.]+\.\d*)(\d+)+(?:\1)$/;
    var match = re.exec( val );
    if( !match ){
        val = (val||"").toString().replace( /\d$/, '' );
        match = re.exec( val );
    }
    return match;
};
test("find repeating decimals.", function() {
    deepEqual( func(1), null );
    deepEqual( func(1/10), null );
    deepEqual( func(1/111), [ "0.009009009009009009", "009" ] );

    // This test case fails...
    deepEqual( func(11/111), [ "0.099099099099099", "099" ], 
        "What's wrong with re in func()?" );

    deepEqual( func(100/111), [ "0.9009009009009009", "009"] );
    deepEqual( func(1/3), [ "0.3333333333333333", "3"]);
});

2 个解决方案

#1


2  

Ok. I somewhat solved my own problem by taking Joel's advice.

好的。我采纳了乔尔的建议,在某种程度上解决了我自己的问题。

The problem was that the regular expression section, (\d+)+(?:\1)$, was matching the pattern closest to the end of the string, which made it return "9", instead of "099" for the string "0.099099099099099".

问题是正则表达式部分(\d+)+(? \1)$,是匹配最接近字符串末尾的模式,这使得它返回“9”,而不是“099”的字符串“0.099099099099”。

The way I overcame this problem was by setting the match length to 2 or greater, like so.

我克服这个问题的方法是将比赛长度设置为2或更大,就像这样。

(\d{2,})+(?:\1)$,

(\ d { 2 })+(?:\ 1)美元,

and filtering the result with /^(\d+)(?:\1)$/, incase that a pattern is stuck inside a pattern.

和过滤的结果/ ^(\ d +)(?:\ 1)/美元,装进箱,模式是被困在一个模式。

Here's the code that passes all my test cases.

这是通过我所有测试用例的代码。

Live Demo: http://jsfiddle.net/9dGsw/1/

现场演示:http://jsfiddle.net/9dGsw/1/

var func = function( val ){
    val = (val || "").toString();
    var RE_PatternInRepeatDec = /(?:[^\.]+\.\d*)(\d{2,})+(?:\1)$/, 
        RE_RepeatingNums = /^(\d+)(?:\1)$/,
        match = RE_PatternInRepeatDec.exec( val );

    if( !match ){
        // Try again but take off last digit incase of precision error.
        val = val.replace( /\d$/, '' );
        match = RE_PatternInRepeatDec.exec( val );
    }
    if( match && 1 < match.length ){
        // Reset the match[1] if there is a pattern inside the matched pattern.
       match[1] = RE_RepeatingNums.test(match[1]) ? RE_RepeatingNums.exec(match[1])[1] : match[1];
    }
    return match;
};

Thank you for everyone that helped.

谢谢大家的帮助。

#2


1  

Use: var re = /^(?:\d*)\.(\d{1,3})(?:\1)+$/

用途:var re = / ^ \(?:\ d *)。(\ d { 1,3 })(?:\ 1)+ /美元

I have defined the min/max length with {min,max} of the repeating decimal because otherwise 009009009 would match in the first test case as well. Maybe it is still not the final solution, but at least a hint.

我已经用循环小数的{min,max}定义了最小/最大长度,否则009009009009009在第一个测试用例中也会匹配。也许这还不是最终的解决方案,但至少是一个提示。

#1


2  

Ok. I somewhat solved my own problem by taking Joel's advice.

好的。我采纳了乔尔的建议,在某种程度上解决了我自己的问题。

The problem was that the regular expression section, (\d+)+(?:\1)$, was matching the pattern closest to the end of the string, which made it return "9", instead of "099" for the string "0.099099099099099".

问题是正则表达式部分(\d+)+(? \1)$,是匹配最接近字符串末尾的模式,这使得它返回“9”,而不是“099”的字符串“0.099099099099”。

The way I overcame this problem was by setting the match length to 2 or greater, like so.

我克服这个问题的方法是将比赛长度设置为2或更大,就像这样。

(\d{2,})+(?:\1)$,

(\ d { 2 })+(?:\ 1)美元,

and filtering the result with /^(\d+)(?:\1)$/, incase that a pattern is stuck inside a pattern.

和过滤的结果/ ^(\ d +)(?:\ 1)/美元,装进箱,模式是被困在一个模式。

Here's the code that passes all my test cases.

这是通过我所有测试用例的代码。

Live Demo: http://jsfiddle.net/9dGsw/1/

现场演示:http://jsfiddle.net/9dGsw/1/

var func = function( val ){
    val = (val || "").toString();
    var RE_PatternInRepeatDec = /(?:[^\.]+\.\d*)(\d{2,})+(?:\1)$/, 
        RE_RepeatingNums = /^(\d+)(?:\1)$/,
        match = RE_PatternInRepeatDec.exec( val );

    if( !match ){
        // Try again but take off last digit incase of precision error.
        val = val.replace( /\d$/, '' );
        match = RE_PatternInRepeatDec.exec( val );
    }
    if( match && 1 < match.length ){
        // Reset the match[1] if there is a pattern inside the matched pattern.
       match[1] = RE_RepeatingNums.test(match[1]) ? RE_RepeatingNums.exec(match[1])[1] : match[1];
    }
    return match;
};

Thank you for everyone that helped.

谢谢大家的帮助。

#2


1  

Use: var re = /^(?:\d*)\.(\d{1,3})(?:\1)+$/

用途:var re = / ^ \(?:\ d *)。(\ d { 1,3 })(?:\ 1)+ /美元

I have defined the min/max length with {min,max} of the repeating decimal because otherwise 009009009 would match in the first test case as well. Maybe it is still not the final solution, but at least a hint.

我已经用循环小数的{min,max}定义了最小/最大长度,否则009009009009009在第一个测试用例中也会匹配。也许这还不是最终的解决方案,但至少是一个提示。