特定のセルを選択する

RowDifferences・ColumnDifferencesメソッドは、指定範囲の中で条件に指定したセル以外を選択するメソッドです

'アクティブセル以外のセルを選択状態にする(行方向)
Selection.RowDifferences(ActiveCell).Select
'アクティブセル以外のセルを選択状態にする(列方向)
Selection.ColumnDifferences(ActiveCell).Select

「RowDifferences」「ColumnDifferences」メソッドは、指定したセルと同一のセル以外を選択します

このメソッドは、指定範囲内に引数に指定するセルが存在していないとエラーになります

なので、基本的にはこのメソッドの引数にはActiveCellやCellsなどの相対的な指定方法で行う必要があります
また、引数に指定できるセルは単一のセルになるので、複数のセルを指定した場合もエラーになります

メソッドの動き

特定のセルを選択状態にする(列方向)
行方向への指定選択
Selection.RowDifferences(ActiveCell).Select

画像ではこのコードが実行されています
RowDifferencesメソッドは、行方向への操作時に使用します

画像の動きではActiveCellはA2になりますので、条件は「ステータスA」が指定される形になります

このメソッドは、指定したもの以外を選択状態にするので
元々の選択範囲から「ステータスA」を除いたセルが選択状態になります

空白も対象になるので、列全体を指定するワークシートの列全体を選択してしまいます

特定のセルを選択状態にする(行方向)
列方向への指定選択
Selection.ColumnDifferences(ActiveCell).Select

ColumnDifferencesメソッドは、列方向への操作時に使用します

画像の動きでは、ActiveCellはB2になっていますので、空白のセルが指定される形になります

なので、選択範囲の中で空白ではないセルが指定される形になっています

この画像の動きのように、行のなかで特定の列だけにデータが入力されている表でどの列にデータが入力されているかを調べるのに適しているメソッドです

ただ、指定範囲の中に条件のセルを含める必要があるのがすこし難点です
なので、この画像の例の表ではその為にあえて何も入力しない空白列(B列)が作成されています
こうすることで、常に空白を指定することが出来るようにはなります

しかし、この動きであればFindメソッドの方が柔軟に条件も指定出来て便利ではあります
ですが、Findメソッドは一度に条件にあてはまるセルを選択するような動きはできません
あくまでも1セルずつ処理を行っていきます

でもこのメソッドなら、条件さえ整えてあげれば一括で条件に当てはまるセルを一括選択できます
逆説なので、条件を整えるのがたいへんですが・・・

使いどころが難しいメソッドですが、機能としては便利な機能だと思います

フィルタ機能(全解除)

フィルタの条件を全解除するにはShowAllDataメソッドを使用します

'フィルタの条件設定をクリアする
ActiveSheet.ShowAllData
'フィルタの条件設定をクリアする
On Error Resume Next
ActiveSheet.ShowAllData
On Error GoTo 0

フィルタのどれかの列でソートがかかっている状態を一括で全解除するには「ShowAllData」メソッドを使用します

このメソッドは、フィルタがかかっていない状態で実行するとエラーが発生します
なので、処理の最初に初期化しておきたいような場合はエラーを無視して実行します

フィルターが設定されているかは調べればわかりますが、あまり意味は無いと思います

また、ここでいう解除とはフィルタ機能の解除ではありません
ソート条件の解除になりますので、注意してください

フィルタを処理中にかけなおす場合は、当然エラーにはなりませんので1つ目のエラー無視は入れずに実行するといいです

ユーザーがフィルタをかけて保存していると、当然処理がうまくいかない可能性がありますのでフィルタのあるシートを処理する場合は最初に入れておくと安心です

ちなみに、昇順降順の矢印の表示もクリアされますがその設定は解除されたりはしません

Worksheets(1).ShowAllData

またこのメソッドはシートに対して行いますので、このコードのようにワークシートを指定して、別のシートのフィルタ条件を解除することもできます

引数を渡してプロシージャを実行する

引数付きのプロシージャの作成方法と呼び出し方法について

