見出し画像

0から始めるPHPプログラミング #1-5 VBAで入力チェックを実装する その5

こんにちは。

前回はループ処理を使った入力チェックを完成させました。

ただ、あまり綺麗なソースではなかったんですよね。

続きを実装していきましょう。

(今回は短めです)


入力チェックを実装する ~中級編その6~

長くて恐縮なのですが、今の実装が・・・

Sub validation2()

   '項目名
   Dim itemName As String
   '項目値
   Dim itemValue As String
   'アスタリスクの出現ポイント
   Dim asteriskPoint As Integer
   'メッセージ
   Dim message As String

   For i = 4 To 30
  
       '項目名を代入
       itemName = Cells(i, 1).Value
      
       '項目値を代入
       itemValue = Cells(i, 2).Value
  
       '項目名中のアスタリスクの出現位置を代入
       asteriskPoint = InStr(itemName, "*")
       
       '必須チェックの対象かどうかを評価する
       If asteriskPoint > 0 And Not Cells(i, 1).MergeCells Then
       
           '入力値があるかどうかを検証する
           If itemValue = "" Then
 
               'アスタリスクを削除
               itemName = Replace(itemName, "*", "")
 
               'エラーメッセージの設定
               message = message & itemName & "が入力されていません。" & vbCrLf

           End If
          
           Debug.Print i & "行目の項目:" & itemName & vbCrLf & _
                      " アスタリスクが登場するのは " & asteriskPoint & "番目です。"
         
       End If
     
   Next
   
   For i = 4 To 30
  
       '項目名を代入
       itemName = Cells(i, 2).Value
      
       '項目値を代入
       itemValue = Cells(i, 3).Value
  
       '項目名中のアスタリスクの出現位置を代入
       asteriskPoint = InStr(itemName, "*")
       
       '必須チェックの対象かどうかを評価する
       If asteriskPoint > 0 And Not Cells(i, 2).MergeCells Then
       
           '入力値があるかどうかを検証する
           If itemValue = "" Then
 
               'アスタリスクを削除
               itemName = Replace(itemName, "*", "")
 
               'エラーメッセージの設定
               message = message & itemName & "が入力されていません。" & vbCrLf

           End If
          
           Debug.Print i & "行目の項目:" & itemName & vbCrLf & _
                      " アスタリスクが登場するのは " & asteriskPoint & "番目です。"
         
       End If
     
   Next
   
   For i = 4 To 30
  
       '項目名を代入
       itemName = Cells(i, 6).Value
      
       '項目値を代入
       itemValue = Cells(i, 7).Value
  
       '項目名中のアスタリスクの出現位置を代入
       asteriskPoint = InStr(itemName, "*")
       
       '必須チェックの対象かどうかを評価する
       If asteriskPoint > 0 And Not Cells(i, 6).MergeCells Then
       
           '入力値があるかどうかを検証する
           If itemValue = "" Then
 
               'アスタリスクを削除
               itemName = Replace(itemName, "*", "")
 
               'エラーメッセージの設定
               message = message & itemName & "が入力されていません。" & vbCrLf

           End If
          
           Debug.Print i & "行目の項目:" & itemName & vbCrLf & _
                      " アスタリスクが登場するのは " & asteriskPoint & "番目です。"
         
       End If
     
   Next
   
   For i = 4 To 30
  
       '項目名を代入
       itemName = Cells(i, 9).Value
      
       '項目値を代入
       itemValue = Cells(i, 10).Value
  
       '項目名中のアスタリスクの出現位置を代入
       asteriskPoint = InStr(itemName, "*")
       
       '必須チェックの対象かどうかを評価する
       If asteriskPoint > 0 And Not Cells(i, 9).MergeCells Then
       
           '入力値があるかどうかを検証する
           If itemValue = "" Then
 
               'アスタリスクを削除
               itemName = Replace(itemName, "*", "")
 
               'エラーメッセージの設定
               message = message & itemName & "が入力されていません。" & vbCrLf

           End If
          
           Debug.Print i & "行目の項目:" & itemName & vbCrLf & _
                      " アスタリスクが登場するのは " & asteriskPoint & "番目です。"
         
       End If
     
   Next
   
   '住所
   If Range("B7").Value = "" Then
       message = message & "住所が入力されていません。" & vbCrLf
   End If
  
   '児童との続柄
   If Cells(14, 10).Value = "" Then
       message = message & "児童との続柄が入力されていません。" & vbCrLf
   End If
  
   'メールアドレス
   If Cells(17, 3).Value = "" Then
       message = message & "メールアドレスが入力されていません。" & vbCrLf
   End If
   
   If Len(message) = 0 Then

       '正常メッセージの設定
       message = "入力チェックを行いました。問題ありません。"

   End If

   MsgBox message
  
