VB.NETでJVLinkからデータ取得 10 コーディング 7 (終)
前回で望みのデータを取得してExcelに落とすところまでできました。
ですが現実の競馬では、除外や取消といった予期せぬ事態が生じます。
その時、JV-Dataでは下のように処理されます。
これを見たらわかりますが、枠順確定後の取消には二種類あります。
オッズは"----"と"****"、人気は"--"と"**"のパターンです。
除外は発売後取消の"----"、"****"のほうになりますね。
さて、これらの値がJV-Dataに入ること自体は問題ないのですが、これらを処理しようとすると数字ではないので当然エラーになります。
例として3/24(日) 中山1R 3歳未勝利 のデータを取得してみます。
実行します。いつものように管理者権限でVisual Studio2019を立ち上げ、ビルド(ソリューションのビルド)→デバッグ(デバッグなしで開始)です。
馬番4番の馬が除外になっていて例外で弾かれます。
なので、値に"--", "----", "**","****"があっても処理が進むようにしてやる必要があります。
つまり、数字以外の値があった場合には無条件で
"--" → 0
"----" → 0
"**" → 0
"****" →0
にしてやればいいんです。
具体的には、コード内で単勝人気と単勝オッズをInteger.ParseとDecimal.Parseを使って直接数値に変換している箇所をTryParseを用いた変換に変更するだけでOKです。これで単勝人気と単勝オッズが数値として扱えない場合に0として扱えるようになります。
' Excel操作用の名前空間の追加
Imports OfficeOpenXml
Imports System.IO
Public Class Form1
Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
' 取得したいレースIDを指定
Dim raceNum As String = "2024032406030201"
' JVLinkからの戻り値を格納する変数を定義
Dim retval As Long
' 定数としてretvalのバッファサイズを指定
Const buffSize As Long = 1000
' JVLink初期化を実施
Me.AxJVLink1.JVInit("UNKNOWN")
' 0B31からレースIDを引数にして人気オッズを読み込みを開始
retval = Me.AxJVLink1.JVRTOpen("0B31", raceNum)
' retvalが負の値だと何かしらのエラーが発生しているので処理を中断
If retval < 0 Then
MsgBox("JVRTOpenエラー。RC=" & retval)
Exit Sub
End If
' JVRTOpenが成功した事をTextBoxにを表示
TextBox1.AppendText("JVRTOpen成功。RC=" & retval & Environment.NewLine)
' Excelファイルへの書き込み準備
Dim excelFilePath As String = "C:\Users\ユーザー名\Desktop\JVLink-TEST\JVLink_test.xlsx"
Dim fileInfo As New FileInfo(excelFilePath)
Using package As New ExcelPackage(fileInfo)
Dim worksheet As ExcelWorksheet = package.Workbook.Worksheets.FirstOrDefault(Function(x) x.Name = "Sheet1")
If worksheet Is Nothing Then
worksheet = package.Workbook.Worksheets.Add("Sheet1")
End If
Dim startRow As Integer = 2
' データ読み込みのためのループを開始
Do
' データを格納するためのバッファを準備
Dim strBuff As String = New String(vbNullChar, buffSize)
' JVLinkからデータを読み込む
retval = AxJVLink1.JVRead(strBuff, buffSize, Nothing)
If retval = -1 Then ' データの終端に達したらループを終了
Exit Do
ElseIf retval < 0 Then ' JVReadエラー処理
' エラー内容表示
MessageBox.Show("JVReadエラー。RC=" & retval)
Exit Do
ElseIf retval > 0 Then ' データが正常に読み込まれた場合、解析を行う
Dim dataStartIndex As Integer = strBuff.IndexOf("O"c) + 1
If dataStartIndex > 0 Then
Dim validData As String = strBuff.Substring(dataStartIndex).Trim()
Dim endIndex As Integer = validData.IndexOf(" "c)
If endIndex > 0 Then
validData = validData.Substring(0, endIndex)
End If
' データの成形と表示
Dim i As Integer = 0
While (42 + i * 8 + 6) <= validData.Length ' 馬番の位置と単勝人気の位置を考慮
Dim horseNumber = validData.Substring(42 + i * 8, 2) ' 馬番の頭の0を保持
Dim winOdds = validData.Substring(44 + i * 8, 4) ' 単勝オッズ
Dim winOrder = validData.Substring(48 + i * 8, 2)
' R_IDの正確な生成
Dim raceDate As String = validData.Substring(10, 8) ' 日付
Dim venueCode As String = validData.Substring(18, 2) ' 競馬場コード
Dim holdingNumber As String = validData.Substring(20, 2) ' 開催回
Dim dayNumber As String = validData.Substring(22, 2) ' 開催日数
Dim raceNumber As String = validData.Substring(24, 2) ' レース番号
Dim R_ID As String = raceDate & venueCode & holdingNumber & dayNumber & raceNumber & horseNumber ' 最終的なレースID
' 単勝オッズの整形は行わず、そのまま表示
Dim displayText = $"{R_ID}," & $"{horseNumber}," & $"{winOdds}," & $"{winOrder}"
TextBox1.AppendText(displayText & Environment.NewLine)
' Excelにデータを書き込む処理
worksheet.Cells(startRow + i, 1).Value = R_ID ' レースIDを書き込む
worksheet.Cells(startRow + i, 2).Value = Integer.Parse(horseNumber.TrimStart(New Char() {"0"c})) ' 馬番を整数として書き込む(先頭のゼロを除去)
' 単勝人気(winOrder)と単勝オッズ(winOdds)の数値変換を安全に行う
Dim winOrderInt As Integer = 0
Dim winOddsDecimal As Decimal = 0D
' 単勝人気の変換を試み、変換できなければ0を使用
If Not Integer.TryParse(winOrder, winOrderInt) Then
winOrderInt = 0
End If
' 単勝オッズの変換を試み、変換できなければ0を使用
If Not Decimal.TryParse(winOdds, winOddsDecimal) Then
winOddsDecimal = 0D
End If
' 変換結果をExcelに書き込む
worksheet.Cells(startRow + i, 3).Value = winOrderInt
worksheet.Cells(startRow + i, 4).Value = winOddsDecimal / 10D ' 単勝オッズを10で割って小数点形式で書き込む
'' 単勝人気はそのまま整数として書き込む
'worksheet.Cells(startRow + i, 3).Value = Integer.Parse(winOrder)
'' 単勝オッズをDecimal型に変換し、10で割ってExcelに書き込む(ここで整形)
'Dim winOddsDecimal As Decimal = Decimal.Parse(winOdds) / 10D
'worksheet.Cells(startRow + i, 4).Value = winOddsDecimal
i += 1 ' 次のデータ項目のために行を進める
End While
End If
End If
Loop While retval <> 0
' JVCloseを呼び出してセッションを終了
Me.AxJVLink1.JVClose()
' Excelファイルの変更を保存
package.Save()
End Using
End Sub
End Class
書き換え前と比較できるように修正部分はコメントアウトしておきました。
実行します。
このように数字以外は0にして表示できました。
<少し解説>
今回はwinOrder、winOdds のいずれかが数値として解析不可能な場合、それらの変数を自動的に0として扱うためにTryParseメソッドを使用しました。TryParseメソッドでは、変換が成功したかどうかをブール値(True or False)で返しますが、今回はその返り値を直接使用せず、変換に失敗した場合(Notキーワードによる否定)に明示的に0を設定しています。
これで変換に失敗した場合でもプログラムの実行が中断されることなく、処理が続行されるようになります。また、数値変換の際の例外も発生させることなくデフォルト値(この場合は0)を設定できます。
今シリーズはこれにて終了となります。
希望が沢山あれば今私の使っているStreamlitのRTOM向けのコードも公開します。
これに関しては関数を抜き出してしまっているので、少しとっつき辛い見た目になっています。
また、長々書いてきた気持ちで何とかする~とはかなり趣旨が離れているコードになるので、あくまで希望があればという事にしておきます。