'セルを引数に持つプロシージャ
Sub 呼出テスト(引数 As Range)

End Sub

プロシージャの呼び出しにはCallステートメントを使用します
この時に引数付きのプロシージャを実行する事ができます

その際には呼び出し先のプロシージャで引数の設定を行う必要があります

関数と同様にプロシージャ名の隣の「()」の中に指定を行います
通常引数の無い場合は、空白状態になっています

ここは引数を設定するための場所になります

引数は、変数と同じものを指定します
書き方も変数の宣言と同じものになります

実際の処理の動き

Sub 処理テスト()

 Call 呼出テスト(Range("A1"))

 Call 呼出テスト(Range("A1:A10"))

End Sub

Sub 呼出テスト(引数 As Range)

Debug.Print 引数.Address

End Sub

処理の動きの確認には以上のコードを使用します

引数付きの処理を呼び出したときの動き
引数付きの処理の呼び出し

画像の動きの確認をしてください

 Call 呼出テスト(Range("A1"))

 Call 呼出テスト(Range("A1:A10"))

Callステートメントで2回処理を呼び出しています
その際に、引数としてセルを指定しています

指定方法はプロシージャ名の後に「()」を指定して、中に引数に設定するものを記載します

Sub 呼出テスト(引数 As Range)

Debug.Print 引数.Address

End Sub

呼び出し先の処理では、引数は「(引数 As Range)」として指定されています

ここに呼び出し時に指定するセルを代入することができます
代入されたものは通常の変数と同じ使い方になるので、Addressプロパティでセルアドレスを取得することが出来ます

Callステートメントにより同様の処理をまとめることが出来ますが、こうして対象が違っていてまとめることが出来ない場合に使用できます

なお、この引数付きのプロシージャからデバッグモードに入ることはできません
なので動作確認を行いたい場合は、呼び出し元のプロシージャから実行することでデバッグモードを行うことが可能になります

また、ここではSubプロシージャで行っていますが、Functionプロシージャでも全く同様に使用できます

エラー処理(エラー内容をクリアする)

On Error GoTo -1ステートメントは、エラー情報をクリアすることが出来ます。再度エラー処理を適応することが可能になります

'エラー情報をクリアする
On Error GoTo -1

処理を移動させずに、エラー状態の解除のみを実行するには「On Error GoTo -1」ステートメントを使用します

このステートメントを使用する場面は、エラーが発生している状態で、さらにエラーが発生した場合にどうしたいかによります
つまりエラー処理中のエラーはどうするか、という点です

エラー処理中のエラー発生について

エラールーチン中にエラーの再発生したときの動き
エラー処理中のエラー発生時の動き

画像の動きを確認してください
エラーが発生した際、On Error GoToステートメントにより「エラー発生」のラベル行に処理が移動します

このとき、エラー情報は発生したものが保持された状態です
この状態をエラールーチンが行われている状態といいます

このエラールーチン中に、再度エラーが発生した場合はステートメントの影響に関係なく実行時エラーが発生して処理が停止します

エラー処理とはいえ、処理である以上その処理にエラーが発生する可能性があります
その際にユーザーに処理停止を対処させるのは難しい話である場合が多いと思います

そこで、エラー処理中にエラーが発生したら、エラー処理を行いたい
こういった状況が出てくることがあります
そんなときに使用するのが、このステートメントになります

ステートメント使用時のエラー処理

エラールーチン中にエラーを解除する動き
エラー情報をクリアした時の動き

On Error GoTo -1ステートメントを使用している場合の動きになります

エラー発生:
On Error GoTo 0
On Error Resume Next
'Err.Raise (1)
On Error GoTo -1
Err.Raise (1)
Debug.Print "エラー終了"

この処理が画像のエラー処理部分になります

On Error GoTo 0

まず、最初にOn Error GoTo エラー発生の設定を解除するためにこのコードを実行します
これをしていないと、後で発生するエラーでまた「エラー発生:」に戻ってきてしまい無限ループに入ってしまいます

これで、エラーが発生したらメッセージが出て処理が停止する通常の状態になっています