End Sub

こういう状態ですね。

対象の列が異なるだけで、処理内容としては同じループ処理が4つ連続しています。

この同じ処理を4回やっている部分を関数化しましょう。

1-3で関数の説明をしたとき、

関数はシステムを構成するための部品や歯車という感じです。
日常にある部品や工具をイメージしてほしいんですけど、これらは用途や条件が同じであれば再利用ができるんですよね。

という説明をしました。

今回、4列に対して同様に必須チェックをしたいので、用途が一致します。

そして引数、戻り値の説明では、

​関数に対して処理に必要な材料(=引数)を渡して、結果(=戻り値)を受け取る

とお伝えしました。

今回、必要な材料(=引数)は処理対象の列情報、ということになります。結果(=戻り値)はどの項目がエラーだったのか?というメッセージ情報です。


それでは手を動かしていきましょう。

前回の終わりに、第2弾としては完成の位置づけ、とお話ししましたので、新しいマクロを作成します。

入力チェックを右クリックすると下図のようにメニューが表示されます。

010_マクロ作成

マクロの登録を左クリックしましょう。

すると、「マクロの登録」というダイアログが表示されます。これまでにも見たことのある画面ですね。

020_マクロ登録1

上図赤枠の内容が今、ボタンに紐づけられているマクロです。そこを新しいマクロの名前に書き替えます。

030_マクロ登録2

このように「validation3」と入力し、右にある新規作成ボタンをクリックしましょう。「validation」には検証という意味があるんでしたね。

040_新しいソース

ソースの画面が表示され、このようになっていればOKです。このようになってなかったとしても(Module3が作成されてなかったとしても)、

Sub validation3()

End Sub

このソースがあれば大丈夫です。


今からやる内容としてはvalidation2の改修なんですが、どうして新しくvalidation3を作っていただいたかというと、validation2で宣言してる変数の中には不要になるものがあったりして、ややこしいからです。

ここからはvalidation2のループ処理を関数としてvalidation2の外部に記載します。


ではまず、以下のソースを実装してください。

    'メッセージ
   Dim message As String

050_変数宣言

もうすっかりおなじみですね。messageという名前の文字列(String)型の変数を宣言しています。

それでは次に関数を作っていきましょう。


入力チェックを実装する ~中級編その7~

End Subの下に次のソースを追加してください。

'指定された列の必須項目について
'値があるかをチェックし、エラーメッセージを返す
Function checkRequired(column As Integer)

End Function

060_関数ヘッダ実装

関数を定義すると自動的に他の関数やSubプロシージャの間に横線が入ります。Subの塊のこと、Subプロシージャって言います(覚えなくていい)。

1-3の時に

関数というのは英語で言うとfunction(ファンクション)、つまり機能という意味です。

と、お伝えしました。その名の通り、関数の定義には「Function」という言葉を使います。

Function 関数名(引数の定義)
    ~処理内容~
End Function

↑このような書き方です。

'指定された列の必須項目について
'値があるかをチェックし、エラーメッセージを返す
Function checkRequired(column As Integer)

End Function

今回は関数名をcheckRequired(ちぇっくりくわいやーど)としました。必須チェックの時にRequiredという言葉はよく出てきます。

引数の定義部分に

column As Integer

このように書いています。これは通常時の変数宣言である

Dim 変数名 As データ型

から、「Dim」を外した形ですね。カンマで区切ると複数定義できます。

そして今回は列情報を受け取るので、columnという名前にしました。ここでも名前は重要。引数ですが、これも役割は変数と同じです。

これまでInStr関数やReplace関数を使用したときは値を渡すという風に言っていたのですが、関数は値を引き取る側なので、当然受け取るという言い回しをします。


