文字列を変換(全角・半角)

文字列の全角半角の変換にはStrConv関数を使用します。それぞれに変換するコード

'全角に変換する
Debug.Print StrConv(ActiveCell, vbWide)
'半角に変換する
Debug.Print StrConv(ActiveCell, vbNarrow)

文字列の変換には「StrConv」関数を使用します
引数の設定により、全角と半角の切り替えができます

関数の書式

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

引数「String」は、変換前の文字列を指定します
引数「Conversion」は、変換するモードの指定します

関数の解説

StrConv("aB123", vbWide)
→→→ aB123

「vbWide」を指定すると、半角を全て全角に変換します

StrConv("aB123", vbNarrow)
→→→ aB123

「vbNarrow」を指定すると、全角を全て半角に変換します

数字やアルファベット、カタカナの変換を行います。スペースも変換可能です
全角と半角の変換のためアルファベットの大文字小文字には対応しませんので注意してください

Val関数は全角の数字には対応していないため、これを使用して文字列を全て半角にしてから処理を行えばVal関数でも数値として取得ができるようになります
Val関数に関しての解説は以下の記事を確認してください

文字列の数字を数値で取得

Val関数を使用すると、文字列となった数字を数値として取得できます

'文字列を数値で取得する
Debug.Print Val(ActiveCell.Text)

文字列になっている数字を数値として取得するには「Val」関数を使用します
引数には文字列を指定します、取得が出来なかった場合は「0」が返されます

文字列になっている数値

文字列となっている数値は、そのままでは通常の計算を行えませんので変換する必要があります

文字列が計算できていない状態
文字列が計算されていない状態

画像を確認してください
画像のアクティブセルにはSUM関数が入力されています
引数には上のセル5つが指定されています

SUM関数の答えは「1123.456」になっています
A5はともかく、A1からA4までの合計値とは一致しません
これは、A3とA4が文字列で指定されているためです

SUM関数だけではありませんが、文字列での計算は行えません
この場合に変換が必要となり、この関数の出番がやってきます

また、この関数は「適切な型で返す」とリファレンスにあるように整数だけでなく小数点数値も対象にすることが出来ます

この関数は1文字目から読み込んでいき、数字以外の文字列が出てきた時点で読み込みを終了します

Val("10本")
→→→ 10

つまり上記のコードの様になります
A5セルの「10本」をVal関数で取得すると「本」で読み込みが終了して「10」が返されます

逆に先に数字以外の文字列が出てきた場合は数値に変換は出来ません
よくあるのが、和暦の年数取得ですが、これには使用できません

Val("令和2年")
→→→ 0

「令和2年」をVal関数で取得しても1文字目の「令」の時点で読み込みを終了するため「2」という数値が返されることはありません

Val("123.4 5 6")
→→→ 123.456

A4セルのような小数点の「.」やスペースは無視して読み込みが継続されるので、そういった文字列には対応可能です

特に注意したいのが全角数値は対応できない点です
数字であっても半角のみが対応しています
(※スペースは全角でも対応可能)
全角数字が含まれるデータを扱う場合は、事前に半角に変換する必要があります
以下の記事に半角への変換方法があります

使用場面は、画像の様に文字列入力された数字や数字の後に単位が入力されているような時に使用します

特にこの関数を知らないと、後に単位がある文字列を扱う際にMid関数で単位を除外して数字だけにして・・・と、非常に手間になるのでこの場面では非常に便利です

セルの行数・列数を取得する

セルの行数と列数の取得には、Row・Columnプロパティを使用します。アクティブセルの行列数の取得コード

'アクティブセルの行数を取得
Debug.Print ActiveCell.Row
'アクティブセルの列数を取得
Debug.Print ActiveCell.Column

セルの行数の取得には「Row」プロパティを使用します
列数の取得には「Column」プロパティを使用します

これは行数と列数の取得を行いますが、単体のセルの値が取得されます

行数と列数の取得時のセル選択範囲
範囲選択した状態

画像の様な範囲選択をしている状態で解説します

ActiveCell.Row
→→→ 4

アクティブセルの行数の取得です。4行目なので「4」が取得されます

ActiveCell.Column
→→→ 3

アクティブセルの列数の取得です。C列は3列目なので「3」が取得されます
列はアルファベットではなく、数値で取得されます

範囲選択をしていても、アクティブセルが範囲選択の中にあっても取得される数値が変わることはありません

Selection.Row
Selection.Column

このコードの様に、Selectionで指定すると選択範囲が指定されます
しかし、このプロパティは単一のセルに対してのプロパティのため、複数セルを指定した場合は、1番左上が指定されます

