見出し画像

個サ作 #11 カレンダーLv.5 前編

こんにちは。

前回は自作関数を巧みに駆使したカレンダーLv.4が完成したのでした。今回はLv.5に進みます。この回では正規表現せいきひょうげんを扱います。

ただ、「正規表現」自体とても奥深く複雑さを伴う内容なので、詳細な解説は避けて「こんな技術があるんだね」というレベルでご理解いただけたらOK、というテンションでやっていきます(でも結構ハードにやるよ)。

では、今回もはじまりはじまり~。


今回のゴール

今回はほとんどの内容が正規表現に関する説明になります。次の章で明らかになりますが、「YYYY年MM月」形式の年月情報から年と月それぞれを抽出する正規表現を理解することが今回のゴールです。

外部サイトを使うのですが、以下のような結果を出すところまでもっていきます。

年情報を抽出する正規表現で検証している様子
月情報を抽出する正規表現で検証している様子

実装もまま進みます!


カレンダーLv.5 前編

まずは完成形の動作です。

今回の完成形の動作

これまでと異なるのは1セル内に「2025年5月」のように年も月も指定している所です。


事前準備

これまで「Study2」というモジュールでやってきましたが、新しいものに乗り換えましょう。特に意味はないですが、ソースコードが増えてきましたし、ちょっと心機一転しましょうや、とそういう思いです。

下図の操作を真似してください。

この操作を真似してね

次のモジュール名はStudy3スタディーさんです。

できましたでしょうか。ではマクロのがわを書きます。

'正規表現の学習
Sub H_カレンダー5()

End Sub
赤枠のソースコードを反映してね

今回はこれですね。

「カレンダーLv.5」という通り、今回もカレンダーを実装するのですが、前回でもう各年月の末日を適切に出力することはできるようになりました。

なので、今回は新しい要素が正規表現しかないんです。と、いうことは正規表現関連の実装以外はほぼ前回の使いまわしをします。

そこを先にやってしまって、その後で正規表現の話に参りましょう。


8割実装するどん

前回は変数を宣言する前にまずはユーザの入力値が適切か?という観点でエラーチェックをしましたよね。チェックを通過したら変数に代入しました。

が、今回はそこの勝手が少し変わります。いきなりから変数の宣言をしちゃいましょう。

    Dim year As Integer
    Dim month As Integer
    Dim day As Integer: day = 1
赤枠のソースコードを反映してね

まずはこちらのソースを書きます。

続きまして、

    'エラー通知
赤枠のソースコードを反映してね

このコメントだけ置いておいてください。正規表現を経て「あ、こりゃ正常な年月が入力されてねーな」という場合に処理を終了させるプログラムを後で書きます。

で、最後に・・・

    Range("F2:F32").Clear
    
    For i = 2 To 32
        If isDayWritable(year, month, day) Then
            Cells(i, 6).Value = day & "日"
            Application.Wait [Now() + "0:00:00.05"]
            Cells(i, 6).Select
        Else
            Exit For
        End If
        day = day + 1
    Next
赤枠のソースコードを反映してね

こちらをお願いします。カレンダーLv.4からコピーし、要所(Cells()の列位置)だけ変更しました。もうこれまでに出てきた要素しかないので、説明は割愛します。

isDayWritable関数はこのモジュールStudy3ではなくStudy2にありますが、問題なく呼び出せます。下図に抜粋したものをみてください。

別モジュールの関数を呼び出せる仕組みがあるんです↑


ここまで実装したソースコードをさーっとご覧になってですね、これまでと一部違う点があるんですが、気付きますか?

今回はこのモジュールの冒頭に

'変数宣言を強制する
Option Explicit

これを書いていません。#4で説明した変数の使用には必ず宣言をさせるためのオプションですね。これを書かないことでループで使っている変数 i の宣言を省略することができています。私も普段は省略しています。


さてと、では正規表現を使用する関数を作りましょう。でもまずは正規表現とはなんぞや?というところからですね。

次章でじっくりとやります!


正規表現

正規表現とは?

正規表現とは、端的に言うと文字列の表現方法のことです。ポイントは「正規」の部分でこの文字列の表現方法が予め規定されているんですね。

「正規」だけをググった結果

