空腹おやじのログと備忘録

VBA(主にExcel)でいろいろな実験的な事とか、Linuxのコマンドとか設定とかについて忘れないように、あれこれと・・・

【VBA】9桁以上の16進数表記文字列同士のORを求める

昨日、Twitter で、
「16進数のORをとるのにもっと効率のいいやり方ある?」
というやつを見つけました。

スマホの小さい画面で見ていたので、
実は細かいところまでは見えなかった(見てなかった?)ので
「単純にLongに変換して、OR とって、Hex で16進表記に戻せばいいのでは」と
返したら、どうも4Byte超相当(9桁以上)の文字列を処理したいらしい。

32bit版では Long(16進数表記で8桁)までしか処理できないので、
8桁ずつループ処理するコードを書いてみました。

なお、Twitter で返したコードを少し変えてあります。

Public Function HexStringOr(ByVal sHexValue1 As String, ByVal sHexValue2 As String) As String

    Dim lLen1       As Long
    Dim lLen2       As Long
    Dim lResultLen  As Long
    Dim lOrgLen     As Long
    Dim sHexW1      As String
    Dim sHexW2      As String
    Dim sResult     As String
    Dim lStartPos   As Long
    Dim lHex1       As Long
    Dim lHex2       As Long
    Dim lHexW       As Long
    Dim i           As Long

    Const ZERO8 As String = "00000000"

    '16進文字列判定
    If isHexString(sHexValue1) = False Then
        Exit Function
    ElseIf isHexString(sHexValue2) = False Then
        Exit Function
    End If

    lLen1 = Len(sHexValue1)
    lLen2 = Len(sHexValue2)

    If lLen1 >= lLen2 Then
        lOrgLen = lLen1
    Else
        lOrgLen = lLen2
    End If

    '8の倍数となる文字列長を求める
    lResultLen = ((lOrgLen + 7) \ 8) * 8

    'ゼロパディング
    sHexW1 = String$(lResultLen - lLen1, "0") & sHexValue1
    sHexW2 = String$(lResultLen - lLen2, "0") & sHexValue2

    '結果格納用文字列(ダミー0埋め)
    sResult = String$(lResultLen, "0")

    For i = 1 To lResultLen \ 8
        '処理先頭位置
        lStartPos = 1 + (i - 1) * 8

        '8文字抜き出してLongに変換
        lHex1 = CLng("&H" & Mid$(sHexW1, lStartPos, 8))
        lHex2 = CLng("&H" & Mid$(sHexW2, lStartPos, 8))

        lHexW = lHex1 Or lHex2

        '結果を格納
        Mid$(sResult, lStartPos, 8) = Right$(ZERO8 & Hex(lHexW), 8)
    Next i

    '元のデータの桁に合わせてから返す
    HexStringOr = Right$(sResult, lOrgLen)

End Function

'16進文字列判定
Private Function isHexString(ByVal sValue As String) As Boolean

    If Len(sValue) = 0 Then
        Exit Function
    End If

    isHexString = Not sValue Like "*[!0-9a-fA-F]*"

End Function


実行サンプル

? HexStringOr("1234567890ABCDEF11","22222222")
1234567890ABEFEF33

? HexStringOr("444444442222222200001122","1111222200008888CCCC3333")
555566662222AAAACCCC3333

? HexStringOr("004444444422222222000011","001111")
004444444422222222001111


「これで(速度的な意味で)効率が良くなったのか?」と聞かれれば、もちろん
「ほとんど変わらないよ!!!」
と言っちゃいます。m(_ _)m

パラメータの文字列が、数千桁とか数万桁なら、こっちの方が若干速いような気がしますけど。

最後に

今回のように、生成される文字列長が予め分かっているような場合には、
都度、文字列を結合するより、
予め、結果の文字列長のダミー文字列を用意しておいて、
それに対して、MidステートメントMid関数ではありません)で埋め込んでいったほうが効率的です。

左辺にMidがあるのは、見慣れないかもしれませんが、
覚えておくと便利です。

docs.microsoft.com

docs.microsoft.com