範囲選択した状態
範囲選択した状態
Selection.Row
→→→ 2
Selection.Column
→→→ 2

つまり、画像の選択範囲状態であった場合に取得されるのは
行数が「2」、列数が「2」となります
範囲選択の1番左上のB2セルの数値が取得されます

1つのセルに対してのプロパティであること、絶対数値であることの2点からもループ処理に向いているプロパティです
特にForループの数値指定を行えば、指定範囲を明確に行いやすくなります

月の初日と最終日を取得する

DateSerial関数で任意の指定日付の日付データを取得するコード。月の初日と最終日の取得

'本月の1日を取得
Debug.Print DateSerial(Year(Date), Month(Date), 1)
'本月の最終日を取得
Debug.Print DateSerial(Year(Date), Month(Date) + 1, 0)

月末の日にちを取得するには「DateSerial」関数を使用します
この関数は引数に数値で指定した年月日の日付データを返す関数です

関数の書式

引数(太字は必須引数)
(year, month, day)
戻り値の型 Valiant型(Date型)

引数の「year」は年の数値、「month」は月の数値、「day」は日にちの数値を指定します

関数の解説

この関数は引数に指定した数値の日付データを返しますが、指定する数値に関しては通常の日付数値範囲内でなくても大丈夫です

範囲内を超えた場合は、その上位の範囲に自動的に変換されます
引数「day」に「50」を指定すると、引数「month」に1が加算されて、残りの数値が日にちとして返されます

Debug.Print DateSerial(2020, 1, 50)

このコードを実行すると「2020/02/19」が取得されます
「50 – 31(1月の日数) = 19(2月の日数)」となり、月が加算されて結果の日付になります

これは引数「month」も同様で、「13」以上を指定すると引数「year」に繰り上げされます
引数「year」の繰り上げは無いので関係ありません

コード解説

Debug.Print DateSerial(Year(Date), Month(Date), 1)

本月の1日を取得します

年月はDate関数を使用してコード実行日を取得します
日にちは「1」を固定で指定することで、「○年○月1日」を取得できます

Debug.Print DateSerial(Year(Date), Month(Date) + 1, 0)

本月の最終日を取得します
関数の解説でもあるように、「Month(Date) + 1」が「12 + 1」でmonthの指定値が「13」になるので、yearに繰り上げされるので問題なく取得できます

また、この関数の特別な使い方で、「0以下の数値も指定可能」です
dayに「0」を指定すると、1日の前日が指定されるため、前月の最終日が指定されます

「前月の」なので、月に1を加算する必要があります
月に1を加算することで、来月の0日を指定することになり、来月の前月の最終日
つまり、今月の最終日を取得することが出来ました

また、マイナス数値も可能と言いましたが、その場合は指定数値分前の日にちが返されます

ワークシート関数にあるEOMONTH関数がVBAには無いので、こうした工夫をして最終日は取得します

配列変数の宣言(多次元)

多次元の配列変数の作成方法と多次元に関する解説

'2次元配列の宣言
Dim 多次元配列(3, 5) As String

多次元配列とは、通常の配列は1次元で表現されるのに対し、2次元以上の配列が多次元配列となります

この次元というものは、現実世界でいう次元とはイメージが違います
次元というのはデータの集合体であり、そのグループ分けされたものが別次元です

もはや、訳が分かりませんね
実際に、コードによって生成された変数を確認すると少し分かり易いです

多次元配列を宣言したときの状態
生成された多次元配列

ローカルウィンドウの画像です
例コードのある処理を実行した際に、2次元の配列が作成されます

青の行は変数名なので、これ以下のものが実際のデータ範囲です

すぐ下に「多次元配列(0)」があります、その中にはさらに6つの変数が存在しています
ようするに、次元数とは階層数と同じようにイメージしてもらうと画像と一致します

また、型の列を確認すると、青の行では「String(0 to 3,0 to 5)」となっています

これは要素のインデックスの下限と上限が表示されています
つまり、1次元は「0,1,2,3」の4要素、2次元は「0,1,2,3,4,5」の6要素が作成されていることが分かります

下限は変更可能ですが、常に「0」で考えるようにしてください
これは、この配列データの個数を数える場合に影響があることや、標準の設定をわざわざ変更することによるコードの可読性低下などが理由です

これに関しては変更するコードを書かなければ、常に「0」になるので、あまり意識しなくてもいいと思います

そして、1次元の「3」や2次元の「5」というインデックス最大値を取得するのがUbound関数です、これを利用して配列データの個数は取得します