ここの説明を続ける前にひとつ案内しておきたいサイトがあります。それがこちら。

これは第三者の提供なのですが、正規表現を試してみたいときに大活躍するサービスです。この後の説明でも活用します。

(リンクが切れていたらごめんなさい。「正規表現チェッカー」で検索すれば類似サイトがヒットします。)

正規表現を使うと何ができるのか?に触れる前に少しだけ、その正規表現とは実際どんなものなのか?お教えしましょう。


.(ドット)

任意の1文字を示す正規表現です。これはどんな文字ともマッチする魔法の表記です。ためしに先ほどのサイトの正規表現に「.」を、検索対象文字列に「あいうえお」と打ってみてください。

そうすると、こんな具合に結果に表示されました。これは「.」自体が任意の1文字にマッチする正規表現ですから、検証対象である「あいうえお」に対して「あ」と「い」と「う」と「え」と「お」とそれぞれマッチしたことを示しています。

※任意・・・その人の意思に任せること

その証拠に結果欄は各文字が枠に囲まれて独立しています。まだよくわからなくて大丈夫。


+(プラス)

+は直前に指定した正規表現を1回以上繰返す、という性質があります。

正規表現の欄に「+」を追記しましょう「.+」という形になります。すると・・・

このようになりました。さっきは一字ずつでしたが、今回は文字を囲む枠が連結してひとつの塊になりましたね。

「.」の任意の一文字と「+」の前の表現を1回以上繰り返すというパターンを掛け合わせると連続する任意の文字、ということになります。

だから「あいうえお」という塊がヒットしました。


正規表現を使用した処理パターン

ここまでは正規表現の基礎中の基礎で、なんのこっちゃだと思います。

というのも、今回実装するカレンダーLv.5では、例えば「2024年5月」という文字列から「2024」と「5」を抽出する、という処理をしています。

ここまでの説明だと、正規表現の使用がこの抽出処理に繋がるのか?それがまだイメージできませんよね。

そもそも正規表現を使うと何ができるのか、これを使うことでどんな良いことがあるのか、知りたいですね。

まず正規表現を用いたときにどんなことができるのか?という視点から理解の足場を広げていきたいと思います。

正規表現を使用するときはやりたいことがだいたいはっきりしています。検証対象の文字列が・・・

  • とある文字列パターンに一致するかどうかを判定したい

  • とある文字列パターンに一致した文字を置換したい

  • とある文字列から指定した文字列パターンに一致した文字を抽出したい

だいたいこの3つですね。今回は3つ目をやろうとしています。

ここまでにお伝えした「.」は任意の文字列、「+」は前の正規表現を繰り返す、というものだからイメージできませんが、やりたいことから逆算して考えると「こんな正規表現もあるのでは?」というあたりが付きますね。

はい、「2024年5月」から「2024」と「5」を抽出したい場合、どんな正規表現があると役に立ってくれそうでしょうか。

あなたが今思ったこと、当ててもいいですか。文字列の中から数値だけを抽出できる正規表現がもしもあれば、今まさに使いどころではないか?と思いますね。

では、これを踏まえて引き続き正規表現パターンの習熟を深めていきます。


\d [0-9]

項タイトルに「\d」と「[0-9]」を挙げました。これは2つの正規表現パターンですが、どちらも同じ働きをします。後者の方から推測できるでしょう。はい、数値を抽出します。

では、正規表現チェッカーにて正規表現に「\d」を([0-9]でも可)、検証対象文字列に下記の文字列を入力してください

あいうえお12345
かき678くけこ

さて、いかがでしょうか。

正規表現「\d」を使ってと文字と数値が混在した文字列を検証する様子

8つ、正規表現と一致しています。「\d」は1桁の数値とマッチするものだから「1」とのマッチ、「2」とのマッチ、「3」とのマッチ・・・という具合に1文字ずつヒットしたものがハイライトされています。

では、ここでも先ほど習った「+」を使ってみましょう。直前の正規表現を繰り返すというものです。正規表現を「\d+」にしてみてください。

(「[0-9]+」でも可)

正規表現「\d+」を使ってと文字と数値が混在した文字列を検証する様子

はい、2つのマッチになりました。「12345」と「678」です。

