テキストデータからデータを取得(Input#)

テキストデータからデータを取得するInput#ステートメントの使用方法。csvデータ取得に向いています

'csvやWrite#の文字列を取得
Input #1, 文字列変数

開いたテキストデータから文字列を取得するには「Input#」ステートメントを使用します
主にcsvデータやWrite#ステートメントで追記した文字列を取得する際に使用します

このステートメントでは「,」や改行でデータが区切られます
データは、引数に指定した変数に代入されます

Input #1, 文字列変数

引数1つ目の「#1」はOpenステートメントで開く際に指定したファイル番号になります
ファイル番号に関する解説は以下の記事を確認してください

2つ目の引数「文字列変数」は、取得したデータを代入する変数名を指定します
この引数はリストデータになるので、追加で指定することが可能です

取得時の動き

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

1要素ずつ取得して、それをイミディエイトに出力していく処理です
このコードを以下の文字列で実行して、取得の動きを確認します

取得を行うテキストデータ
取得を行うテキストデータ

この画像のテキストデータをコード実行し、取得を行います
その取得後の出力結果が以下の画像になります

取得を実行したイミディエイトの出力結果
イミディエイトの出力結果

上下の画像を見比べて取得のされ方を確認してください

「新しいテキスト1行目,青」
これは「,」でデータが区切られるので「新しいテキスト1行目」と「青」に分割して取得されます

「”新しいテキスト2行目”,黄」
これは1つ目に取得される文字列には、「”」で囲まれた文字列表現になっています
このステートメントでは「”」は除外して中の文字列を取得します
2つ目は「,」で区切られるので上記と同じです

「”新しいテキスト3行目,赤”」
これは1行まるごと「”」で囲まれています
この状態では、「,」は文字列と認識されるのでデータが分割されることはなく1行まるごとが取得されます

Input #1, 文字列変数(0), 文字列変数(1)

このコードのように、取得させる変数を「,」で区切って追加することでまとめて取得する事が可能です
上記の「新しいテキスト1行目,青」を取得させた場合は、1回の取得で「青」までの2つを取得できます
とはいえ、分割して一括取得はSplit関数を応用するほうが簡単です

このステートメントで、取得を行う際に文字列がcsvのようにある程度きちんとしたデータではなかった場合不安定かもしれません
そういったテキストデータを扱う際には以下のLineInput#ステートメントの方がいいかもしれません

テキストデータを閉じる

Openステートメントで開かれたテキストデータはCloseステートメントで終了させます

'番号1のファイルを閉じる
Close #1
'全てのファイルを閉じる
Close

Openステートメントで開かれたテキストデータを閉じるには「Close」ステートメントを使用します

このコードを実行する事で、開いているデータが閉じられるので新規作成されていた場合はファイルが実際に作成されます

また、指定番号の使用も終了します
なのでここで終了したファイル番号は以降で同じ番号が使用できるようになります

基本的には、番号を指定して終了します
使用していない番号を指定してもエラーは発生せず、開いている分は当然終了することはありません
番号は省略が可能で、省略した場合は開かれているデータが全て終了されます

Openステートメントで開いたデータはこのコードで必ず終了するようにしてください

テキストデータを開く(書き込み用)

テキストデータをメモリ上に開くにはOpenステートメントを使用します。その時に書き込み用で開くコードと注意点

'書き込み用で開く(既存は保持される)
Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Append As #1
'書き込み用で開く(既存は消去される)
Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Output As #1

テキストファイルを開くには「Open」ステートメントを使用します
このステートメントを実行する事でメモリ上にテキストデータを展開します

ステートメントの書式

引数(太字は必須引数)
Open Pathname For Mode As # Filenumber

引数「Pathname」・「Filenumber」に関しては以下の記事で解説を行っていますので確認してください

「Mode」は開くデータの扱いに関しての指定方法です
書き込み用に開く場合は、「Append」・「Output」のどちらかを指定します

「Append」・「Output」の違いについて

どちらのキーワードを指定しても、テキストデータの書き込みが可能です
違いは既存のデータの扱いになります

Appendは既存のデータに追記していきます
Outputは既存のデータを消去して追記していきます

実際の動きをテキストデータで確認してみます

処理前のテキストデータ
処理実行前のテキストデータ

まずは、処理を実行する前のテキストデータをメモ帳で開いた状態です
この文字列にそれぞれのモードで文字列の追記を行います

Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Append As #1

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

Close #1

このコードでは、Appendモードでの追記を行います
追記にはPrint#ステートメントを使用します

Appendでの書き込み時のテキストデータ
Appendでの追記実行時

コード実行後のテキストデータです
もともとある3行の下にコードで追記した文字列が挿入されています

Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Output As #1

Print #1, "新しい追加行,銀"

Close #1

こちらでは、Outputモードでの追記を行います

Outputでの書き込み時のテキストデータ
Outputでの追記実行時

コード実行後のテキストデータです
こちらでは、もともとある3行のデータは消去され、コードでの追記文字列が挿入されます

新規ファイルにデータを書き込む際には、どちらのモードを使用しても構いませんが基本的には、新規時はOutput、既存に追記時はAppendをそれぞれ使用するようにします

既存テキストデータの文字形式に注意

文字化けした状態
文字化けした状態

なお、書き込み時に文字形式がANSI形式に保存されます
もともとUTFなどで保存されていた場合、Appendモードで既存の文字列の文字形式が違ってしまい、文字化けが発生します

テキストデータを開く(読み込み用)

テキストデータをメモリ上に開くにはOpenステートメントを使用します。その時に読み込み用で開くコード

'読み込み用で開く
Open ThisWorkbook.Path & "\新しいテキスト ドキュメント.txt" For Input As #1

テキストファイルやCSSデータをテキスト形式で開くには「Open」ステートメントを使用します。

このステートメントはあくまでもテキストファイルを開く動作を行うものです
この開いたデータに対して各メソッドを使用して処理を行っていきます

ステートメントの書式

引数(太字は必須引数)
Open Pathname For Mode As # Filenumber

「Pathname」はテキストデータとして開くファイルの絶対パスを指定します
単体のファイルを指定する必要がありますので、ここでワイルドカードでのファイル名指定はできません
その場合は、FileSystemObjectを使用します

また、ここで指定したファイル名のデータが存在しない場合はファイルが新規作成されます
ただ、このOpenステートメント時点では作成はメモリ上で作成されているだけです
Closeステートメントを実行する事で保存され、ファイルが作成されます

「Mode」は開くデータの扱いに関しての指定方法です
読み込み用で開く場合には「Input」を指定します

「Filenumber」はこのテキストデータの内部的なファイル番号です
1~511の整数値で番号を指定します
この番号は同時に開く場合に、重複しない番号にする必要があります
重複した番号を指定するとエラーが発生します

同時に開くことがなく、単一で処理を実行する場合は「1」を固定で使用してかまいません

この「同時に開く」というのは、OpenステートメントからCloseステートメントの間のことで、処理実行中という意味ではありません
つまり、別のファイルであっても一度Closeステートメントで閉じた後であれば番号を振り替える必要はありません

この番号は未使用番号を取得する関数がありますので、そちらに関しては以下の記事を確認してください

テキストデータを扱う

テキストデータを扱う際の操作の流れの解説と記事一覧

VBAでテキストデータを扱うには、まずテキストデータを開く必要があります
この開くという動作は、ブックを開くというアプリを起動してデータを開く方法ではなくメモリ上にデータを開きます

以降、このメモリ上でテキストデータは操作します
追記や編集、取得を行う操作を行った後、最後にテキストデータを閉じる操作を行います

テキストデータとは、文字列のみで表現されたデータのことになります
主な使用場面は、通常のテキストデータやCSVデータ、設定用にiniファイルを操作することもできます

テキストデータを扱う際の流れは以下の通りになります

  1. テキストデータを開く-Openステートメントを使用してデータを開く
  2. テキストデータの各種操作を実行する-編集・取得を行う
  3. テキストデータを閉じる

以上の操作を行い、テキストデータの形式や使用用途によって操作を分けて実行します

テキストデータを扱う際、特にcsvデータはデータサイズが特大になりがちです
このデータを操作する際には、メモリ上に展開して操作することから処理時間が異様にかかってしまうことがあります
特にループ処理時に発生しやすいので、ループ処理に組み込む際は実装前に想定以上のビッグデータでテストしてみたほうが良いです

また、テキストデータ操作はFileSystemObjectでも行うことができます
こちらは、単一のテキストファイルだけでなくフォルダ内にあるすべてのファイルを操作する時などでは合わせて実装できるので、便利ですし
コードも分かり易くて使いやすいです

ただ、本記事の操作方法は標準コードなので前準備が必要ないのが利点です

単体のテキストデータでは、本記事操作を行う
複数のテキストデータでは、FileSystemObjectを使用する

この様に使い分けると良いと思います

環境依存文字を入力する

ChrW関数を使用して環境依存文字を入力する方法。AscW関数を使用してその文字コードも取得します

'Unicodeから文字入力
ActiveCell = ChrW(9451)
'Unicodeの文字コードを取得
Debug.Print AscW(ActiveCell.Text)

VBAで無効な環境依存文字について

PCの環境によって使用ができる「環境依存文字」という特別な表現をする文字があります

VBAでサポートされていない環境依存文字
取得できない文字

画像のような文字になります
これは「11」の変換で出てきた文字なのですが、これを見ているPCでは存在しないかもしれません、それが環境依存文字です

さらにこの文字の困ったことに、VBAで認識されない文字が存在しています
画像の文字の場合に、アクティブセルの文字列をイミディエイトに出力しようとすると「?」が返されます

これはVBAで存在しない文字列のため、表現ができない文字になります
PCの環境で使用できるはずが、VBAははじいてしまいます
わがままな困ったさんではありますねぇ

なので、これをワークシートに入力しようとして「?」を指定しても、当然「?」が入力されるだけで画像の文字を入力することは出来ません

コード解説

そこで使用するのがChrW関数です

ActiveCell = ChrW(9451)

この関数はUnicodeの文字コードで指定した文字を返す関数です
このコードを実行すると、アクティブセルに画像の環境依存文字を入力します

VBAでは無効なので、イミディエイトに出力しても「?」になるだけですが、ワークシートに出力すればちゃんと文字が入力されます

またメモリ上であれば取得は出来ているので、変数に取得させることも可能です

ただ、この文字コードは大量にあり、とても掲載できるレベルのものではありませんので調べる必要があります

Debug.Print AscW(ActiveCell.Text)

AscW関数を使用することで、指定文字のコードを調べることが出来ます
この関数は引数に指定した文字の1文字目のUnicodeの文字コードを返す関数です

この関数で使用したい環境依存文字のコードを調べたうえで、ChrW関数を使用すれば入力することが出来ます

基本的には環境依存なのであまり使用したくない文字種ですが、やはり「㈱」なんかは結構便利なので使いたくもなります

ちなみに、このUnicodeはMac版ではAscW関数でコードの取得はできません

文字コードから文字入力する

Chr関数はコードから特別な文字入力を行えます、よく使う入力コードを掲載

'「 」半角スペースを入力
Debug.Print Chr(32)
'「"」ダブルクォーテーションを入力
Debug.Print Chr(34)
'「'」シングルクォーテーションを入力
Debug.Print Chr(39)
'タブ(半角スペース4つ)を入力
Debug.Print Chr(9)
'改行文字(vblf)を入力
Debug.Print Chr(10)
'改行文字(vbcr)を入力
Debug.Print Chr(13)

文字コードから文字を入力するには「Chr」関数を使用します

引数に指定されたコードの文字を返します

例コードでは、VBAのコード中で特別な意味を持つため文字として入力する際によく使用されるものを上げています

「”」は文字列として入力したい場合に使用します、いちおう連続入力で代用はできます
このあたりの解説は以下の記事で行っています

また改行文字はVBAでよく使われるのが「vbcrlf」ですが、コードを見て分かるようにこの「vbcr」と「vblf」が結合されているものであることが分かります
Asc関数で「vbcrlf」のコードを取得すると、先にある「vbcr」の「13」が取得されます

文字コードに関しては以下のリンクから確認することが出来ます
MicrosoftDocs-文字セット(0~127)

この関数に指定するコードはAsc関数で調べることもできます
Asc関数に関しては以下の記事で解説しています

上記のAsc関数の解説記事内でもありますが、このChr関数もBとWを付与することで同じように文字コードから入力できます

ただ、VBAでは1バイト文字というのが存在しません
半角であっても2バイトで表現されるためです、なのでVBAコード上で表現できないためワークシートに入力して使用しますが、非常に使いどころが少なく良い例が見つかりませんので割愛しておきます
良い例が見つかれば改めて記事にしたいとは思います

また、ChrW関数に関しては環境依存文字を使用する場合に使用することが多いので、ここでは解説せず別の記事にて解説を行います
以下の記事で環境依存文字とからめた関数の解説を行っています

文字コードを取得する

文字コードの取得にはAsc・AscB・AscW関数を使用します。それぞれの使用方法について

'文字コードを取得
Debug.Print Asc("a")
'1バイト目の文字コードを取得
Debug.Print AscB("a")
'Unicode文字コードを取得
Debug.Print AscW("a")

文字コードを取得するには「Asc」関数を使用します
また、AscにBを付けると最初の1バイト文字を取得します
Wを付けるとUnicode文字コードを取得します

この関数の引数に指定した文字のコードを整数値で返します

なお、複数の文字を指定しても最初の1文字のコードのみが返されるので、文章に対してコードを取得する場合は1文字ずつ処理を行う必要があります
あまりそんな状況は無いとは思いますが・・・

関数の解説

Debug.Print Asc("aあ")
→→→ 97

Asc関数を使用して文字コードを取得しています
1文字目のみが対象となるため、「a」の文字コード「97」が取得されます

Debug.Print Asc("あbc")
→→→ -32096

Asc関数を使用してひらがなの文字コードを取得しています
1文字目の「あ」が対象となり、文字コード「-32096」が取得されます

Debug.Print AscB("aあ")
→→→ 97

AscB関数を使用して文字コードを取得しています
AscB関数は1バイト目の文字コードを取得します
半角文字の「a」は、上記と同じく「97」が取得されます

Debug.Print AscB("あbc")
→→→ 66

AscB関数を使用してひらがなの文字コードを取得しています
ひらがなは2バイト文字になるので、うまく取得はできません
実際このコードを使用しても、「あ」を入力することはできません

Debug.Print AscW("aあ")
→→→ 97

AscW関数を使用して文字コードを取得しています
Unicodeであっても半角文字のコードは同じなので「97」が取得されます

Debug.Print AscW("あbc")
→→→ 12354

AscW関数を使用してひらがなの文字コードを取得しています
こちらでは同じ文字であってもコードは違うため「12354」が取得されます

基本的には、ひらがなであればAsc関数の文字コード内にあるものはそれで取得すればいいです

このコード以外のものを取得する際にはAscW関数を使用します
特に環境依存文字を使用する場合には必要になります
その方法の解説は以下の記事で行っています

ダブルクリックで入力を切り替える

シートイベントのダブルクリックでセルの入力値を切り替える処理の解説

作成したい入力例
作成したい入力例

まず、この画像のような表があるとします
毎日なんらかの確認作業を行い、確認完了後にチェックを付ける表です

単純に○を入力するだけのなんてことない表ですが、これが項目数が大量にあった場合は結構大変になります
画像は結果表示なので一気に入力されてますが、実際は1つずつ入力する必要があります

そこで、セルをダブルクリックするだけでチェックを入力して、間違った時のことも考えて、ダブルクリックで○と空白を切り替えるようにします
こうすると、結構入力が楽になります

まずは、処理上選択されているセル範囲のみで実行する必要があります
見出しや日付のセルに○が入力されると困ります

名前定義セルの作成

名前定義を作成するボタン
名前の管理ボタンの場所

処理したいセル範囲を選択して、数式タブにある名前の管理ボタンからセル範囲に名前定義を作成します

名前定義の新規作成方法

名前の管理画面から新規作成ボタンを選択します

表示された新しい名前画面から、新規作成内容を設定します
名前はなんでも構いませんが、範囲はシート範囲にするようにしてください

シートを複製しても処理が問題なく動作できるように、名前定義の範囲を限定しておきます

また、画面作成をおこなわずにコードで行いたい場合は以下の記事から行ってください

シートイベントの作成

シートイベントの作成画像
イベントの作成

シートのイベントプロシージャで処理を作成していきます

今回の処理では、ユーザーの意思による操作で誤操作の可能性の低いダブルクリックを選択します
ダブルクリックは、ワークシート上では編集モードに入る操作なので無意識にしてしまうことは少ないのでこういった処理に向いています

ダブルクリックをしたときに発生するイベントが「BeforeDoubleClick」イベントになりますのでシートモジュールでプロシージャボックスから選択して作成してください

作成したコード画像
作成したコード

今回作成したコードがこのような形になっています

コード解説

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
    If Not Intersect(Range("チェック範囲"), Target) Is Nothing Then
        Cancel = True
        If Target = "○" Then
            Target.ClearContents
        Else
            Target = "○"
        End If
    Else: End If
End Sub

このコードでは、ダブルクリックされたセルが指定範囲であれば入力処理を実行します
入力処理では、空白セルには○を入力し、○が入力されていれば消去する処理です

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

シートイベントです。
シートのセルをダブルクリックした後に発生するイベントで、引数Targetにダブルクリックしたセルが代入されます

Targetにはセル範囲が代入されますので、単一セルとは限りません
ですが、ダブルクリックはExcelの仕様上必ず1セルに限定されます
この仕様からもダブルクリックイベントは使いやすいです

    If Not Intersect(Range("チェック範囲"), Target) Is Nothing Then

~~ 中略 ~~

    Else: End If

ここでTargetセル範囲と名前定義したセル範囲で処理実行するセル範囲かを判定しています
このセル範囲判定に関しては以下の記事で詳しく解説しています

        Cancel = True

このコードを実行すると、既定の動作をキャンセルします
イベントによって規定の動作は変わります

ここではセルの編集モードに入るのをキャンセルします
最後に解説しますが、入力モードに入られると非常にわずらわしいです

        If Target = "○" Then
            Target.ClearContents
        Else
            Target = "○"
        End If

最後に入力処理になります

If分岐でセルに○が入力されているかで分岐します
○が入力されていれば、ClearContentsメソッドにより入力内容を消去します
○以外であれば、○を入力します

○以外の別の文字列でも○を入力します
これはCOUNTIF関数を使用したことがある人は分かるかもしれませんが、○をカウントするのに別の文字を入力されていてうまく個数が取得できないことがあります
そういったことを回避する意味でも指定文字以外なら指定文字にしてしまいます

動きの解説

入力時のコードの動き
○が入力される動き

まずは空白セルに○を入力する動きです
セル範囲が処理実行可能範囲なので、処理が実行されます
またCancelにTrueを代入することで、ダブルクリックしたセルが編集モードに入りません

空白セルで○以外セルなので、○が入力されてい処理が完了です

入力解除時のコードの動き
セルが空白になる動き

今度は○が入力されているセルをダブルクリックしたときの動きです

今回は○が入力されているため、そのセルは空白になります

指定セル範囲以外では処理が動いてない動き
処理範囲外の動き

最後に処理が許可されていない範囲をダブルクリックしたときの動きです

日付セルは名前定義したセルとは重複していないため、最初のIf分岐で何も処理を実行しない形になっています

このとき、Cancelも変更されていないため、通常の操作通りセルの編集モードに入っていることが確認できます

この処理は、入力処理ですが非常に応用範囲が広い内容です

例えばセルへのデータ入力ではなく書式設定の変更を行えばダブルクリックでセルの背景色を切り替えたりできます
ユーザーフォームの表示処理を行うことも可能です、この場合表示ボタンが必要なくなります

まずは入力処理から行って、動きが確認できたら色々な設定変更を行ってみてください

任意のセル範囲が指定セル範囲に含まれているか調べる

Intersectメソッドを使用して処理セル範囲かを判定する方法

'アクティブセルがB列か判定
If Not Intersect(Range("B:B"), ActiveCell) Is Nothing Then
Debug.Print "範囲内"
Else: End If

任意のセル範囲が指定セル範囲に含まれているかを調べるにはIntersectメソッドを使用します

コード解説

任意のセル範囲とは、ユーザーが選択しているセル範囲であったりする
動的に変化する指定セル範囲のことになります
このコードでは、ActiveCellの部分になります

指定セル範囲とは処理の実行を前提とした固定の指定セル範囲のことになります
ActiveCellがこのセル範囲内にあれば処理を実行するような判定の親要素のセル範囲になります
コードでは、Range(“B:B”)になります

このコードを実行した時点のアクティブセルの位置によって処理が分岐します
引数のセル範囲は順番は関係ありませんので、入れ替えても使用可能です

If Not Intersect(Range("B:B"), ActiveCell) Is Nothing Then

ここで条件分岐を行っています

Intersectメソッドは重複する範囲が存在しない場合は「Nothing」を返します
Nothingは文字列ではないので、比較には「Is」演算子を使用します

これで、重複する範囲が無い時はTrueとなります
ただそれでは処理上少しわかりにくいので、逆説を取って判定します

その為に「Not」演算子を合わせて使用します
これで、範囲内に存在する場合にTrueになります

主な使用場面

ユーザーにセル範囲を指定させて処理を実行するような場合には、必ず使用します

データを入力したり、背景色を変更したりするような処理であった場合に、見出しのセル範囲であったり、関数の入力されたセルを指定されては困ります
そういった場合に、処理の実行前にこのコードで実行可否を判定します

また、Range(“B:B”)の部分を名前定義セルにすれば複雑なセル範囲も簡単に指定できますのでおすすめです

このコードをより実用的に使用するには、以下の記事にある方法を使用します