この関数の解説は以下の記事で行っています

この次元数自体は、どんどん増やしていくことが可能です

Dim 多次元配列(3, 5, 8) As String

この様に、引数の数値を増やしていくだけです
これで、3次元配列が作成されます

ただ、次元数が増えすぎると管理が大変になるため、実用性で考えると2次元で十分かな
3次元ぐらいまでなら、なんとか管理できるけど、4次元以上になるとかなり複雑な配列になるのでコードも組むの大変でバグめっちゃ出そうやので、自分はしません

なにより、3次元以上はセルへの一括出力ができません
ワークシートは縦と横の2次元で表現されているためです

2次元配列は、セルへの一括出力が可能です

また、この多次元は静的、動的配列のどちらにも使用可能で使用方法もそれぞれの宣言に引数の数値をコードの様に記載するだけです

再定義時の注意点

多次元配列使用時は、Preserveキーワードでの再定義が行えません
最後の次元数は変更可能ですが、それ以前の次元数の再定義は行えません

ReDim 動的配列(5, 5, 5)

まず、最初にこのコードで3次元のそれぞれに要素数を定義します
その後、再定義を行う際に注意する必要が出てきます

ReDim Preserve 動的配列(5, 5, 6)
→→→ 実行可能

この様に最後の次元数の変更は可能です
当然、キーワードを使用しているので既存のデータは保持されています

ReDim Preserve 動的配列(5, 6, 5)
ReDim Preserve 動的配列(6, 5, 5)
→→→ 実行不可

こちらのように、最後の次元数以外の変更は出来ません
実行時エラーが発生します

このキーワードを使用せずに次元数を再定義することは可能ですが、既存のデータは初期化されてしまいます

多次元配列の動的使用時は、どの次元数がどの時点で確定するかをしっかり見極めたうえで使用する必要があります

配列のインデックスの最大値を取得

UBound関数は、配列データの個数を取得する際に使用します。実際には最大値を取得します

'配列の最大数を取得
Debug.Print UBound(配列変数)

配列変数のインデックスの最大値を取得するには「UBound」関数を使用します

関数の書式

引数(太字は必須引数)
UBound(arrayname, dimension)
戻り値の型 Long型

引数「arrayname」は、配列変数名を指定します
引数「dimension」は、取得する次元数を数値で指定します。省略時は1次元が指定されます。多次元配列を使用する際に、指定する引数です

多次元配列に関しては以下の記事を確認してください

関数の解説

基本的には、配列データの個数を取得するために使用しますが、この関数の戻り値がそのまま個数にはならない点には注意が必要です

と、いうのも配列データの下限値は任意に変更することが出来ます
下限値を3に設定してUbound関数で5が取得された時、要素数は3,4,5の3つとなります
通常は0から始まるため、Ubound関数の戻り値に1を加算すれば個数になります

こういったことからも、下限値はあまり変更しない方がいいと思います
当サイトは下限値の設定は行わず、常に0であると想定して解説しています

主には動的配列使用時に、要素を新規追加したりループの回数指定に使用したりします
要素のインデックス最大値なので、データの個数はそれに+1したものになります

また下限値を取得するには「LBound」関数を使用しますが、基本的に下限値を「0」以外に設定する処理は解説もしていませんので記事としての解説は割愛しておきます
使い方は全く同じ使い方をします

FileDialog.AllowMultiSelectプロパティ

FileDialog.AllowMultiSelectプロパティは、複数選択の許可設定です。単一選択にするコード

'単一選択のみ可能にする
Application.FileDialog(msoFileDialogFilePicker).AllowMultiSelect = False

ファイル選択のダイアログボックスで、1つのファイルのみ選択可能にするには、「FileDialog.AllowMultiSelect」プロパティに「False」を設定します
この設定を行った後に、Showメソッドを使用してダイアログを表示します

初期設定では、複数のファイル選択が可能(Trueの状態)です
フォルダの選択は複数選択ができませんので、このプロパティはファイル選択のダイアログボックスで使用します

通常、複数選択であっても処理する対象が1つで、インデックスが1番目のもののみを行っていればエラーが発生することはありません

ただ、この複数選択を行った場合はインデックスの1番目に来るものが最初に選択したものにはならないので想定外のファイルが指定される可能性があります

そういったことを無くすために、最初から単一のファイル指定しか行えないようにする場合に使用します

FileDialog.Titleプロパティ

FileDialog.Titleプロパティでは、ダイアログボックスのタイトルを設定できます

'ダイアログのタイトル文字列の設定
Application.FileDialog(msoFileDialogFilePicker).Title = "タイトル"