先ほどは各数値が独立してマッチしていましたが「+」を付けたことで前の正規表現を繰り返す、すなわち連続する数値を検出する、という正規表現パターンとなりました。

この感じでいくと、「2024年5月」から「2024」と「5」を抽出するパターンにも難なくたどり着けそうな感じがしますね。

さて、では次に必要な要素はなんでしょう。今、とりあえず文字も混在する中から数値だけを抽出する、ということはできるようになりました。


{n}(波括弧内に任意の数値)

ここで前回やったカレンダーLv.4の年のチェック内容を思い出してみましょう。

'年の妥当性チェック
Function isYear(year As String) As Boolean
    isYear = (IsNumeric(year)) And (Len(year) = 4)
End Function

前回作ったisYear関数です。ここで確認していることは以下の2点

  • 数値であり かつ

  • 4桁であること

ですね。前項の正規表現パターン「\d」or「[0-9]」によって数値の抽出方法は明らかになりました。となると、残すは4桁の部分です。

ここで項タイトル「{n}」の出番です。この「n」は任意の数値を表しています。

これまでは「+」記号が直前の正規表現パターンをヒットする限り繰り返す、という役割で確認してきましたが、「{n}」は何回繰り返しているのか?を確認することができます。

先ほどのこれね、「12345」と「678」がヒットしているでしょう。これ、それぞれ5回の繰り返しと3回の繰り返しパターンにヒットしたことになります。

では、繰り返し回数を指定したいので「+」を試しに「{3}」に置き換えてみましょう。

正規表現「\d{3}」を使って文字と数値が混在した文字列を検証する様子

はい、「123」と「678」のマッチに変わりましたね。「+」のときは数値に該当しない文字にあたるまで永遠に繰り返していました

でも今回は「{3}」と明確に指定したことで3桁のみが抽出されました。「4」と「5」も数値なのにヒットしていません。それぞれ4桁目、5桁目だからです。

ちなみに、今回の例だと3桁の数値の一致は「123」以外に「234」も「345」も一致するのでは?と思われた方もいるかもしれません。

一度パターンにマッチした数値は次のマッチには使用されない、すなわちまだマッチしていない値からマッチングの検証が行われる、という動作をします。

これを証明するために先ほど「{3}」とした箇所を「{2}」にしてみましょう。

正規表現「\d{2}」を使って文字と数値が混在した文字列を検証する様子

はい、「12」と「34」と「67」がヒットしましたね。こういうことです。「12」がヒットしたら次は「3」からマッチング検証が行われます。

というわけで、話を戻しまして、

  • 数値であり かつ

  • 4桁であること

この2つの条件を満たす正規表現パターンはもうお分かりでしょう。

検証対象文字列を「2024年5月」(数値はなんでもいいです)にしていただきまして、正規表現には「\d{4}」と入力してみましょう。

([0-9]{4}でも可)

正規表現「\d{4}」を使って「2024年5月」を検証する様子

はい、無事に「2024」のみがハイライトされていますね。

正規表現の力を使ってここまでできればあとはこの後で実装する関数の働きによって処理を行います。マッチした箇所を抽出する、という風にすればあとはそれを変数yearに代入し処理を進めることができます。


さて、これで年を抽出する正規表現はクリアだ~と思われたかもしれません。が、まだ甘いんです。というかここからが正規表現の本領発揮です。

たとえばユーザが誤入力をして「22024年5月」と入力したらどんな値がヒットすると思います?

正規表現「\d{4}」を使って「22024年5月」を検証する様子

はい、前方の文字から順番に検証していきますから、「2024」ではなく「2202」がヒットしちゃってますよね。

この場合、本来すべき動作はユーザに「入力に誤りがありますよ」と伝えることです。だから愚直に「OK!2202年の情報ね!」と解釈してる場合じゃないんです。

ここで前提をまず整理しましょう。システム側としてはユーザが「YYYY年MM月」形式で入力してくることが期待値です。

(「Y」はYearの「Y」、「M」はMonthの「M」)

これを少しでも逸脱していたらエラーとして返したい、ということはもう少し縛りが必要ですよね。4桁の数値を抽出だけではお粗末ということです。

