3

繰り返し小数で繰り返される一意の数字に一致する正規表現を作成するにはどうすればよいですか?

現在、私の正規表現は次のとおりです。

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"]);
});
4

2 に答える 2

3

Ok。Joel のアドバイスを参考にして、私自身の問題をある程度解決しました。

問題は、正規表現セクション(\d+)+(?:\1)$が文字列の末尾に最も近いパターンに一致していたため、文字列 "0.099099099099099" に対して "099" ではなく "9" を返すことでした。

私がこの問題を克服した方法は、マッチの長さを 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;
};

助けてくれたみんなに感謝します。

于 2012-05-29T16:38:01.317 に答える
1

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

最初のテスト ケースでも 009009009 が一致するため、繰り返し小数の {min,max} で最小/最大の長さを定義しました。多分それはまだ最終的な解決策ではありませんが、少なくともヒントです.

于 2012-05-28T19:36:57.287 に答える