では、このcheckRequired関数では受け取った列にある項目に対して必須チェック対象だったらその項目に値があるかどうか?を確認し、値がなかったらエラーメッセージとして呼び出し元に返すという処理をします。

まず、関数内に以下の変数群を宣言してください。

    '項目名
    Dim itemName As String
    '項目値
    Dim itemValue As String
    'アスタリスクの出現ポイント
    Dim asteriskPoint As Integer
    'エラーメッセージ
    Dim errorMessage As String

070_変数宣言

このように実装できればOK。

ここの変数たちはvalidation2でも出てきました。ひとつ異なるのは「message」として宣言していた変数が「errorMessage」となっている点です。

以前のソースではmessage変数に対して値の入力状態によってエラーメッセージが入るか、正常メッセージが入るかの2パターンがありました。

ですから、なにかしらのメッセージという意味でmessageという変数名にしていました。

ですが、このcheckRequired関数で設定するのは必ずエラーメッセージです。ですので、errorMessageとしています。


では次の実装です。

validation2を開いていただきまして、ソースをコピーしましょう。関数化する、ということは同じ処理を4回も連続で書かずに1か所に集約するということです。

080_ソース追加ループ部分

validation2のソースは画面左の「Module2」をダブルクリックし開きます。ソースのうち上図の赤枠で囲った部分をコピーするのですが、青の下線を引いた変数名は今回「errorMessage」に変えているので、ペースト後に変更します。

また、青の丸で囲んだ部分は引数として受け取ったcolumnに書き換える必要があります。

つまり!checkRequired関数に追加するソースは以下です。

    For i = 4 To 30
  
       '項目名を代入
       itemName = Cells(i, column).Value
      
       '項目値を代入
       itemValue = Cells(i, column + 1).Value
  
       '項目名中のアスタリスクの出現位置を代入
       asteriskPoint = InStr(itemName, "*")
       
       '必須チェックの対象かどうかを評価する
       If asteriskPoint > 0 And Not Cells(i, column).MergeCells Then
       
           '入力値があるかどうかを検証する
           If itemValue = "" Then
 
               'アスタリスクを削除
               itemName = Replace(itemName, "*", "")
 
               'エラーメッセージの設定
               errorMessage = errorMessage & itemName & "が入力されていません。" & vbCrLf

           End If
          
           Debug.Print i & "行目の項目:" & itemName & vbCrLf & _
                      " アスタリスクが登場するのは " & asteriskPoint & "番目です。"
         
       End If
     
   Next

ループの1回分ですね。messageはerrorMessageに、Cells関数に指定する第二引数はcolumnに変更しています。項目の入力値がある列を指定する部分では

       '項目値を代入
       itemValue = Cells(i, column + 1).Value

このように + 1 と式を書いているのもポイントですね。こういう書き方もアリです。

例えばcolumnが1だとしたら1 + 1 の結果、この第二引数は2としてCells関数に渡されます。

ソースは以下のようになればOK。

085_ソース追加後


そして、ループを抜けたところに値を呼び出し元に返す処理を記載しましょう。以下ソースを下図のように実装ください。

    'エラーメッセージを呼び出し元に戻す
    checkRequired = errorMessage

090_戻り値を返す処理

これを見たとき、「あれ?」と思いませんでしたか。

今まで、事前に宣言した変数に対して値を代入するという処理を何度も行ってきました。

しかし今回は、宣言した覚えのない入れ物にerrorMessageを代入しています。そう、これこそが呼び出し元に値を返すための処理なんです。

関数名 = 戻したい値

↑こういう書き方をします。変数ではなく関数名に対して値を代入するんですね。ちなみにPHPではもう少しわかりやすい書き方をします。

これで関数は完成です。

どうでしょう。やったことと言えば、これまでにSub validation2のメイン処理内に書いていたものを別の関数に移管しただけです。簡単ですね。


では次に、呼び出す側のソースを実装します。呼び出し方はこれまでInStr関数やReplace関数でやってきたのと同じです。以下のソースを追加しましょう。

    '1列目の必須チェックを実施
    message = checkRequired(1)

100_関数呼び出し1

