異なる桁数この広告は、90日以上更新していないブログに表示しています。2017の10日目です。TSGでは(特に1年生の)新入部員を募集しています。gasin.hatenadiary.jpさて、TSGの先輩方と雑談しているときに出てきた「正規表現で2進数を扱ったりして遊ぶ」という話題を発展させて、正規表現で足し算の式が正しいか判定することについて考えます。"123+456=789"二進、十進それぞれ2番目の例において、数の先頭に余分な0が付いています。これは前回紹介した正規表現に「A,B,Cは全て同じ桁数」という制約があったためです。今回の目標は、この不自然な制約を、「数の先頭に余分な0が付いていない*1」という(自然な)制約に変えて*2、自然な形式の足し算を判定する正規表現を作ることです。(?~)は使ってないから2.3以下でもたぶん動く。アドベントカレンダーの記事へのリンクを追加ふりかえり前回の記事では次のようなことを言いました。正規表現の再帰を用いることで、(各iについて)A[i]を読み終えた位置から、先読みでちょうどB[i]やC[i]を参照する正規表現が書ける。これを用いて、繰り上がりを判定する正規表現をゴリゴリ書く。これらを組み合わせることで足し算の判定ができる。これを踏まえて、次のようなコードを紹介しました*3*4。/x今回はこれを改造する形で、可変の桁数に対応していきます。考察(場合分け)A,B,Cの桁数(それぞれX,Y,Zとする)の大小で場合分けし、個別に考えます。100+1=101この場合、基本的にチェックする内容は(前回の記事の)同桁数の場合と同じです。BのY桁目以上は「0」と見なすようにします。することで、A[i]+B[i]=C[i]の形式を崩さずに判定できます。1+1=10、1100+111=10111。Bの繰り上がりの1となっているときです。同桁数の場合は「必ず0」としていた最高位の繰り上がりの判定を、場合によって\g<Carry0>と\g<Carry1>で使い分ける必要があります。1+101=110、101+1010=1111、101+1110=10011。(I)と同様に「Bの最高位より上に0が続いていると見なす」パターンが必要です。X桁(E)」に注目します。Dは0または(繰り上がりの)1です。0のときX桁目の繰り上がりは0です。Yのチェックの際に、Dをキャプチャします。Zのチェックの際にそのまま用います。1のときX桁目の繰り上がりは1です。p.18)を利用できます。インクリメント判定のうち「左辺や右辺の終端」で判定していたところを、「BやCの終端」ではなく「DやEの終端」にする必要があります。そのために、「B,Cの下位X桁(それぞれF,Gとする)」をキャプチャして、「Dの終端からはFと『=』が続く」、「Eの終端からはGが続いて文字列終端に達する」という風に判定します。)/xまとめこれらを全て結合させると、このようになります。長い正規表現となってしまいましたが、任意の桁数に対応する、自然な足し算を判定する正規表現が書けました!!正規表現を書いていて、「Bの桁が足りないときは簡単なのに対して、どうしてAの桁が足りないときはここまで煩雑になってしまうんだ......」と思いました。Rubyの正規表現の後読みが任意の長さに対応していれば簡単なのですが......ともかく、これで無事完成です。やりたいといった感じです。出来るのでしょうか?アドベントカレンダーを埋めるのは大変ですね。お送りします!hakatashi.hatenadiary.com*1:非零の数は「1」から始まる*2:逆に01+01=10のような文字列は受け付けない*3:ほんのちょっとだけ変更しています。*4:グループ名のうち、小文字の"a"から"d"は再帰のためのマーカーであり、意味はありません。*5:以降も同様に、小文字一文字のグループ名は再帰のマーカーであり特に意味はない。広告を非表示にする関連記事2017-11-24Rubyの正規表現で加算を判定する正規表現における「再帰」をご存知でしょうか。月別アーカイブはてなブログをはじめよう!akouryyさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。