2012年11月27日火曜日

Java で、ランダムな文字列を生成する方法

まずJavaにはランダムを提供するクラスとして

java.util.Random
java.security.SecureRandom
の2つがあってRandomクラスは以下のような強度しか持っていない。

Random クラスのインスタンスは、一連の擬似乱数を生成します。クラスでは 48 ビットのシードを使い、このシードは線形合同法で変更されます。
no title
しかも初期化があまりよくなくて初回の乱数がとても偏る。

Random r = new java.util.Random();
double x, min = 1, max = 0;
for (int i = 0; i < 1024; i++) {
r.setSeed(i);
x = r.nextDouble();
if (x > max)
max = x;
if (x < min)
min = x;
}
System.out.println("Min=" + min + " Max=" + max);
Min=0.6753377750582709 Max=0.7669794809891215

こんなプログラムを回してみるとと1000通りの種を渡しても初回生成値が極度に偏ってしまう。

んで、SecureRandomはこのあたりの問題を解消するのでててきた。

for (int i = 0; i < 1024; i++) {
sr.setSeed(i);
x = sr.nextDouble();
if (x > max){
max = x;
}
if (x < min){
min = x;
}
}
BigDecimal bigMin = new BigDecimal(min).setScale(16,BigDecimal.ROUND_HALF_UP);
System.out.println("Min=" + bigMin + " Max=" + max);
x = 0.0;
Min=0.0004351500205996 Max=0.9986417236968099

SecureRandomにすると一気に分散するようになった。



ランダムな文字列を生成するには

そもそもランダムな文字列を作る為にRandomを久々にみてたわけですが、

今普通にランダムな文字列を使うのならcommons-langのRandomStringUtilsで事足りる。

アスキー文字なら

RandomStringUtils.randomAscii(10)
⇒DF|M1!7W=@
アルファベットなら

RandomStringUtils.randomAlphabetic(10)
⇒doKntQIMve
数字なら(0始まりも生成されてしまうので注意)

RandomStringUtils.randomNumeric(10)
⇒8266471697
頭0を嫌うなら
RandomStringUtils.random(1,"123456789") + RandomStringUtils.randomNumeric(9);
自分で指定した文字の中からランダムにしたいのなら

RandomStringUtils.random(10,"012345abcdef");
⇒c021cc0b24
長さもランダムにしたいのならRandomUtils.nextIntと組み合わせて(1〜3文字のランダムな文字が変える)

RandomStringUtils.random(RandomUtils.nextInt(3)+1,"12345678");
⇒1
⇒255
⇒86

0 件のコメント:

コメントを投稿