では「\d{4}」←この正規表現に対してさらにどんな制約を追加したら確実に年の情報が抽出できるでしょうか。2つあります。シンキングタイム!


(?=年) (肯定先読み)

まず一つ目からいきましょう。年を示す4桁の数値を抽出するためにさらに加えたい制約、それは4桁の数字の直後に「年」があることです。

これを叶えるため、今書いている正規表現「\d{4}」に対して項タイトルの「(?=年)」を付け加えます。

正規表現を「\d{4}(?=年)」このようにしていただくと・・・

(「[0-9]{4}(?=年)」も可)

正規表現「\d{4}(?=年)」を使って「22024年5月」を検証する様子

はい、「2202」ではなく「2024」の方がマッチしました。

「(?=年)」←このパターンはですね、|肯定先読《こうていさきよ》みと言いまして、指定した文字(今回なら「年」)が後方にあるときだけ、その前の文字列を調べる、という動きをします。

「先読み」というと文字列の先頭をイメージされると思いますが、文字列検証を左から右に進めるにあたっての前方を意味しています。つまり右の方です。進行方向のの方をむ、ということです。


ここにひとつ補足がありまして、指定したパターンの末尾に「年」がつく文字列を調べたいならもっと簡単な方法もあるんです。

正規表現に「\d{4}年」と入力してみてください(「[0-9]{4}年」も可)。

正規表現「\d{4}年」を使って「22024年5月」を検証する様子

「\d{4}」の後ろを「(?=年)」と書かずに「年」としました。これでもヒットはします。ただ、「年」も一緒に抽出してしまうんですね。

この肯定先読みは後ろに付与されている文字をパターンマッチングの対象文字ではなくあくまでマッチング検証の条件として使用できるところに利便性があります。


さて、肯定先読みを使用したことで

この結果が得られました。2024年が抽出できましたね。これでOKな気もします。

ただ、先ほど追加できる制約が2つあります、と言ったうちのまだ1つしかお伝えしていませんね。それに本来このケースではエラーにしたい、とも言いました。

また、システム開発において案外重要なのが、作り手の想像で決めつけない、ということなんです。

「22024年」とあったら、今現在の西暦からして「あぁ、2024年と打ちたかったのね」と思うでしょう(まあ私がそう先導したところはありますが)。

でも(屁理屈に聞こえるかもしれないけど)ユーザは「2202年」のカレンダーを出力したかったのかもしれません。それはこちらにはわかりません

なので、解釈に幅のある入力を許してはいけないんです。誤作動に繋がるから、想定していない入力はすべてエラーとしてはじ、この姿勢が間違いのない堅牢なシステムを実現させます。


というわけで年情報の取得に関する最後の制約に参りましょう。


^(キャレット)

キーボードの中で[Back Space]キーの2つ左隣に「^」←こんなマークの付いたキーがあるでしょうか。これ、キャレットと呼ぶそうです。私も今知りました。

このキャレットも正規表現のひとつです。

こいつが一体どんな働きをしてくれるのか、想像できますか。彼はですね・・・後ろに続く正規表現とマッチする文字が文頭にあるときのみマッチさせる、という役目をもっています。

正規表現「\d{4}(?=年)」を使って「22024年5月」を検証する様子

こういう状態かと思いますが、正規表現の先頭に「^」をつけてください。

正規表現「^\d{4}(?=年)」を使って「22024年5月」を検証する様子

はい、なにもマッチしなくなりましたね。期待値と一致します。なにもマッチしない、つまり年の入力として不適切、すなわちエラーにできる!です。

行頭から4桁の数字が始まってはいるのですが、5文字目が「年」ではなく数値なんですよね。この正規表現の制約を整理すると・・・

  • 数値であること

  • その数値が4桁であること

  • その4桁の数値の直後に「年」があること

  • 上記をすべて満たす文字列が行頭から始まっていること

です。正規表現を用いるだけでこれだけの制約を満たす文字列を簡単に抽出することができるんですね。

OK!年情報を抽出する正規表現はこれで完了です。「^\d{4}(?=年)」です。

次、月の抽出にいきましょう。


[...](角括弧内に任意の文字)

年情報は年情報を抽出する専用の正規表現として使うので、先ほどたどり着いた答え(^\d{4}(?=年))は一旦忘れてくださいね。

