9の倍数の正規表現


14

9の倍数を認識する有限状態マシンを記述するのは簡単です。数字の合計(mod 9)を追跡し、次に受け入れられる数字を追加します。このようなFSMには9つの状態しかなく、非常に簡単です!FSMの認識可能性と正規言語の同等性により、9の倍数の正規表現があります。しかし、そのような正規表現はおそらく...非常に...長いです。のように、おそらくギガバイトのオーダーで。

https://www.quaxio.com/triple/には、3の倍数の有効な例があります。ページの下部で、著者は、「手作業で最適化された」ソリューションを提供します。正規表現へのFSM。

チャレンジ:

9の倍数を検出するには正規表現を作成する必要があります。このような正規表現は非常に長いことが予想されるため、正規表現を出力できるプログラムを提供するようお願いします。(正規表現全体を提供したい場合は、おそらく他の場所でホストし、ここにリンクしてください!)

プログラムの出力の正確な文字数を教えてくれる必要があります。つまり、ある長さまですべての正規表現を試行するプログラムは、動作するものが見つかるまで、十分に速く実行しない限り受け入れられません。最後まで実行して、結果の正規表現の長さを教えてください!

もちろん、プログラムの長さに基づくのではなく、最短の出力正規表現を使用するためです。正規表現は私が求めている「プログラム」であり、ここで便利に送信するには長すぎるので、このコードゴルフにタグを付けています。

ルール:

  • 入力には、に一致する文字のみが含まれます[0-9]*
  • 正規表現は9の倍数と一致する必要がありますが、それ以外は一致しません。完全に数字0〜9で構成されておらず、無効な入力であるケースは、希望どおりに一致または失敗する可能性があります。
  • DFAで簡単に認識されるという動機を考えると、結果の正規表現は、実際にはより理論的な用語での正規表現、つまり、正規言語が閉じられている演算子のみである必要があります。正確に言うと、許可される唯一のもの:
    • リテラル、文字範囲([ab][a-f][^k])、クリーネ閉包(*)、アンカー(^および$)、括弧を介して、交互(グループ化|)、任意の用語(?)、一又は、複数の用語(+)、先読み((?=))、負の先読みを((?!))、 lookbehinds( (?<=))、負lookbehinds( (?<!)(のように)、条件文https://www.regular-expressions.info/conditional.html - (?(?=test)then|else))、及び有界長の後方参照(下記参照)。
  • 許可されていないものの例:
    • 任意の長さの後方参照、前方参照、再帰、サブルーチン、ループ構造、実行可能コード、「eval」のバリエーション、または文字列を算術値にキャストするための組み込み構造。
  • 制限された長さのバインディング文字列を持つことを示すことができる後方参照は、有限状態で保存でき、言語の規則性を変更しないため、受け入れられます。たとえば(..2.[3-5])4\1.\1、キャプチャグループにバインドされた長さがあるため、正規表現は受け入れられ\1ます。これは通常の構造です。(2*)0\1キャプチャされたグループは有限状態で保存できないため、このような構造は受け入れられません。
  • 正規表現は、必要に応じて、余分な先行ゼロを含む整数を自由に受け入れたり拒否したりできます。ただし、文字列"0"は受け入れられる必要があります。

2
関連、必ずこれは、重複と見なされますされていない場合
ASCIIのみ

ああ、うーん!「regex multiple」を検索しましたが、「regex divisible」は検索しませんでした。私はそれが非常に似ていると思います、はい。
アレックスメイブルク

11
まだ言われていないので、PPCGへようこそ、面白い最初の挑戦!別のユーザーが述べたように、メインに投稿する前にフィードバックを取得できるように、サンドボックスにチャレンジ提案を投稿することが推奨されますが、必須ではありません。ただし、これはよく考えられた明確な課題であるため、これをサンドボックスに移動する理由はありません。コミュニティをお楽しみください!
コイナーリンガーアーイング

200キビバイト未満のソリューションが可能であるため、それほど大きくなることはありません
Ton Hospel

3
.NETの拡張機能を使用したソリューション:^(0|9|(?<c>1|(?<c>2|(?<c>3|(?<c>4|(?<c>5|(?<c>6|(?<c>7|(?<c>8))))))))((?<-c>){9})?)*$(?(c).)
ニール

回答:


3

Haskell207,535 202,073バイト

可能な場合の0|9代わりに使用することにより[09]、5,462バイトが節約されました。

digits n
  | x == 0    = "0|9"
  | otherwise = show x
  where x = mod n 9

regex 0 = "[09]*"
regex n = (regex' n (-1) (-1)) ++ "*"

regex' 0 start end = digits (end - start)
regex' n start end = '(':(regex' 0 start end) ++ (concat ['|':(regex' (n-x) (start-x) (-1)) ++ (regex (n-x))
                                                  ++ (regex' (n-x) (-1) (end-x)) | x <- [1..n]]) ++ ")"

main = do
  putStr ("^" ++ (regex 8) ++ "$")

オンラインでお試しください!

リンクされた記事の脚注に記載されている正規表現をすぐに適用して、作業を開始してください。

出力正規表現のペーストビン、 Herman Lauenstein提供。

完全な正規表現をテストすることはできませんでしたが、3で割り切れる値をチェックするようにプログラムを変更すると、これに基づいた正規表現とまったく同じことが得られます。さらに、プログラムを変更して数字の合計の分割可能性を4または5でチェックすることも、テストした数字で機能するようです。


また、メソッドが2で割り切れる(のようなものである必要があります/even$/)と5で割り切れる(5のようなものでなければなりません)ことをテストすることもできます/[05]$/。PS:コードの言語に言及してください
Ton Hospel

ここでは(すべての出現箇所で出力してペーストビンである([09]|と置き換える(0|9|バイト数千人を救うために)
ハーマンL
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.