ただ、このステートメントはエラー発生時の制御を解除しただけであり
エラー情報をクリアしたわけではないので、エラールーチンは継続中です

On Error Resume Next
'Err.Raise (1)

次に、エラー処理中にエラーが発生した場合の対応を作成します

今回はエラー処理中に発生したエラーは無視するように設定しますので、On Error Resume Nextステートメントを使用します

2行目はエラー発生させるコードをコメントアウトしています

実際、ここでもまだエラールーチン中なのでエラーが発生した場合は実行時エラーが発生し処理が停止します

On Error GoTo -1

ここでようやく記事のステートメントを使用しています

この時点で、エラー情報がクリアされます
そして、その時点でエラールーチンも終了しています

これにより、上記で設定したエラー発生時の制御が有効な状態になります

Err.Raise (1)
Debug.Print "エラー終了"

画像の動きと合わせて確認してください

ここでエラーを発生させていますが、処理は停止せずに最後のエラー終了の文字列出力まで実行されています

エラー処理中のエラー対応について

通常エラーの解除にはResumeかResume Nextのどちらかのステートメントを使用しますが、このステートメントでは処理が戻ってしまいます

通常、処理の組み方としてはそれが正統な作り方だと思います
でも前述したように、エラー処理を作成するということはそこでもエラーが発生する可能性は十分にあり得ます

例えば、以下の記事の動きを確認してもらいたいのですが
エラー処理でLong型変数に加算していき使用できる整数値で処理が正常に戻ります

ただ、このエラー処理でも使用できる数値がLong型の範囲内になかった場合
加算され続けて、いずれオーバーフローして実行時エラーが発生します

処理上、ほぼあり得ませんが
エラーが出ない処理は無い、ということは事実として存在します

なので、このコードを実行することによってエラーの発生がクリアされるので再度エラーが発生した場合は改めてエラー処理を適応することが出来ます

ただ、エラーの情報がクリアされるので当然エラーの発生した行もどこにあるかが分からなくなります
なので、Resumeステートメントなどでエラー発生した行に戻ることはできなくなるので注意が必要です

エラー処理(エラー処理後に戻す)

Resume Next・Resumeステートメントを使用すると、エラー処理後に処理を戻すことが出来ます

'エラー発生の次行に戻す
Resume Next
'エラー発生行に戻す
Resume

エラーが発生して、On Error GoToステートメントで処理を移動させていた状態から元のエラー発生した場所に戻すには「Resume Next」「Resume」ステートメントを使用します

戻す場所によって、コードを使い分けます

エラーが発生した行の次行に戻すにはResume Nextステートメントを使用します
エラーが発生した行に戻すにはResumeステートメントを使用します

動きの確認

エラー処理後に次の行から再実行する動き
Resume Next

エラーが発生した次の行に処理を戻すコードです

次の行に処理が戻るので、もともとエラーが発生した処理は実行されません
つまり、そのエラーが発生した処理が以降の処理に影響を与えない場合にのみ使用できます

当然、以降の処理にこのエラーが発生した処理を前提としていた場合バグが発生します

例えば、フォルダの新規作成や、存在しなかったファイルの削除など
エラーが発生すること自体は処理に影響を与えない場合に利用できます

On Error Resume Nextステートメントでもエラーが無視できますが、エラー処理が行えません
ユーザーにエラーが発生していることはメッセージで伝える必要がある場合はこちらのコードでエラー処理を作成してコードは次の行から再開させます

エラー処理後エラー発生行から実行する動き
Resume

このコードはエラーの発生した行に戻します

エラーが発生した行に処理を戻すことになるので、このエラー原因を解消するようにエラー処理を組まないと、無限ループに入ってしまいます

画像の動きを確認してください
A1セルからマイナス方向への移動ができないため、エラーが発生します

エラー処理では、移動値に数値を加算してから処理を発生行に戻しています

しかし加算値が「1」なので「-2」からは2回実行する必要があるので、2回エラーが発生して、最後にまた「0」になりA1セルが指定されて処理が正常動作に戻ります

