投稿者 魔界の仮面弁士  (社会人) 投稿日時 2021/10/16 11:56:21
> 12 36  45  5
>  7 69  21 30

むむ…!?

数字はすべて半角ですが、区切りとなる空白部には
半角スペースの" " は一切用いられておらず、すべて
全角スペースの" " が使われていますね。
しかも列によって、スペースの数が異なるようで。

固定長のデータというわけでもないですし、かといって
スペースの数が数字の桁数に依存しているわけでも無さそう…?
かなり変則的ですね。

視認しやすいよう、全角スペースを別の文字に置き換えたものを載せておきます。
12🟩36🟩🟩45🟩🟩5
🟩7🟩69🟩🟩21🟩30



質問文からは正確な仕様が読み切れなかったので、ここでは仮に下記の仕様として話を進めますね。

① 情報源となる「4列のテキストデータ」は、Shift_JIS で書かれたテキストファイルから得るものとする。
② 1個以上の連続した空白を区切り文字とみなす。
③ 4列構成を前提とし、空要素な列は無いものとする。
④ 各列の中身は半角数字のみで構成され、"01" などは "1" と同義。全角数字や小数は無し。
⑤ 列を区切る空白として、全角スペース" "・半角スペース" "・水平タブ" "の 3 種を許容する。
⑥ 行頭(あるいは行末)には、0個以上の空白を含めても良い。
⑦ 行と行の間には、CrLf 改行が含まれる。(行末改行ではなく行間改行なので、最終行には改行が無い)



> C(1)=45
C(1)="45" ではなく C(1)=45 となっていることから、
String の配列ではなく、数値の配列が必要なのですね。
今回はひとまず Integer ということにしておきます。

> A(1)=12
> B(1)=36
全角の変数と半角の変数が混在しているのが気になりますが、あえてそうしているのでしょうか?
話がややこしくなるため、ここでは半角1文字の A/B/C/D に統一させていただきますね。


ところで、最初のインデックスが (0) ではなく (1) なのは何故でしょうか。
(もしかして、先頭に列名を表す行があって、それをスキップしているとか?)

御存知とは思いますが、.NET では Option Base 1 な配列を選択することができません。

.NET そのものは、A(1 To 2) や A(-3 To -1) といった配列もサポートしているのですが、
VB.NET の方は言語仕様として、0 ベースでない限りはプリミティブな配列として扱われません。
そのため今回は、A(0) = 12、A(1) = 7 という結果になる前提に書き換えさせてもらいます。

なお、VB6 の経験をお持ちならわかると思いますが、配列というものは
事前に要素数の定義が必要です。行数が可変なファイルの読み取りに使うのは不便です。

VB6 でも VB.NET でも、一応は「ReDim Preserve」ステートメントを用いることで、
元データを維持したまま要素数を事後変更できますが、このステートメントは、
 ①新しい配列を別メモリに確保
 ②そこに既存のデータを複写
 ③古い方のメモリを破棄する
という 3 ステップを内部的に行うため、要素数が増えるほど、
ReDim Preserve のパフォーマンスは明らかに落ちていきます。

そのためこういったケースでは、配列ではなく List(Of ) クラスを用いた方が良いでしょう。
List(Of ) ならば、事前に要素数を決める必要がありませんし、追加・挿入・削除も容易です。

また、List(Of ) と一次元配列は、.ToArray() および .ToList() という拡張メソッドを使うことで
相互変換もできるので、既存ソースへの影響もほとんどないはずです。

とはいえ今回は配列がお望みということなので、その前提で組んでみました。
要件定義で不明瞭な点は、こちらで好き勝手に定めてしまっているので、
そちらの事情に合わない部分は、適宜修正してください。

'Imports System.IO 
'Imports System.Text 

'ファイル名と文字コードは適宜修正してください 
Dim fileName As String = "C:\test\example.txt"
Dim enc As Encoding = Encoding.GetEncoding("Shift_JIS")

'列ごとに区切る処理です。 
Dim q = (
    From s In File.ReadLines(fileName, enc)
    Let ary = s.Replace(" ", vbTab).Replace(" ", vbTab).Split(
        New String() {vbTab}, StringSplitOptions.RemoveEmptyEntries)
    Where ary.Length = 4 '←4列以外の行も許容する場合はこのWhereを省きます 
    Select ary).Select(
        Function(Columns, RowIndex) New With {Key RowIndex, Columns}
    ).ToArray()

'件数が分かったので、配列4つを初期化しておき… 
Dim upperIndex As Integer = q.Length - 1
Dim A(upperIndex), B(upperIndex), C(upperIndex), D(upperIndex) As Integer

'整数に変換しながら、文字列配列から整数配列に代入しなおします(変換失敗時は 0 を代入) 
For Each x In q
    Integer.TryParse(x.Columns(0), A(x.RowIndex))
    Integer.TryParse(x.Columns(1), B(x.RowIndex))
    Integer.TryParse(x.Columns(2), C(x.RowIndex))
    Integer.TryParse(x.Columns(3), D(x.RowIndex))
Next


なお今回、途中に 4 列構成ではない行(たとえば6列ある行や2列しか無い行など)が
含まれていた場合、エラーにするのではなく、その行の存在を無視するようにしています。

そのため、配列のインデックスは 0 から始まる番号としてはいますが、
このインデックスは、元のテキストの行番号と必ずしも一致するとは限らない点にご注意を。