「FileDialog.Title」プロパティでは、表示されるダイアログボックスのタイトル部分の文字列の設定を行えます
このプロパティ変更後に、Showメソッドでダイアログを表示することで確認できます

ダイアログのタイトル設定がされた状態
タイトルが設定された状態

コードを実行して、ダイアログを表示すると枠内のタイトル部分の文字列が変更されます

ダイアログボックスの種別には影響はしないので、どの種別を使用しても問題ありません

簡単な操作の説明をここに表示することで、ユーザーが今なんのために選択をしているかが分かり易くなります

逆に名前を付けて保存のダイアログを変えてしまうと、かえって分かりにくくなる場合もありますので、使用頻度はあまり無いかもしれません

FileDialog.Filters.Addメソッド

FileDialog.Filters.Addメソッドはダイアログでファイルの種別を限定する設定です

'2003までのExcelファイル形式のみ有効にする
Application.FileDialog(msoFileDialogFilePicker).Filters.Add "旧Excelファイル", "*.xls"

ダイアログボックスでファイル選択を行う際に、指定の種類のファイルのみに限定する場合は「FileDialog.Filters.Add」メソッドを使用します
このメソッドは設定を変更するだけです、この後にShowメソッドでダイアログを表示させて確認してください

通常未設定の状態では、全てのファイルを指定することができます

ただ、Excelファイル以外のファイルを指定しても開く場合はExcelによって開かれるのでデータによっては内容が変化したり、欠損したりします

また、処理上必要なファイルに限定しておかないとバグの元にもなります
ファイルを開くダイアログの場合は基本的には使用するメソッドです

ファイル種別を限定している状態
ファイル種別を限定している状態

画像の様にコードで設定後に、ダイアログを表示することで制限がかかっていることが分かります

この状態であれば、限定された拡張子しか表示されないので後続の処理に影響を与えません

画像枠内の「旧Excelファイル(*.xls)」が引数に指定した内容になります

Application.FileDialog(msoFileDialogFilePicker).Filters.Add "旧Excelファイル", "*.xls"

1つ目の引数の文字列が、説明用の文字列です
2つ目の引数の文字列が、許可するファイルの拡張子です

これは、任意の文字列になるのでWordファイルと表示しても.xlsで指定することは可能です、混乱するだけですが

Application.FileDialog(msoFileDialogFilePicker).Filters.Add "Excelファイル", "*.xls;*.xlsx"

複数の種別を指定する場合は、この様に「;」を入れてから別の拡張子を指定することで可能です

配列データを連続していないセルに一括出力する

飛び飛びのセル範囲に一括出力する方法と考え方の解説

Dim zz配列 As Variant
'アクティブセルのある行のデータ範囲を配列に代入
zz配列 = Intersect(Range("A1").CurrentRegion, ActiveCell.EntireRow).Formula

'配列データの加工
zz配列(1, 3) = #5/15/2020#
zz配列(1, 4) = 600
zz配列(1, 6) = #5/22/2020#
zz配列(1, 7) = 900

'配列データの出力
Intersect(Range("A1").CurrentRegion, ActiveCell.EntireRow) = zz配列
'配列データの初期化
Erase zz配列

配列データをセルに出力する場合、そのセル範囲は連続している必要があります
連続していない場合は、その途切れた範囲ごとにデータの1個目から入力されていきます

例えば、以下のような表があるとします

やっかいな入力リスト
入力フォーマット

ピンクに色付けされた所に数値を入力する処理を作成します
上記にもあるように連続していないセル範囲で飛ばして配列データを出力することはできません
配列データはピンク以外の列のデータも含んでおく必要があります

この表に出力したい配列数が5個のデータを入力したいセルだけを選択状態にして出力するとします
なお、配列データは「100,200,300,400,1000」だと想定します

失敗した配列データの一括出力
うまく入力できていない状態

連続していないセル範囲に配列データを出力すると、画像の様に選択範囲のそれぞれからデータが入力されていくため、思い通りの数値が指定セルに入力されていないのが分かります
AB列は要素0(100)と1(200)が代入され、DE列も要素0と1が代入され、G列は要素0が代入されている状態になっています

本来入力したい形は、客先B_1には「300」、客先B_2には「400」、合計には「1000」を入力したかったわけです
それが実行できていません

また、客先ごとに備考列が必要なため削除して連続セルにすることはできません
この例では客先数が2つですが、これが10や50となってくるとすさまじく面倒な入力になります