カレンダーLv.4で実装したisMonth関数をおさらいします。

'月の妥当性チェック
Function isMonth(month As String)
    If IsNumeric(month) Then
        isMonth = (1 <= month And month <= 12)
    End If
End Function

こちらですね。数値でありかつ1から12の間に該当する値、としています。

数値を示す正規表現「\d」のときに「[0-9]」も可能、という話をしていましたが、これを補足させてください。

角括弧を用いた正規表現自体はその中に書いた文字のいずれかに該当する文字を抽出できます。例えば正規表現に「[125]」と打ってみましょう。

正規表現「[125]」を使って「22024年5月」を検証する様子

はい、1と2と5に該当する数値がマッチしています(1はないですけどね)。ではこれをすべての数値でマッチさせようと思うと「[012345689]」←こういう正規表現を用意することになります。

正規表現「[0123456789]」を使って「22024年5月」を検証する様子

でもこれって冗長じゃないですか。そこで「じゃあ0から9の間の数字に該当する文字、ということにしよう」としたのが「[0-9]」←この正規表現です。

正規表現中の数値と数値をハイフンで繋ぐことでその間に該当するものも含む、という効果にできます。ですので、上図と同じ結果を返します。

正規表現「[0-9]」を使って「22024年5月」を検証する様子

ほら。で、ここまでの説明をきいたあなたは

あ、な~んだ。だったら1から12に該当する数値を正規表現で表すのも簡単ね。[1-12]ってことでしょ?

って、思うと思うんです。

てか私も思いましたもん。で、実際やってみて「違うんかい!」ってなりました。では、ためしに正規表現に「[1-12]」を指定してみましょう。

正規表現「[1-12]」を使って「22024年5月」を検証する様子

はい、「2」だけが単発でマッチしています。これね、今指定した「[1-12]」がどう解釈されたかというと、

  • 1から1の間に該当する文字列 もしくは

  • 2と一致する文字列

なんですよ。なので結果として「2」だけなんですよね。マッチするのは。

この括弧を使った手法の落とし穴は検証が1桁ずつ行われるという点です。「12じゅうに」として捉えてほしいのに「1」と「2」になるせいで望んだ結果が得られませんでした。

では、こちらの希望を叶えてくれる正規表現のお出ましだ!


|(パイプライン)

[Back Spaceバックスペース]キーの1つ左隣のキーを[Shift]キーを押しながら押下すると「|」←こんな縦棒が入力されると思います。これ、「パイプライン」というらしいです(他にも「縦線」「パイプ」とか読み方があるらしい)。

これは「1|2|3」のように指定することができ、この場合「1か2か3」に該当する文字とマッチします。で、これの便利なところは1文字ずつではなく、「|」で阻まれた文字列を1単語として扱ってくれる点です。

ですので、今やりたい1~12月に該当する数値を炙り出す、という正規表現は「1|2|3|4|5|6|7|8|9|10|11|12」で表すことができます。見てみましょう。

結果をわかりやすくするために検証対象文字列の月を11月にしています。

正規表現「1|2|3|4|5|6|7|8|9|10|11|12」を使って「22024年11月」を検証する様子

ほら、できてい・・・ない・・!!できていないだと・!?11月の数値が「11」ではなく「1」「1」としてマッチしてる・・・!?あ・・・

すみません。取り乱しました。でもたった今、原因がわかりました。「11」の前に「1」がヒットしちゃった、ということですね。

正規表現を次のように書き換えてください。「12|11|10|9|8|7|6|5|4|3|2|1」。

12から順番に数値を小さくしていっています。これでやると・・・

正規表現「12|11|10|9|8|7|6|5|4|3|2|1」を使って「22024年11月」を検証する様子

キタ━━━━(゚∀゚)━━━━!!「11」としてマッチしています。


月を抽出する正規表現をブラッシュアップ

前項で1~12の間に該当する数値を抽出する正規表現もわかりました。ただ、

このような結果になっているので、今不要なものもマッチしていますよね、年情報とのマッチは不要です。この辺りを仕上げていきます。

まず、年情報のときにも使った肯定先読こうていさきよを使いましょう。

