如何形成与重复小数重复的唯一数字匹配的正则表达式?
目前我的正则表达式如下。
var re = /(?:[^\.]+\.\d*)(\d+)+(?:\1)$/;
示例:
// Pass
deepEqual( func(1/111), [ "0.009009009009009009", "009" ] );
// Fails, since func(11/111) returns [ "0.099099099099099", "9" ]
deepEqual( func(11/111), [ "0.099099099099099", "099" ] );
现场演示:http://jsfiddle.net/9dGsw/
这是我的代码。
// 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"]);
});
答案 0 :(得分:2)
确定。我采取了乔尔的建议,解决了我自己的问题。
问题在于正则表达式部分(\d+)+(?:\1)$
匹配最接近字符串末尾的模式,这使得它返回“9”,而不是字符串“0.099099099099099”的“099”。
我克服这个问题的方法是将匹配长度设置为2或更大,就像这样。
(\d{2,})+(?:\1)$
,
并使用/^(\d+)(?:\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;
};
感谢所有帮助过的人。
答案 1 :(得分:1)
使用:var re = /^(?:\d*)\.(\d{1,3})(?:\1)+$/
我已经用重复小数的{min,max}定义了最小/最大长度,否则009009009也会在第一个测试用例中匹配。也许它仍然不是最终的解决方案,但至少是一个提示。