问题
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/
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"]);
});
回答1:
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".
The way I overcame this problem was by setting the match length to 2 or greater, like so.
(\d{2,})+(?:\1)$
,
and filtering the result with /^(\d+)(?:\1)$/
, incase that a pattern is stuck inside a pattern.
Here's the code that passes all my test cases.
Live Demo: 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:
Use: 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.
来源:https://stackoverflow.com/questions/10789435/form-regex-that-finds-pattern-within-a-repeating-decimal