1列目の項目に対して必須チェックをしたいので、引数に1を渡しています。そして、エラーメッセージを返して(戻して)くれるので、message変数で受け取っています。

同じ要領で2,6,9列目もチェックしましょう。以下のソースを追加してください。

    '2列目の必須チェックを実施
    message = message & checkRequired(2)
    '6列目の必須チェックを実施
    message = message & checkRequired(6)
    '9列目の必須チェックを実施
    message = message & checkRequired(9)

110_関数呼び出し2

1列目との違いはmessage変数と戻り値を連結している点ですね。

ここは1-2でひらがな項目と性別項目のメッセージの件で説明しました。ただ代入するだけでは元の値を上書きしてしまうので、連結しています。


残りの実装も済ませてしまいましょう。Module2を開いてください。

120_残りの処理実装

赤枠部分をコピーしましょう。今回はペースト後に変更する部分はありません。

つまり、↓このソースを・・・

    '住所
    If Range("B7").Value = "" Then
        message = message & "住所が入力されていません。" & vbCrLf
    End If
  
    '児童との続柄
    If Cells(14, 10).Value = "" Then
        message = message & "児童との続柄が入力されていません。" & vbCrLf
    End If
  
    'メールアドレス
    If Cells(17, 3).Value = "" Then
        message = message & "メールアドレスが入力されていません。" & vbCrLf
    End If
   
    If Len(message) = 0 Then

        '正常メッセージの設定
        message = "入力チェックを行いました。問題ありません。"

    End If

    MsgBox message​

130_残りの処理実装ペースト

こう!・・・完成!!

はい、完成しました。


動作確認して今回は終わりにしましょう。

まずは、必須項目すべてに値があるパターン。

140_動作確認1

はい、OKです。

次に、必須項目すべてに値がないパターン。

150_動作確認2

ポップアップのサイズが大きいので少し右寄せにしています。これもOK。


次に、ループ処理にしたことの恩恵を感じる動作確認をしてみましょう。

新たに卒園名、身長を必須項目にしたいとします。その時、あなたがすべきはソースをいじることではなく項目名にアスタリスクを追記することです。

すると・・・

160_動作確認3

はい。卒園名、身長の項目名にアスタリスクを設定し、未入力にして実行してみました。ご覧の通り、エラーとして検出されていますね。OKです。


ただ、前回もお伝えしました通り、この実装は住所、児童との続柄、メールアドレス項目をハードコーディング(直書き)による実装を行っているので、完成度としてはまだ足りないです。

ですが、ループ処理と関数の説明には大活躍してくれました。感謝です。


今回はここで終わりにしましょう。

Ctrl + S で保存しておいてください。

次回は上級編としてまた1から新しく実装していきます。これまで学習したことと新しく学ぶことの合わせ技でもう一段階拡張性を意識した実装にします。


あとがき・ふりかえり

今回もお疲れさまでした。

以下の1つのことをお伝えします。

・リファクタリングについて

--  --  --  

・リファクタリングについて

前回までと今回実装いただきましたvalidation2とvalidation3のソースコードは処理内容としてはまったく同じです。

ただ、validation3はvalidation2のソースから無駄を省きスリムにした、というところでしょう。

このように、処理内容を変えずにソースを最適化することをリファクタリングといいます。

ですので、実装を進める中でどのタイミングで処理を関数化するかというと一通り実装が終わってからということも十分あるんですよね。

もちろん実装途中で、何度も利用することがわかっていれば早い段階で関数として外に切り出すこともあります。

ここは結構、プログラマ個人の裁量によります。


最初から綺麗なコーディングを目指す人もいれば、まず荒削りに動作を完成させてその後ソースコードとしてのクオリティを上げる人もいます。私はどちらかというと後者。

この辺りの感覚はコーディングを重ねる中で磨かれていくと思うので、あなたにとってやりやすい方法・手順を見つけてみてください。

けっこう個性がでるところです笑。


おわりに

おわりです!

プログラミングの基本事項を網羅しつつあります。まだもう少し抑えておいてもらいたいことがあるので、説明が続きますが、この調子でついてきてください。

よろしくお願いしますね。


美味しいもの食べてゆっくり休みましょう。

今回もありがとうございました。


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