年では「(?=年)」としていました。ということは「(?=月)」ですね。これを用いるのですが、1点注意があります。

今、正規表現を「12|11|10|9|8|7|6|5|4|3|2|1」としていますが、この両端に括弧を付けてください。「(12|11|10|9|8|7|6|5|4|3|2|1)」となります。その上で「(?=月)」を続けます。

括弧にはその括弧内の正規表現たちをグループ化する効果があります。今ここで括弧を付けないで

  • 12|11|10|9|8|7|6|5|4|3|2|1(?=月)

この表現にしてしまうと肯定先読みの効果があるのは「1」だけなんですね。だからこれでやると

正規表現「12|11|10|9|8|7|6|5|4|3|2|1(?=月)」を使って「22024年11月」を検証する様子

こんな結果になってしまいます。「2」「2」「2」「4」はいらないですよね。年の方にある情報だから。でも末尾に「月」がつくか?の検証は「1」以外働いていないからこんなことになってしまいます。

括弧を付与することで「12|11|10|9|8|7|6|5|4|3|2|1」がひとつのグループとしてみなされ、「12の末尾に「月」があるか」「11の末尾に「月」があるか」「10の末尾に「月」があるか」・・・という風に検証がされます。

末尾に「月」の文字がないならマッチしたとはみなされないわけです。なので正規表現を「(12|11|10|9|8|7|6|5|4|3|2|1)(?=月)」とすると・・・

正規表現「(12|11|10|9|8|7|6|5|4|3|2|1)(?=月)」を使って「22024年11月」を検証する様子

このような結果が得られます。やっと近づいてきましたね。


前項で「1」から始めて最後に「12」を検証するように正規表現を「1|2|3|4|5|6|7|8|9|10|11|12」としたら、「11」にマッチさせたいのに先に「1」がマッチしちゃったという不具合あったじゃないですか。

肯定先読みを使ったことでそれも直るんです。

各数字に対して末尾に「月」がついているか?を検証しているので、「11月」を相手にしている場合、まず1桁目の1は次の文字が「月」じゃないからスルーされます。「「1」の次に「1」?じゃあ君は違う!」となります。

そうやって何にもマッチせず11月とのマッチング検証に辿り着きます。

だから正規表現は・・・

  • (1|2|3|4|5|6|7|8|9|10|11|12)(?=月)

これでOK、ということになります。しかしもっと洗練させられます。1桁の正規表現は角括弧を用いてまとめてしまえばいいので・・・

  • ([1-9]|10|11|12)(?=月)

正規表現「([1-9]|10|11|12)(?=月)」を使って「22024年11月」を検証する様子

これでも同じ結果を得られますね。まだいけます。

10, 11, 12月のところは結局、1桁目は「1」で2桁目は0から2の間の数値であればOK、という解釈なので・・・

  • ([1-9]|1[0-2])(?=月)

こんな書き方でも同様の動作をしてくれます。ちょっと(理解するにあたっては)複雑になりましたね。

正規表現「([1-9]|1[0-2])(?=月)」を使って「22024年11月」を検証する様子

はい、月を抽出する正規表現としてはいよいよあと一歩です。

まだ出ていない新しい表現を紹介し、それを付与すれば完成します!


(?<=年) (肯定後読み)

まず最初に断っておかないといけないことがあります。

ここでやるのは「肯定後読こうていあとよ」と呼ばれる正規表現なのですが、調べたところVBAでは肯定後読みが使えないらしく、これを適用した上でプログラムに組み込むとエラーを起こすことがわかっています。

ですので、この項では学習として新たな表現を学びはするのですが、プログラム中に使用する正規表現としてはさっきの項で完成している、ということになります。「([1-9]|1[0-2])(?=月)」←これです。

そういうわけですし、さっと流しましょう。

年情報の時に肯定先読みというのが出てきましたね。月情報の抽出にも使用しています。「(?=年)」と「(?=月)」ですね。


肯定後読こうていあとよみとはこれの逆バージョンと捉えてください。検証対象の文字列の手前に指定した文字がついている場合のみマッチさせます。

文字列の検証が左から右に進んでいくので、その視点からすると文字列の左の方が「後ろ」ということになります。なので後読みと呼びます。

