[2019/11/22] 文字列変換関数(StrConv)の使い方 (No.142)
[2019/11/22] 文字列変換関数(StrConv)で変換が途中で切れる (No.141)
[2019/11/04] コレクション「List」の列挙中における要素の削除について (No.136)
[2019/10/28] コレクション「Dictionary」から配列及び List への変換について (No.134)
-
文字列の一種として、特殊文字の「改行」「タブ」「バックスペース」等をシステム定数として定義されています。
この定義済みの文字列を紹介します。 特殊文字として使うとすれば「復帰」「ラインフィード」「改行」「タブ」「バックスペース」ぐらいでしょうか。
以下の様にシステム定数文字列 vbCr , vbLf , vbNewLine , vbTab , vbBack を使います。 長さが1(復帰のみ2)の文字列として文字列変数にそのまま代入したり連結する形で使えます。 (これらの文字列は Microsoft.VisualBasic.Constants モジュールに定義されています。)
また Microsoft.VisualBasic.ControlChars モジュールにも同じものが定義されていますので、こちらを使うこともできます。
ところで1つはまる点があるのですが、 C# や PHP などではダブルクォテーションで文字列を定義した時に 「¥」円マーク(バックスラッシュ)でエスケープ文字として特殊文字を記述できるので VB.NET でも同じ様に記述すると 単なる「¥」と「n」等の文字そのものになります。■定義済みの文字列定数
Dim str1 As String Dim str2 As String Dim str3 As String '復帰文字 : &H0D str1 = vbCr str2 = ControlChars.Cr str3 = "\r" 'VB.NET では \ はそのままの文字列でエスケープシーケンスではない! Console.WriteLine("vbCr = ControlChars.Cr : " & (str1 = str2) & _ " ControlChars.Cr = ""\r"" : " & (str2 = str3)) 'ラインフィード文字 : &H0A str1 = vbLf str2 = ControlChars.Lf str3 = "\n" Console.WriteLine("vbLf = ControlChars.Lf : " & (str1 = str2) & _ " ControlChars.Lf = ""\n"" : " & (str2 = str3)) '復帰文字とラインフィード文字の組み合わせ : &H0D &H0A str1 = vbCrLf str2 = ControlChars.CrLf str3 = "\r\n" Console.WriteLine("vbCrLf = ControlChars.CrLf : " & (str1 = str2) & _ " ControlChars.CrLf = ""\r\n"" : " & (str2 = str3)) '改行文字(WindowsではvbCrLfと同等) str1 = vbNewLine str2 = ControlChars.NewLine str3 = "\n" Console.WriteLine("vbNewLine = ControlChars.NewLine : " & (str1 = str2) & _ " ControlChars.NewLine = ""\n"" : " & (str2 = str3)) 'タブ文字 : &H9 str1 = vbTab str2 = ControlChars.Tab str3 = "\t" Console.WriteLine("vbTab = ControlChars.Tab : " & (str1 = str2) & _ " ControlChars.Tab = ""\t"" : " & (str2 = str3)) 'バックスペース文字 : &H8 str1 = vbBack str2 = ControlChars.Back str3 = "\t" Console.WriteLine("vbBack = ControlChars.Back : " & (str1 = str2) & _ " ControlChars.Back = ""\b"" : " & (str2 = str3))上記のソースの部分のみを実行させた場合に、デバッグ出力ウインドウに以下の様に表示されました。
vbCr = ControlChars.Cr : True ControlChars.Cr = "\r" : False vbLf = ControlChars.Lf : True ControlChars.Lf = "\n" : False vbCrLf = ControlChars.CrLf : True ControlChars.CrLf = "\r\n" : False vbNewLine = ControlChars.NewLine : True ControlChars.NewLine = "\n" : False vbTab = ControlChars.Tab : True ControlChars.Tab = "\t" : False vbBack = ControlChars.Back : True ControlChars.Back = "\b" : False
当然なのですが結果から vbCr と ControlChars.Cr は同じであることがわかります。 (他の文字列も同様です)
■定義済みの文字列定数を使う場面について
上記の定義済みの文字列定数を使えば改行等がソース上に視覚的にはっきりとわかる形で記述できます。
ではどの様な時にこれを使う意味が有るのか。 私の場合、改行文字が必要な場面と言えば、 Oracle 等のデータベースへの SQL 文を作成する場合に使用します。 以下のソースでその例をしめします。生成される SQL 文は例なので意味はありません。'接続文字列(これ自身は意味がありません) Dim strConnect As String = "Data Source=//*********/test; User ID=test;Password=test;" 'オラクル接続オブジェクト Dim Conn As New OracleConnection(strConnect) 'オラクル接続オープン Conn.Open() 'SQL文 Dim strSQL As String = "" strSQL &= "SELECT " & vbCrLf strSQL &= " TT.伝票番号, TT.伝票日付" & vbCrLf strSQL &= "FROM 売上伝票 TT" & vbCrLf strSQL &= "WHERE TT.伝票日付 = TO_DATE('2019/11/12')" & vbCrLf strSQL &= "ORDER BY TT.伝票番号" & vbCrLf 'コマンドオブジェクト(SQL文と接続オブジェクト) Dim Cmd As New OracleCommand(SQL, Conn) Cmd.CommandType = CommandType.Text '読込オブジェクトに接続 Dim dr As OracleDataReader = Cmd.ExecuteReader() '*** この後はデータ処理... ***このソースでは SQL 文を SELECT FROM WHERE ORDER BY の各句で改行を入れています。
この改行ですが Oracle SQL 文の解析を行う時に空白文字の様にホワイトスペースとして扱われ、文字列の中では単語の区切りとみなされます。 そのため、この SQL 文では句の区切りとして使用しています。
改行を入れなくても、先頭に1文字空白を入れれば同じことにはなるのですが、テキストとして見ると改行が入った方が見やすい為です。 (先頭に空白を入れ忘れた時のバカ除けでもあります)
実際システムではよく実行 SQL 文のログを残したりしますが、 その時に長い文字列の1行よりも適当に改行が入っていた方が見やすいのです。
■ダブルクォテーションそのものを文字列の中に定義する方法
ダブルクォテーションそのものを文字列の中に宣言したい場合について説明します。 文字列はダブルクォテーションで囲まれていますが、その文字列の中でダブルクォテーションを2回連続して記述します。 (""として記述)
文字列の中にダブルクォテーションを記述する例として思い当たるのは、 上記のソースの SQL 文の中でカラム名とテーブル名が全角になっていますが、 Oracleではこれらをダブルクォテーションで 囲んだ方が安全です。(昔の Oracle ではある全角文字がうまく判定できないことがありました。)
結果として以下の様な記述になります。'SQL文 Dim strSQL As String = "" strSQL &= "SELECT " & vbCrLf strSQL &= " TT.""伝票番号"", TT.""伝票日付""" & vbCrLf strSQL &= "FROM ""売上伝票"" TT" & vbCrLf strSQL &= "WHERE TT.""伝票日付"" = TO_DATE('2019/11/12')" & vbCrLf strSQL &= "ORDER BY TT.""伝票番号""" & vbCrLf
PR -
文字列データを全角に全て統一したり、または半角に強制的に変換したい場合に使用するのが StrConv 関数です。 この関数は以下の様な宣言になっています。
Public Function StrConv(str As String, Conversion As Microsoft.VisualBasic.VbStrConv, Optional LocaleID As Integer = 0) As String ・str :変換する String 型の式。 ・Conversion:Microsoft.VisualBasic.VbStrConv のメンバー。 実行する比較の種類を指定する列挙値。 ・LocaleID :省略可能です。 システム LocaleID 値と異なる場合の LocaleID 値。 既定値は、システムの LocaleID です。
LocaleID の引数は通常であれば必要はありません。
尚、Conversion の引数は以下の様な種類があります。
Conversion 処理 VbStrConv.Hiragana 文字列内のカタカナをひらがなに変換します。 日本語ロケールのみに適用されます。 VbStrConv.Katakana 文字列内のひらがなをカタカナに変換します。 日本語ロケールのみに適用されます。 VbStrConv.Lowercase 文字列を小文字に変換します。 VbStrConv.Narrow 文字列内の全角文字を半角文字に変換します。 アジア ロケールに適用されます。 VbStrConv.Uppercase 文字列を大文字に変換します。 VbStrConv.Wide 文字列内の半角 (1 バイト) 文字を全角 (2 バイト) 文字に変換します。
アジア ロケールに適用されます。これらの Conversion の値を OR で連結して指定ができます。
上記の例を以下のソースで行います。
文字列変換関数(StrConv)の使用例
' 元の文字列宣言 Dim strOrg As String = "01245ABCDExyzあいうえおカキクケコサシスセソタチツテト" Dim str As String Console.WriteLine("[変換前の文字列] :" & strOrg) ' 大文字を小文字に変換 str = StrConv(strOrg, VbStrConv.Lowercase) Console.WriteLine("[大文字] ⇒[小文字] :" & str) ' 半角文字を全角文字に変換 str = StrConv(strOrg, VbStrConv.Wide) Console.WriteLine("[半角文字]⇒[全角文字]:" & str) ' 全角文字を半角文字に変換 str = StrConv(strOrg, VbStrConv.Narrow) Console.WriteLine("[全角文字]⇒[半角文字]:" & str) ' 文字列内の[カタカナ]を[ひらがな]に変換します str = Strings.StrConv(strOrg, VbStrConv.Hiragana) Console.WriteLine("[カタカナ]⇒[ひらがな]:" & str) ' 文字列内の[ひらがな]を[カタカナ]に変換します str = Strings.StrConv(strOrg, VbStrConv.Katakana) Console.WriteLine("[ひらがな]⇒[カタカナ]:" & str) ' 小文字を大文字に変換後、全角文字に変換 str = StrConv(strOrg, VbStrConv.Uppercase Or VbStrConv.Wide) Console.WriteLine("[大文字]+[全角文字] :" & str)
上記の処理を実行すると以下の様な表示が、「出力」ウインドウに表示されます。[変換前の文字列] :01245ABCDExyzあいうえおカキクケコサシスセソタチツテト [大文字] ⇒[小文字] :01245abcdexyzあいうえおカキクケコサシスセソタチツテト [半角文字]⇒[全角文字]:01245ABCDExyzあいうえおカキクケコサシスセソタチツテト [全角文字]⇒[半角文字]:01245ABCDExyzあいうえおカキクケコサシスセソタチツテト [カタカナ]⇒[ひらがな]:01245ABCDExyzあいうえおかきくけこサシスセソたちつてと [ひらがな]⇒[カタカナ]:01245ABCDExyzアイウエオカキクケコサシスセソタチツテト [大文字]+[全角文字] :01245ABCDEXYZあいうえおカキクケコサシスセソタチツテト
関連する記事
⇒文字列変換関数(StrConv)で変換が途中で切れる
-
文字列変換関数の StrConv を使っていて、変換結果が途中で切れてしまう現象が発生してしまいました。 普通に考えて以下の様な処理を行ったのですが、思った通りの結果が得られずに途中までしか変換されません。
文字列変換関数(StrConv)で変換が途中で切れるソース
Dim strOrg As String = "abcあいうえお" Dim str As String = StrConv(strOrg, VbStrConv.Wide) Debug.WriteLine("全角文字変換:" & str)上記のソースの部分のみを実行させた場合に、デバッグ出力ウインドウに以下の様に表示されました。
全角文字変換:abcあ
予想変換結果は「abcあいうえお」のはずなのですが、上手く変換されません。 変換種類の第2引数を変えてもうまくいかない場合があります。
そこでネットで調べたのですが Visual Studio が互換モードで実行されていると、 この現象が発生することがわかりました。 早速、自分のPCの Visual Studio の実行ショートカットのプロパティを開いてみました。上図の様に互換性にチェックが入っていたので、互換性のチェックを外して以下の様にしました。
Visual Studio 再度起動しなおして、上記のソースを実行すると、当然のことながら以下の結果が表示されました。
全角文字変換:abcあいうえお
Visual Studio のインストールの時点で互換性をONしていたのかもしれません。今となってはよくわかりませんが。 StrConv の変換がなぜか上手くいかない場合は互換性をチェックしてみて下さい。関連する記事
⇒文字列定数(改行、タブ、バックスペース等)について
⇒文字列変換関数(StrConv)の使い方
-
コレクションクラスの List を For Each 等で要素の削除を行いたい場合があります。 List の要素の削除ぐらい簡単だと思っていたのですが、上手くいかなかった方法と、解決方法について記します。
- 簡単に考えていた List からの要素の削除(Remove)
- 解決方法その1・List を配列の様に扱い最後尾から削除(RemoveAt)
- 解決方法その2・ToArray メソッドと For Each による削除(Remove)
■簡単に考えていた List からの要素の削除(Remove)
List を For Each で要素を順次取得し、その要素値で削除してみました。
以下のソースを見て下さい。Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click ' Listの生成(初期化) Dim list As New List(Of Integer) From {0, 1, 10, 100, 1, 1000, 1, 10000} ' 列挙中に削除する Console.WriteLine("=== Remove ===") For Each i As Integer In list Console.WriteLine("要素値「{0}」の表示", i) If i = 1 Then ' 要素値「1」が削除対象 Console.WriteLine("要素値「{0}」の削除", i) list.Remove(i) End If Next End Sub実行結果がコンソールには以下様に表示されます。
2番目の要素「1」は削除されたのですが、その直後 Next のところで System.InvalidOperationException のエラーが発生してしまいます。 For Each で要素を順次取得中に List の内容を変更したため内部的に位置がずれ、エラーが発生した様です。=== Remove === 要素値「0」の表示 要素値「1」の表示 要素値「1」の削除
■解決方法その1・List を配列の様に扱い最後尾から削除(RemoveAt)
上記の方法では先頭から削除処理を行ったので内部的にずれが発生しエラーとなったので、 今度は最後尾から削除すれば行けるのではないかと以下のソースの様に変更しました。
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click ' Listの生成(初期化) Dim list As New List(Of Integer) From {0, 1, 10, 100, 1, 1000, 1, 10000} ' 列挙中に削除する Console.WriteLine("=== Remove ===") Dim nVal As Integer Dim i As Integer For i = list.Count - 1 To 0 Step -1 nVal = list.Item(i) Console.Write("{0}番目に取得したListの要素:{1}", i, nVal) If nVal = 1 Then '要素値「1」の削除(Index指定) list.RemoveAt(i) Console.Write("...削除", i) End If Console.WriteLine("") Next Console.WriteLine("=== 削除後 ===") i = 0 For Each nVal In list Console.WriteLine("{0}番目に取得したListの要素:{1}", i, nVal) i += 1 Next End Sub結果は以下の通りです。最後尾から順次、値が「1」のものが削除され、最後に一覧してみると値が「1」の要素は確かに削除されています。
=== Remove === 7番目に取得したListの要素:10000 6番目に取得したListの要素:1...削除 5番目に取得したListの要素:1000 4番目に取得したListの要素:1...削除 3番目に取得したListの要素:100 2番目に取得したListの要素:10 1番目に取得したListの要素:1...削除 0番目に取得したListの要素:0 === 削除後 === 0番目に取得したListの要素:0 1番目に取得したListの要素:10 2番目に取得したListの要素:100 3番目に取得したListの要素:1000 4番目に取得したListの要素:10000
■解決方法その2・ToArray メソッドと For Each による削除(Remove)
今度は For Each を使うのですが、最初の失敗した方法では無く List を ToArray メソッドにより配列として取得する方法を使います。 ToArray メソッドは List を別の配列として生成し、その配列から順次その要素を取得することになります。
直接 List にアクセスするのではなく、一旦別の配列にしてそれにアクセスするので当初の様にエラーが発生しません。Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click ' Listの生成(初期化) Dim list As New List(Of Integer) From {0, 1, 10, 100, 1, 1000, 1, 10000} ' 列挙中に削除する Console.WriteLine("=== Remove ===") Dim nVal As Integer Dim i As Integer For Each nVal In list.ToArray Console.Write("{0}番目に取得したListの要素:{1}", i, nVal) If nVal = 1 Then '要素値「1」の削除 list.Remove(nVal) Console.Write("...削除", i) End If Console.WriteLine("") Next Console.WriteLine("=== 削除後 ===") i = 0 For Each nVal In list Console.WriteLine("{0}番目に取得したListの要素:{1}", i, nVal) i += 1 Next End Sub結果は以下の通りです。先頭から順次、値が「1」のものを削除します。 最後に一覧してみると値が「1」の要素は確かに削除されています。
=== Remove === 0番目に取得したListの要素:0 0番目に取得したListの要素:1...削除 0番目に取得したListの要素:10 0番目に取得したListの要素:100 0番目に取得したListの要素:1...削除 0番目に取得したListの要素:1000 0番目に取得したListの要素:1...削除 0番目に取得したListの要素:10000 === 削除後 === 0番目に取得したListの要素:0 1番目に取得したListの要素:10 2番目に取得したListの要素:100 3番目に取得したListの要素:1000 4番目に取得したListの要素:10000
関連する記事
⇒コレクション「List」の使い方について
⇒コレクション「List」と配列の相互変換について
⇒コレクション「Dictionary」の使い方について
⇒コレクション「Dictionary」から配列及び List への変換について
⇒配列の使い方について(Dim, Redim)
⇒配列の使い方の注意点について(コピー, Clone)
⇒配列の範囲指定によるコピー(Array.Copy, Skip, Take)
-
コレクションクラスの Dictionary は内部的にキー(Keys)と要素(Values)を別々のコレクションとして持っているので、 それぞれ個別に配列に変換ができます。
■Dictionary のキー・要素から配列及び List への変換(ToArray, ToList)
Dictionary のキー(Keys)及び要素(Values)はコレクションとして保持されていて、 そのコレクションとして以下の様なメソッドがあります。
メソッド or
プロパティ書式 説明 ToArray ToArray() As T()
戻り値:
コレクションの内容をそのデータ型の一次元配列を返すコレクションの内容を配列として返す ToList ToList() As List(Of T)
戻り値:
コレクションの内容を List コレクションとして返すコレクションの内容をList コレクションとして返す Count Count As Integer (これはプロパティ) コレクションに存在する要素の数を取得します CopyTo CopyTo(array() As T, index As Integer)
array:コレクションから要素がコピーされる 1次元の System.Array
index:コピーの開始位置で、array 内の 0 から始まるインデックス
例外:ArgumentOutOfRangeException
index が 0 未満
例外:ArgumentException
コレクションの要素数が index からコピー先の array の
末尾までに格納できる数を超えていますコレクション全体を互換性のある1次元の指定したインデックスから配列にコピーします
以下のソースを見て下さい。ToArray, ToList の例を記します。
配列からの要素取得は通常の For で直接要素を指標で指定し、 List の場合には For Each で順次要素を取得します。Private Sub btnList_Click(sender As Object, e As EventArgs) Handles btnList.Click Dim i As Integer = 0 ' Dictionaryの生成(初期化) Dim dic As New Dictionary(Of String, String) From _ {{"USA", "America"}, {"CHN", "China"}, {"JPN", "Japan"}} ' Values(要素の値)を配列へ変換 Dim arrVal() As String Console.WriteLine("=== Values : ToArray ===") arrVal = dic.Values.ToArray() For i = 0 To UBound(arrVal) Console.WriteLine("arrVal({0})の要素:{1}", i, arrVal(i)) Next ' Values(要素の値)を配列へのコピー Console.WriteLine("=== Values : ToList ===") Dim listV As List(Of String) = dic.Values.ToList i = 0 For Each Str As String In listV Console.WriteLine("{0}番目の要素:{1}", i, Str) i += 1 Next ' Keys(キーの値)を配列へ変換 Dim arrKey() As String Console.WriteLine("=== Keys : ToArray ===") arrKey = dic.Keys.ToArray For i = 0 To UBound(arrKey) Console.WriteLine("arrKey({0})の要素:{1}", i, arrKey(i)) Next ' Keys(キーの値)を配列へのコピー Console.WriteLine("=== Keys : ToList ===") Dim listK As List(Of String) = dic.Keys.ToList i = 0 For Each Str As String In listV Console.WriteLine("{0}番目の要素:{1}", i, Str) i += 1 Next End Sub実行結果がコンソールには以下様に表示されます。
=== Values : ToArray === arrVal(0)の要素:America arrVal(1)の要素:China arrVal(2)の要素:Japan === Values : ToList === 0番目の要素:America 1番目の要素:China 2番目の要素:Japan === Keys : ToArray === arrKey(0)の要素:USA arrKey(1)の要素:CHN arrKey(2)の要素:JPN === Keys : ToList === 0番目の要素:USA 1番目の要素:CHN 2番目の要素:JPN
■Dictionary のメソッド CopyTo について
CopyTo メソッドは指定した配列のインデックスからコレクションをコピーします。
以下の例では、最初のディクショナリを ToArray により配列に変換後、2番目のディクショナリをその配列の直後にコピーしています。 コピーする前に配列の要素数を拡張しています。Private Sub btnList_Click(sender As Object, e As EventArgs) Handles btnList.Click Dim i As Integer = 0 ' Dictionaryの生成(初期化) Dim dic As New Dictionary(Of String, String) From _ {{"USA", "America"}, {"CHN", "China"}, {"JPN", "Japan"}} Dim dic2 As New Dictionary(Of String, String) From _ {{"FRA", "France"}, {"IRL", "Ireland"}, {"THA", "Thailand"}, {"BTN", "Bhutan"}} ' Values(要素の値)を配列へ変換 Dim arrVal() As String Console.WriteLine("=== Values : ToArray ===") arrVal = dic.Values.ToArray() For i = 0 To UBound(arrVal) Console.WriteLine("arrVal({0})の要素:{1}", i, arrVal(i)) Next ' Values(要素の値)を配列へのコピー Console.WriteLine("=== Values : CopyTo ===") Dim idxMax As Integer = UBound(arrVal) ReDim Preserve arrVal(idxMax + dic2.Values.Count) dic2.Values.CopyTo(arrVal, idxMax + 1) For i = 0 To UBound(arrVal) Console.WriteLine("arrVal({0})の要素:{1}", i, arrVal(i)) Next ' Keys(要素の値)を配列へ変換 Dim arrKey() As String Console.WriteLine("=== Keys : ToArray ===") arrKey = dic.Keys.ToArray For i = 0 To UBound(arrKey) Console.WriteLine("arrKey({0})の要素:{1}", i, arrKey(i)) Next ' Values(要素の値)を配列へのコピー Console.WriteLine("=== Keys : CopyTo ===") idxMax = UBound(arrKey) ReDim Preserve arrKey(idxMax + dic2.Keys.Count) dic2.Keys.CopyTo(arrKey, idxMax + 1) For i = 0 To UBound(arrKey) Console.WriteLine("arrKey({0})の要素:{1}", i, arrKey(i)) Next End Sub結果は以下の通りです。
=== Values : ToArray === arrVal(0)の要素:America arrVal(1)の要素:China arrVal(2)の要素:Japan === Values : CopyTo === arrVal(0)の要素:America arrVal(1)の要素:China arrVal(2)の要素:Japan arrVal(3)の要素:France arrVal(4)の要素:Ireland arrVal(5)の要素:Thailand arrVal(6)の要素:Bhutan === Keys : ToArray === arrKey(0)の要素:USA arrKey(1)の要素:CHN arrKey(2)の要素:JPN === Keys : CopyTo === arrKey(0)の要素:USA arrKey(1)の要素:CHN arrKey(2)の要素:JPN arrKey(3)の要素:FRA arrKey(4)の要素:IRL arrKey(5)の要素:THA arrKey(6)の要素:BTN
関連する記事
⇒コレクション「List」の使い方について
⇒コレクション「List」と配列の相互変換について
⇒配列の使い方について(Dim, Redim)
⇒配列の使い方の注意点について(コピー, Clone)
⇒配列の範囲指定によるコピー(Array.Copy, Skip, Take)