このように、エラー処理で複数回繰り返してでもエラー原因を解消するような組み方が重要になります

ファイルの名前を付ける際に、重複しない連番をここで更新していくことで取得することが出来ます

なお、どちらのステートメントもエラー処理に使用するコードとなります
エラーが発生していない状態で実行されるとエラーが発生します

エラー発生後のエラー処理の最後に入れるようにします

エラー処理(発生時に移動させる)

エラーの発生時に任意の箇所に処理を移動させるコード。On Error GoToステートメントを使用します

'エラー発生したときは移動させる
On Error GoTo エラー発生

エラー発生:

エラー処理として、エラーが発生した際に特定の処理を実行する場面があります

その場合、エラーが発生した時点で実行するステートメント行を移動させることになります
その際に使用するのが「On Error GoTo」ステートメントです

On Error GoTo エラー発生

このステートメントに指定した文字列がラベル文字列となります
行指定も出来ますが、通常は例のように文字列で指定します
ここでは「エラー発生」の部分が当てはまります

このコード以降にエラーが発生した時点で、処理は停止せず指定した行に処理が移動されます

なお、ラベル文字列の設定はGotoステートメントと同じ設定の仕方になるので混同しないようにわかりやすい名前を付けましょう
Gotoメソッドと同じようにラベル文字列行の前には処理を終了させる「Exit Sub」を配置するようにしましょう

この設定を解除するには「On Error GoTo 0」ステートメントを使用します
解除しないと、以降の全ての処理でエラー処理が実行されますので、エラーの予期している範囲で使用するようにします

コードの動き

エラー発生時に処理を移動させる動き
エラー発生時の動き
Err.Raise (1)

このコードはエラーを意図的に発生させるコードです

このコードが実行された時点で、エラーが発生しOn Error GoToステートメントにより処理が移動しています

通常、エラー処理は正常処理の後に作成します
そのままEnd Subまで走らせる形で処理を継続させます

エラーが発生せずに処理が通常終了する動き
エラーが発生しない場合の動き

エラーが発生せずに正常に処理が実行された場合の動きです
終了コードにより、End Subまで行かずに処理を終了させています

これが通常のエラー処理の組み込み方です

処理終了コードを入れていない場合の間違った動き
終了コードを入れてない場合の動き

この画像のように、終了コードを入れ忘れていた場合、正常処理後にエラー処理が実行されてしまいます

Exit Sub
エラー発生:

なので基本的には、以上のような形でコードを作成するようにしましょう

EOF関数(プロパティ)

EOF関数(プロパティ)はデータの末尾を判定するために使用します

EOF関数とは、開かれているデータの末尾を調べる関数です
データベースではプロパティとして使用されます

データが末尾に到達した時点で「True」を返します
それ以外の時点では「False」を返します

主に使用するのは、テキストデータの読み取りや、データベースデータのレコードの最終データの判定に使用します

関数の書式

引数(太字は必須引数)
(Filenumber)
戻り値の型 Integer型(Boolean型)

引数「Filenumber」はOpenステートメントで開いたときのファイル番号です

プロパティでの使用時に引数はありません

実際の使用場面

今回はよく使用するテキストデータの末尾判定処理を行います

取得を行うテキストデータ
末尾判定を行うテキストデータ

この画像のテキストデータを取得しながらEOF関数の動きを確認します

Sub 処理テスト()
Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Input As #1
    Do Until EOF(1) = True
        Debug.Print EOF(1)
        Line Input #1, 文字列変数
        Debug.Print 文字列変数
    Loop
    Debug.Print EOF(1)
Close #1
End Sub

このコードが今回作成した処理です
内容としては、テキストデータをメモリ上に読み込みモードで開き
そのファイル番号をEOF関数で「True」が返されるまで取得し続けるループ処理です

EOF関数のコード上の動き
コードの動き

画像の動きを確認してください
EOFがテキストデータの存在している場合には「False」が返されています
データが末尾に来た時点で「True」が返されてループが終了しています

この判定を行っていないと、データが存在しない状態で参照しようとしてエラーが発生します