それでは肯定後読みの正規表現を付与します。「(?<=年)」を正規表現の先頭につけてください。

  • (?<=年)([1-9]|1[0-2])(?=月)

これが完成形です(プログラムでは「([1-9]|1[0-2])(?=月)」を使います)。

正規表現「(?<=年)([1-9]|1[0-2])(?=月)」を使って「22024年12月」を検証する様子

はい、正しくマッチしています。年のときもやったのですが、これのいいところは例えば「2024年112月」という誤った入力があった場合、どこにもマッチしないという結果が得られることですね。

正規表現「(?<=年)([1-9]|1[0-2])(?=月)」を使って「22024年112月」を検証する様子

その様子はこの通りです。これが肯定後読みを外すとマッチしちゃうんです。でも今回はVBAでは使えないので致し方なし・・・!


正規表現の学習をかなりしっかりとやりましたね。今回はここまでにして、残りの実装は次回片づけましょう。


今回のふりかえり

今回は実装上の新しい要素はなく、ひたすら正規表現をやりました。習ったことを簡単に総振り返りしましょう。

  • .ドット・・・任意の文字列とマッチします

  • +プラス・・・直前の正規表現をヒットする限り繰り返します

  • \dエンディー・・・数値をマッチします

  • [0-9]・・・数値とマッチします。各カッコ内は任意の範囲にできます

  • {n}・・・一致する桁数を指定します

  • (?=年)・・・文字列後方に指定値があれば前方のパターンとマッチします

  • ^キャレット・・・構造のパターンが文頭から始まればマッチします

  • |パイプライン・・・併記するときの区切りとして使用します

  • (?<=年)・・・文字列前方に指定値があれば後方のパターンとマッチします

正規表現の難しさはこれ↑だけ読んでもなんのこっちゃわからない、というところにありますね。今回は例を通して学べたので良かったです。

私もやってないと忘れてしまうものばかりですので、みなさんもあまり理解できていない/覚えられそうにないなどの思いがあっても心配しないでくださいね。

正規表現チェッカーを使って、期待値が得られたらその正規表現パターンを使えばいいんです。その都度考えたらOKです。

「\d」に「えんでぃー」というよみがなを振っていますが「¥」←エンマークと「d」←ディーのことですからね。お間違えなきよう・・。「¥」は半角入力すると「\」になるので混乱するかもしれません。


今回の補足

オススメの正規表現学習書籍の紹介

今回は正規表現をメインに扱ったのですが、私も一度は時間をとって学習したことがあります。そのときお世話になった書籍がこちらです。

これがわかりやすかったんですわ。この記事を書く上でもパラパラと捲りました。

アニメ調が苦手とかキャラクターが受け付けない等の事情がなければ、より本格的に学習されたい方は一度書店で立ち読みされては、と思います。


正規表現でできること

今回の内容でなんとな~く想像はつくと思いますが、正規表現を使うことでできる便利な処理がいくつかあります。その中でもメジャーなものが以下です。

  • パスワードの形式チェック

  • メールアドレスの形式チェック

  • 郵便番号の形式チェック

  • 電話番号の形式チェック

はい、この辺りは正規表現がよく用いられます。

例えば、あらかじめパスワードの形式を満たす正規表現をこちらで用意しておきます。そしてユーザが入力した情報を正規表現にマッチするかを検証します。

マッチすればOK、マッチしなければエラーというように分岐させます。

正規表現って本当に便利な仕組みでして、普通にロジックを組んだら長々とコーディングをしなきゃいけないのに、正規表現を使えばたったこれだけのソースコードで同じことが実現できる!なんてことがあったりします。

こういう便利なものがあるんだね、程度でいいので頭の片隅に置いておいてもらえるとよいかと思います。


おわりに

おわりです。今回はちょっと毛色の異なる回でしたね。

正規表現・・・奥が深いです。私も今回の記事を通して改めて勉強になりました。

実装を進める材料は揃いましたので、次回はこの続きをさっと実装して、お待ちかね、演習問題あみだくじに入りましょう。

正直、私はかなり楽しみです・・・!

では、今回もありがとうございました。ゆっくりお休みになってください!


この記事が気に入ったらサポートをしてみませんか?