これは、どうにもなりませんでした
調べても一切出てこない内容で、なかなか悩みましたが、とりあえず解決方法として考えたのが、「入力しないセルも配列データに含める」ということでした

追記:調べても出てこない、というよりそもそもセル範囲を先に取得しておけば事足りるため、その程度のことがあえて解説されていなかったのかもしれません

例コードの前提と動き

コード解説の前にまずは前提条件の説明と動きを確認します

今回入力を実行したい表範囲
入力したいセル範囲

今回の前提として、A列は年月の日付データが入っています
この表は、各月ごとを1行として、客先数分の列データが追加されていくような表データです

B列はその月の合計金額が表示されます
今回は数が少ないので簡単にSUM関数で入力金額を合計しているだけです
これが数十件以上あるような場合はSUMIF関数にする形になるでしょうね

C・D列が客先1つ目の日付と金額データです
E列はなんらかの備考情報です
この3列が客先数分作成される表となります
今回は2つしか作成していません

コードを実行したときの配列の動きと出力の動き
実際の動き

この画像で、実際の動きを確認してください
今回は5月分のデータを入力します

配列が作成され、それを加工して出力するところまでの動きをなんとなく追ってみてください

コード解説

Dim zz配列 As Variant

最初に配列データを代入する変数宣言を行います
今回はセル範囲を先に取得するので、静的配列は使用できません
動的配列を指定する必要があります、ですがセル範囲代入の場合は自動的に動的配列として認識されるので変数名だけで問題ありません

また、セル自体がどんなデータも受付するのでそれを取得するためにはValiant型で宣言しておきます

zz配列 = Intersect(Range("A1").CurrentRegion, ActiveCell.EntireRow).Formula

宣言した変数にセル範囲のデータを代入します
この時にセルオブジェクトの代入をしてしまわないように、Setステートメントは使用しないように注意してください
この代入は値の代入になるので、省略またはLetステートメントを使用する必要があります

代入元のセル範囲の指定ですが、まず表範囲全体を取得するCurrentRegionプロパティを使用して、さらにIntersectメソッドを使用してその範囲とアクティブセルのある行全体の重複する部分を取得します

つまり、表内のアクティブセル行のデータ範囲を取得します

そして、今回ここが一番重要な部分といってもいいかもしれませんが、取得する際のセル範囲のプロパティには注意が必要です

今回はFormulaプロパティを使用しています
これはセルデータのうちの数式を取得するプロパティです

今回の表データにはSUM関数が入力されていますので、通常のValueプロパティで取得を行うと、SUM関数の結果の数値が取得されてしまい
後で出力する際に、値に振り替えられ関数がなくなってしまいます

そのため、取得するセル範囲に数式が含まれている場合はFormulaプロパティを使用するようにしてください
なお、このプロパティは数式ではない場合は値を取得するので基本的にはどのデータを取得する際も問題はありません

ただ問題があるとすれば空白セルが「””」と取得される点と日付データは実データが文字列で取得されている点です
Valueプロパティで取得した場合、空白はEmpty値という特別な値になりますが、こちらでは「””」という文字列として取得されます
この辺りを処理上、判定が必要な場合は注意してください

ただ、便宜上取得して、それを出力するだけならセルが自動的に判定してくれるので問題はありません

配列データに取得させる場合のセルのプロパティには要注意です

zz配列(1, 3) = #5/15/2020#
zz配列(1, 4) = 600
zz配列(1, 6) = #5/22/2020#
zz配列(1, 7) = 900

ここは、取得した配列データの加工の部分です
今回は決め打ちの値を代入していますが、実際の処理時はここで色々な計算を行ったり、取得したデータを代入させます

この時、配列はメモリ上に展開されますので画像の様にローカルウィンドウを表示して、その配列データを展開しておくと分かりやすいです

またセル範囲の配列データは2次元配列になります
2次元目が列数になるので、今回は3・4・6・7行のデータを入力するので、その要素数の配列に代入しておきます

Intersect(Range("A1").CurrentRegion, ActiveCell.EntireRow) = zz配列

加工した配列データの出力です
出力は基本的に取得した範囲をそのまま使用するので、取得時の左辺と右辺を入れ替えるだけで処理可能です
そのため、おおよその処理ではセル範囲も変数に代入しておくと処理が実行しやすくなります

Erase zz配列

最後に配列データを初期化します
配列データはデータが大量に入っているため、1つ1つに初期値の代入を行ったりはしません
Eraseステートメントを使用して初期化します
なおこのステートメントでは、値だけでなくオブジェクトを参照していたとしても問題ありませんので、配列データの初期化にはこのステートメントを使用します