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

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

VBAで乱数を使って、意味不明(?)な文字列を生成する・・・コケヲチヰヱタトンシ

いろいろな処理をするコードを書いていると、テスト用の文字列データが欲しくなる時があります。
5個とか10個位なら適当にキーボードから入力して作ってもいいのですが、数百とか数万とか、それ以上となるととても手入力では無理なので、どこかから探してくるか、あるいは自分で作るかということになります。

内容はどうでもいいから、とにかくデータが欲しいような時には、乱数を使って作ってしまいましょう。

基本的な事

乱数を使用するにあたって、必要なのは、以下の2つです。
Rnd関数
Randomize ステートメント

Rnd関数の使い方は、ここでは省略します。

特定の範囲の整数を生成するには以下のような計算を行います。

Randomize
ランダム整数 = Int((最大値 - 最小値 + 1) * Rnd) + 最小値

最大値、最小値のいずれも整数を指定します。
負の数を指定しても大丈夫ですが
最小値<最大値
はmustです。

数字の場合

前述の式を使って取得した値をCStr関数またはFormat関数で文字列変換します。
固定桁数にし、前に0を付けたい場合には、

? Format$(123,String$(7,"0"))
0000123
? Right$(String$(6,"0") & CStr(123),7)
0000123

こんな感じで出来ます。
注)元データの桁数が指定桁を超えた場合(上の例では7桁)、上記の2例は結果が異なりますので、ご注意ください。

アルファベットの場合

最初の式で得られるのは整数なので、これをアルファベットに変換しなければいけません。
この変換には、Chr関数を使います。
Chr関数には、文字コードを渡しますが、アルファベットの場合、ASCIIコードを指定すればOKです。
ASCIIコードは、こちらで確認できます。

大文字、小文字それぞれの範囲は、以下のようになることがわかります。

文字 文字コード
A &H41
Z &H5A
a &H61
z &h7A

イミディエイトウィンドウで確認してみると

? Chr(&H41)
A
? Chr(&H5A)
Z
? Chr(&H61)
a
? Chr(&H7A)
z

となります。

以上を踏まえて、コードは以下のようになります。

Public Function creaeStringAlpha(ByVal lLength As Long, ByVal useUpperCase As Boolean) As String

    Dim iBeginCode  As Integer
    Dim iEndCode    As Integer
    Dim sResult As String
    Dim i   As Long

    If useUpperCase Then
        iBeginCode = Asc("A")
        iEndCode = Asc("Z")
    Else
        iBeginCode = Asc("a")
        iEndCode = Asc("z")
    End If

    Randomize

    For i = 1 To lLength
        sResult = sResult & Chr(Int((iEndCode - iBeginCode + 1) * Rnd) + iBeginCode)
    Next i

    creaeStringAlpha = sResult

End Function

useUpperCase に Trueを指定すれば大文字で、Falseを指定すれば小文字で生成します。
大小混在としたい場合には、開始コードをAsc("A")、終了コードをAsc("z")とした上で、一旦生成した文字(文字ではないですよ)が、A~Z、a~zであるかを確認し、OKなら結合、駄目なら再度文字生成し直しというような処理にすればできます。(下記の英数混在を参照)

開始の文字コードと終了の文字コード&H○○と直接書いてもいいのですが、あとから見て「なんだこれ?」となるのが(私の場合)普通なので、あえてコメント無しでもわかるような書き方をしています。

実行例(イミディエイトウィンドウ)
for i=1 to 5:? creaeStringAlpha(10,True):next
YPMLCFTQXW
WOIGQGMJCU
ODWMWPUGGP
UJOWHJNLLM
FKPAEYZHKK

for i=1 to 5:? creaeStringAlpha(10,false):next
rkwqfoyvpr
nyzkqsiren
hygqzyzlyl
djbrscyzxh
fpenxaqfrd

英数混在の場合

先程ちょっと出てきた「対象外のコードを除外」をするとこんな感じで出来ます。
ASCIIコードは、
数字 < アルファベット大文字 < アルファベット小文字
なので、
最小文字コードは、数字の最小:Asc("0")
最大文字コードは、アルファベット小文字の最大:Asc("z")
を使用します。

Public Function creaeStringAlphaNum(ByVal lLength As Long) As String

    Dim iBeginCodeN     As Integer
    Dim iEndCodeN       As Integer
    Dim iBeginCodeAU    As Integer
    Dim iEndCodeAU      As Integer
    Dim iBeginCodeAL    As Integer
    Dim iEndCodeAL      As Integer
    Dim iCode   As Integer
    Dim sResult As String
    Dim i       As Long

    iBeginCodeN = Asc("0")
    iEndCodeN = Asc("9")
    iBeginCodeAU = Asc("A")
    iEndCodeAU = Asc("Z")
    iBeginCodeAL = Asc("a")
    iEndCodeAL = Asc("z")

    Randomize

    For i = 1 To lLength
        Do While True
            iCode = Int((iEndCodeAL - iBeginCodeN + 1) * Rnd) + iBeginCodeN

            Select Case iCode
            Case iBeginCodeN To iEndCodeN
                Exit Do
            Case iBeginCodeAU To iEndCodeAU
                Exit Do
            Case iBeginCodeAL To iEndCodeAL
                Exit Do
            End Select
        Loop

        sResult = sResult & Chr(iCode)
    Next i

    creaeStringAlphaNum = sResult