また、ループ条件の1行に関して

    Do Until EOF(1) = True

この部分に関しては、If関数と同様に比較を行わない方法でも構いません

    Do Until EOF(1)

この様に、「=」以降は入力しなくても関数がTrueを返して条件が成り立つので必要はありません

ただ、それはある程度知識のある人が見てパッと分かるようなコーディングだと思いますのでIfステートメントにしても、自分は「= True」は省略しないようにしています

比較を行わないので、処理速度にも影響はあるようです
見やすさの方が重視するので、あまり気にしませんがねぇ

なお、テキストデータを一括で1つのデータで読み込む場合は
以下の方法も利用できます

テキストデータを1文字ずつ取得する

テキストデータから指定文字数を取得するにはInput関数を使用します。Input#ステートメントとは別物になります

'テキストデータから1文字取り出す
文字列変数 = Input(1, 1)
'テキストデータから1文字ずつ全て取り出す
Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Input As #1
Do Until EOF(1) = True
文字列変数 = Input(1, 1)
Debug.Print 文字列変数
Loop
Close #1

テキストデータから指定の文字数を取得するには「Input」関数を使用します
同じ名前のInput#ステートメントとは使い方が全く違いますので注意してください

例えば、テキストデータの文字列の文字コードを調べていきたい場合に使用できます
文字コードの取得は1文字ずつしか行えませんので、この関数で1文字ずつ取得していくことで簡単に調べることができます

関数の書式

引数(太字は必須引数)
(Number, Filenumber)
戻り値の型 String型

引数「Number」は取得する文字数です。バイト数ではなく文字数になりますので、半角も全角もどちらでも1文字は「1」になります

引数「Filenumber」はOpenステートメントで開いたファイル番号です

コード解説

文字列変数 = Input(1, 1)

関数で戻り値があるので、基本的に変数などに代入させて使用します

このコードでは、ファイル番号1の1文字を取得します
この関数をコード中で再度実行すると、次の文字が取得されます
なので、ループ処理を使用することで最後まで取得させることができます

2つ目の例コードのループ処理を以下で解説します

Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Input As #1
~~ 中略 ~~
Close #1

Openステートメントの取得モード「Input」で指定テキストファイルを開いています
この時、対象ファイルが存在しない場合は新規作成されてしまいます

Close#ステートメントで開いたデータをメモリから閉じています

Do Until EOF(1) = True
~~ 中略 ~~
Loop

テキストデータを最後まで参照するためのループ処理です

取得するテキストデータの最終データを判定するEOF関数を使用してループを行います

文字列変数 = Input(1, 1)
Debug.Print 文字列変数

ここで1文字を取得して、イミディエイトに出力しています

このループ処理のイミディエイト出力の箇所に、処理を組めばテキストデータを1文字ずつ加工していくことができます

テキストデータにデータを書き込む(Write#)

テキストデータにWrite#ステートメントで書き込みを行います。csvなどのデータとして扱う場合に使用

'テキストデータに書き込み
Write #1, "文字列", 123

Openステートメントで開いたテキストデータに書き込みを行うには「Write#」ステートメントを使用します

このステートメントはcsvデータなどの、後でデータとして扱う場合に使用します
なので、データを1行にまとめて指定する必要があります
その場合に「,」もしくは「;」を使用することでデータを結合して指定できます

引数1つ目はOpenステートメントで開いたときのファイル番号です
引数2つ目が書き込みをするデータになります

データとして書き込みをされるため、文字列の場合には「”」を含めて書き込みされます
数値は文字列ではないため、数値だけが書き込みされます

書き込みの動き

Write#ステートメントでテキストデータを書き込む場合は、csvのようなデータ群である場合が多いため、空白のテキストデータに書き込みを行います
そのため、Openステートメントで「Output」モードで既存のデータはクリアしてからデータの書き込みを行います

Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Output As #1
Write #1, "新しい追加行,白", 123
Write #1, "新しい", "追加行"; "黒", "123"
Close #1

このコードは、既存のデータがあった場合はクリアしてから2行のテキストデータを書き込みます

データの書き込みを実行した状態
実行結果

画像のテキストデータが実行結果のデータです

文字列で指定した部分は、「”」が付与されたまま書き込まれています
数値指定で書き込んだ場合はそのまま書き込みが行われます

また、「,」でも「;」でも実際に書き込まれているのは「,」になっています

空白行の追加

Write#ステートメントでは、文字列には「”」が付与されます
そのためPrint#ステートメントのように「””」と指定するとうまくいきません
何も入力しないことで空白行の指定が可能です

Write #1, "新しい追加行,白", 123
Write #1,
Write #1, "新しい", "追加行"; "黒", "123"

2行目に空白行を挿入する場合には、このコードのように2つ目の引数には何も入力しないようにします

空白がうまく挿入された状態
空白がうまく入っている状態

実行結果の画像を確認してもらうと分かりますが、2行目には何も入力されておらず、ちゃんと空白行が挿入されています

Write #1, "新しい追加行,白", 123
Write #1, ""
Write #1, "新しい", "追加行"; "黒", "123"

このコードのような状態で実行するとうまくいきません

空白がうまく入っていない状態
空白がうまく入っていない状態

画像の様に2行目が空白行とならず、「””」が入ってしまいます
空白行を挿入する場合は上記のコードのようにしてください

また、このWrite#ステートメントで書き込みをしたデータの読み込みにはInput#ステートメントを使用してください

テキストデータにデータを書き込む(Print#)

テキストデータに追記するPrint#ステートメントについて。1行の文字列を追記する場合に使用

'テキストデータの追記
Print #1, "文字列"

Openステートメントで開いたテキストデータに追記するには「Print#」ステートメントを使用します

Print#ステートメントは、csvデータのようなテキストデータはなく、文章として表示させる場合に使用します

Print#ステートメントは、コードに記載した文字列をテキストデータに書き込むので操作履歴や処理履歴などに使用することが出来ます
また、iniファイルなどの設定データをExcel外部にデータ保存する際にも使用できます

引数1つ目の「#1」はOpenステートメントで開いたときのファイル番号です
引数2つ目に追記する文字列を指定します、文字列なので「”」で囲みます

文字列の末尾には自動的に改行文字が追加されますので、ステートメントの実行前に改行文字を挿入する必要はありません

追記の動き

追記の動きの確認をするうえで重要なのが、Openステートメントでのモード選択なります
ここの設定で、既存の文字列を消去するか、それに追記していくかを選択します
ここでは、追記モードの「Append」の設定で行います

Print#ステートメント自体が文章入力の意味合いが多いので、基本的には追記モードをよく使用します

追記をするテキスト元データ
元となるテキストデータ

この画像のテキストデータに追記を行います
なお、上記にあるようにPrint#ステートメントの末尾には改行文字が付与されますが、前には挿入されません
画像を確認してもらうと分かるように、4行目に空白行が存在している状態です
この状態を前提としています

Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Append As #1
Print #1, "新しい追加行,白"
Print #1, "新しい追加行,黒"
Close #1

このコードを実行します
追記モードで開いて2行追記する処理です

追記が実行された状態のテキストデータ
コード実行結果

コードを実行すると、2行が追記されていることが確認できます
また、6行目に空白行ができていることからも改行文字がちゃんと付与されていることも確認できます

Print #1, ""

また、このコードのように追記する文字列を空白に指定することで空白行を挿入することも可能です

Print #1, "新しい追加行", "白"
Print #1, "新しい", "追加行", "黒"

このコードのようにデータを「,」で区切って複数データを一括で指定できます
ただ、Print#ステートメントの場合はうまくスペースが入らないため、基本的には「”」で囲んだ1つの文字列データを指定していきます

「,」を使って追記したときの実行結果
「,」で区切って指定した結果

コードを実行すると、この画像の様にスペースが入ってしまいます
非常に見にくくなることこの上ないので、「,」で区切るcsvデータにはWrite#ステートメントを使用してください

このPrint#ステートメントで書き込まれたデータは、LineInput#ステートメントを使用して読み込みを行います