End Function
実行例(イミディエイトウィンドウ)
for i=1 to 5:? creaeStringAlphaNum(20):next
sC2TMIaUKFpJgxGLCjV8
UDnhkqy3OOG6Lk4QdwZC
5AldQ84Ug33RKwTtbIyj
W1Wd1iifx2qrJ66IxNp9
Lj31yD74w0In3i8zqEn2

ひらがなの場合

基本的には、アルファベットの時と同じですが、ひらがなの場合文字コードがASCIIコードではなく、ユニコードを使用することになるのでChr関数がChrW関数に、Asc関数がAscW関数を使用することになります。

ユニコードのひらがなは、
こちらを見てください。
VBAでは、一部の文字(&H3094以降の一部)が使用できないため、それらの文字は除外する必要があります。

コードは、

Public Function creaeStringKana(ByVal lLength As Long) As String

    Dim iBeginCode  As Integer
    Dim iEndCode    As Integer
    Dim sResult As String
    Dim i   As Long

    '厳密には違うが、VBAで対応できないので、対応可能範囲に限定する
    iBeginCode = AscW("ぁ")
    iEndCode = AscW("ん")

    Randomize

    For i = 1 To lLength
        sResult = sResult & ChrW(Int((iEndCode - iBeginCode + 1) * Rnd) + iBeginCode)
    Next i

    creaeStringKana = sResult

End Function
実行例(イミディエイトウィンドウ)
for i=1 to 5:? creaeStringKana(10):next
ふだわんぇよずぽへゎ
ろすいらうぱこだぶよ
ゎゆめぐほばぽきぴぺ
わたのぞらぼづきそあ
をむゑろもべぬぶぼよ

カタカナの場合

ひらがなの時と同じですね。コードの範囲が変わるだけです。
文字コードこちらになります。

コードは、

Public Function creaeStringKatakana(ByVal lLength As Long) As String

    Dim iBeginCode  As Integer
    Dim iEndCode    As Integer
    Dim sResult As String
    Dim i   As Long

    '厳密には違うが、VBAで対応できないので、対応可能範囲に限定する
    iBeginCode = AscW("ァ")
    iEndCode = AscW("ヶ")

    Randomize

    For i = 1 To lLength
        sResult = sResult & ChrW(Int((iEndCode - iBeginCode + 1) * Rnd) + iBeginCode)
    Next i

    creaeStringKatakana = sResult

End Function
実行例(イミディエイトウィンドウ)
for i=1 to 5:? creaeStringKatakana(10):next
ヶェコゼヂクズザシヤ
ゥゼゼキピォンナイベ
ヲヒユテビゲネモツノ
ズェャヨベリコデグダ
コケヲチヰヱタトンシ

"ヰヱ"なんて誰が使うんだよっ! orz

2019/4/1追記
不連続の多い文字群の場合、キーコードを使用しないで、予め使用可能な文字を配列に1文字ずつ突っ込んで全部結合してから、rndで発生させた乱数で配列のインデックスを指定してもいいのかもしれない全部結合してから、rndで発生させた乱数を使って、midで抜き出してもいいのかもしれない。
これなら、半角、全角混在でも簡単(?)に出来そう。

2019/4/2追記
昨日のアイデアを元に、簡単なパスワード生成関数を作ってみた。

Public Function createPassword(ByVal lLength As Long) As String

    Const USABLE_CHARS  As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%(){}"

    Dim lPos        As Long
    Dim sPassword   As String
    Dim i           As Long

    Randomize

    For i = 1 To lLength
        lPos = Int(Len(USABLE_CHARS) * Rnd) + 1

        sPassword = sPassword & Mid$(USABLE_CHARS, lPos, 1)
    Next i

    createPassword = sPassword

End Function

実行結果

for i=1 to 15:? createPassword(10):next
lG%wfn9kA7
#VkE0X!xN}
pAFE6hQHhK
}EhwtPoBEE
nZZeeiDYC4
Ivrs96dxq%
0)NsDNg#8v
f8JG3rd07o
hamu)ojZXd
Y%Zwlxh4VT
dCgkztKKFK
VU6(y!xdfB
ba!2Pu6bs4
Wi4ei!Gbc)
w{oG{ZZ(ov