C ++でランダムな英数字の文字列を作成するにはどうすればよいですか?


180

英数字からなるランダムな文字列を作成したいのですが。文字列の長さを指定できるようにしたい。

C ++でこれを行うにはどうすればよいですか?

回答:


287

Mehrdad Afshariの答えでうまくいきますが、この単純なタスクには少し冗長すぎます。ルックアップテーブルは、不思議に思うことがあります。

void gen_random(char *s, const int len) {
    static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";

    for (int i = 0; i < len; ++i) {
        s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
    }

    s[len] = 0;
}

5
@ケント:だれかがコードをvalgrindに入れることを考えるまで、それがOpenSSLチームです。;-)
コンラートルドルフ

11
モジュラスで単純なrand()を使用したくない場合があります。参照: c-faq.com/lib/randrange.html
Randy Proctor

5
s[len] = 0が間違っていると思います。場合は、sCの文字列(NULL終了)次に、メソッドのシグネチャを有する必要がないlenことでパラメータ。Imo、長さを引数として渡す場合、配列はC文字列ではないと想定しています。したがって、C文字列を関数に渡さない場合s[len] = 0、配列が0からlen-1になるため、行が壊れる可能性があります。また、C文字列を関数に渡しても、その行s[len] = 0は冗長になります。
フェリペ

16
C ++ 11を使用するか、ランダムにブーストしてください。現在2016年です
日光

13
Stackoverflowで古い答えをシンクする方法が必要です。
Velkan、2017年

107

これがC ++ 11を使用したAtes Goralの回答の私の適応です。ここにラムダを追加しましたが、原則として、ラムダを渡して、文字列に含まれる文字を制御できます。

std::string random_string( size_t length )
{
    auto randchar = []() -> char
    {
        const char charset[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
        const size_t max_index = (sizeof(charset) - 1);
        return charset[ rand() % max_index ];
    };
    std::string str(length,0);
    std::generate_n( str.begin(), length, randchar );
    return str;
}

ラムダをランダム文字列関数に渡す例を次に示します。http//ideone.com/Ya8EKf

なぜC ++ 11を使うのですか?

  1. 興味のある文字セットについて、特定の確率分布(または分布の組み合わせ)に従う文字列を生成できるからです。
  2. 非決定論的な乱数のサポートが組み込まれているため
  3. Unicodeをサポートしているため、これを国際化バージョンに変更できます。

例えば:

#include <iostream>
#include <vector>
#include <random>
#include <functional> //for std::function
#include <algorithm>  //for std::generate_n

typedef std::vector<char> char_array;

char_array charset()
{
    //Change this to suit
    return char_array( 
    {'0','1','2','3','4',
    '5','6','7','8','9',
    'A','B','C','D','E','F',
    'G','H','I','J','K',
    'L','M','N','O','P',
    'Q','R','S','T','U',
    'V','W','X','Y','Z',
    'a','b','c','d','e','f',
    'g','h','i','j','k',
    'l','m','n','o','p',
    'q','r','s','t','u',
    'v','w','x','y','z'
    });
};    

// given a function that generates a random character,
// return a string of the requested length
std::string random_string( size_t length, std::function<char(void)> rand_char )
{
    std::string str(length,0);
    std::generate_n( str.begin(), length, rand_char );
    return str;
}

int main()
{
    //0) create the character set.
    //   yes, you can use an array here, 
    //   but a function is cleaner and more flexible
    const auto ch_set = charset();

    //1) create a non-deterministic random number generator      
    std::default_random_engine rng(std::random_device{}());

    //2) create a random number "shaper" that will give
    //   us uniformly distributed indices into the character set
    std::uniform_int_distribution<> dist(0, ch_set.size()-1);

    //3) create a function that ties them together, to get:
    //   a non-deterministic uniform distribution from the 
    //   character set of your choice.
    auto randchar = [ ch_set,&dist,&rng ](){return ch_set[ dist(rng) ];};

    //4) set the length of the string you want and profit!        
    auto length = 5;
    std::cout<<random_string(length,randchar)<<std::endl;
    return 0;
}

出力例。


少なくともMSVC 2012では、const auto randSeed = std :: random_device()を実行してから、randSeedをstd :: default_random_engine()に渡す必要があることに注意してください。std :: random_device {}()は、このバージョンではコンパイルできません。
NuSkooler 2015

8
C ++ 11を使用rand()している場合は、最初のコードスニペットで使用しない方がいいのではないですか。
Ehtesh Choudhury、2015

C ++ 11を使用すると、ジェネレーターをエンジンから分離できますが、最適なのはアプリケーションのニーズによって異なります。これが、最初のスニペットがrandを使用し、2番目のスニペットが使用しない理由です。
カール

7
私はもはやそれを使うことは決して正しくないと主張するでしょうrand()。大声で叫ぶのも均一ではない...
jeremyong

1
@Carl C ++コミュニティでは、randは非推奨であり、不均一性以外の多くの理由でよく知られているアンチパターンです(STLの講演「Rand Thought Harmful」を参照)。ビューからのジェネレーターの抽象化は、C ++の実践者と学生が学ぶために重要だと思う一般的なC ++の概念です(どのようにstd :: chrono、std :: string_viewなどに引き継ぐかを検討してください)。
jeremyong 2017

39

私の2pソリューション:

#include <random>
#include <string>

std::string random_string(std::string::size_type length)
{
    static auto& chrs = "0123456789"
        "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    thread_local static std::mt19937 rg{std::random_device{}()};
    thread_local static std::uniform_int_distribution<std::string::size_type> pick(0, sizeof(chrs) - 2);

    std::string s;

    s.reserve(length);

    while(length--)
        s += chrs[pick(rg)];

    return s;
}

多分default_random_engine代わりに使用しmt19937ますか?コードはより一般的に見えます。
Velkan

1
@Velkan std::default_random_engine標準では、実装間の品質、効率、または再現性が保証されていないため、正直に言うと私は推奨するのが良いとは思いません。
Galik

1
使用を有するので、char配列リテラルを使用しないようにするにはsizeof、変更auto&std::stringあなたを与える、std::string::length
smac89

std::stringデータへの内部ポインタが含まれているため、へのアクセスが遅くなる可能性があると感じました。これは、静的配列が必要としない追加の間接参照を意味します。また、コンパイル時定数であるため、処理sizeof速度が遅くなることはありませんstd::string::size
Galik 2018年

1
@Chronialはい、確かにそれはより良いでしょう。ただし、std::sizeそれまでは登場せずC++17、コーディングだけの人がまだたくさんいるC++11/14ので、とりあえずそのままにしておきます。
Galik

14
 void gen_random(char *s, size_t len) {
     for (size_t i = 0; i < len; ++i) {
         int randomChar = rand()%(26+26+10);
         if (randomChar < 26)
             s[i] = 'a' + randomChar;
         else if (randomChar < 26+26)
             s[i] = 'A' + randomChar - 26;
         else
             s[i] = '0' + randomChar - 26 - 26;
     }
     s[len] = 0;
 }

ニース:これは文字セットとは無関係です(少なくとも、a..z、A..Z、および0..9が連続しているすべての文字セット)。
dmckee ---元モデレーターの子猫、

2
@dmckee:trueですが、他にどのような文字セットがありますか?(EBCDICには連続した文字がありません)。
グレッグ・ヒューギル

1
ええと。私は引っかかっていると思います。私はただ教授が私に一度言ったことをただインパクトしていました...
dmckee ---元モデレーターの子猫

標準の簡単なチェックでは、セクション2.2にそのような継続性の要件はありません。
David Thornley、

2
ただし、0..9は連続している必要があります。セクション番号はありませんが、私はこれについて確信しています。
ヨハネスシャウブ-litb 2009年

10

私はこれをテストしました、それはうまくいき、ルックアップテーブルを必要としません。rand_alnum()は英数字を強制的に出力しますが、可能な256文字から62文字を選択するため、大したことではありません。

#include <cstdlib>   // for rand()
#include <cctype>    // for isalnum()   
#include <algorithm> // for back_inserter
#include <string>

char 
rand_alnum()
{
    char c;
    while (!std::isalnum(c = static_cast<char>(std::rand())))
        ;
    return c;
}


std::string 
rand_alnum_str (std::string::size_type sz)
{
    std::string s;
    s.reserve  (sz);
    generate_n (std::back_inserter(s), sz, rand_alnum);
    return s;
}

8
この関数の実行にかかる時間を知る方法はありません。それは非常にまれですが、厳密に言えば、これは無期限に実行される可能性があります。
ctrlc-root 2012

8

手動でループするのではなく、適切なC ++アルゴリズムを使用します。この場合std::generate_nは、適切な乱数ジェネレータを使用します。

auto generate_random_alphanumeric_string(std::size_t len) -> std::string {
    static constexpr auto chars =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
    thread_local auto rng = random_generator<>();
    auto dist = std::uniform_int_distribution{{}, std::strlen(chars) - 1};
    auto result = std::string(len, '\0');
    std::generate_n(begin(result), len, [&]() { return chars[dist(rng)]; });
    return result;
}

これは、私がこの問題の「標準的な」ソリューションと呼ぶものに近いものです。

残念ながら、一般的なC ++乱数ジェネレータ(MT19937など)を正しくシードすることは非常に困難です。したがって、上記のコードはヘルパー関数テンプレートを使用しますrandom_generator

template <typename T = std::mt19937>
auto random_generator() -> T {
    auto constexpr seed_bits = sizeof(typename T::result_type) * T::state_size;
    auto constexpr seed_len = seed_bits / std::numeric_limits<std::seed_seq::result_type>::digits;
    auto seed = std::array<std::seed_seq::result_type, seed_len>{};
    auto dev = std::random_device{};
    std::generate_n(begin(seed), seed_len, std::ref(dev));
    auto seed_seq = std::seed_seq(begin(seed), end(seed));
    return T{seed_seq};
}

これは複雑で、比較的非効率的です。幸い、thread_local変数の初期化に使用されるため、スレッドごとに1回だけ呼び出されます。

最後に、上記に必要なインクルードは次のとおりです。

#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>

上記のコードはクラステンプレート引数の控除を使用しているため、C ++ 17が必要です。必要なテンプレート引数を追加することで、以前のバージョンに簡単に適合させることができます。


それだけで推測されるstd::size_tためstd::uniform_int_distribution?他のCTADは表示されません
Caleth

@Caleth正解。(なぜ)これはあなたを驚かせますか?
Konrad Rudolph

私は服用をお勧めしたくなるんだrngようなもので、債務不履行のパラメータとしてtemplate <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
Caleth

それを見るのに一秒かかりました。私はおそらく精神的にを置き換えていましたがstd::uniform_int_distribution<>、これは安全ですが、符号付き->符号なしの変換について警告するかもしれません。
Caleth

6

これが誰かの役に立つことを願っています。

C ++ 4.9.2を使用してhttps://www.codechef.com/ideでテスト済み

#include <iostream>
#include <string>
#include <stdlib.h>     /* srand, rand */

using namespace std;

string RandomString(int len)
{
   string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
   string newstr;
   int pos;
   while(newstr.size() != len) {
    pos = ((rand() % (str.size() - 1)));
    newstr += str.substr(pos,1);
   }
   return newstr;
}

int main()
{
   srand(time(0));
   string random_str = RandomString(100);
   cout << "random_str : " << random_str << endl;
}

Output: random_str : DNAT1LAmbJYO0GvVo4LGqYpNcyK3eZ6t0IN3dYpHtRfwheSYipoZOf04gK7OwFIwXg2BHsSBMB84rceaTTCtBC0uZ8JWPdVxKXBd


3
プラス1、マイナス1:リーダー、注意:RandomString(100)!;-)
azhrei 2015

2
このコードはまだ壊れており、いくつかの問題があります。最も重要なstd::srand()ことは、プログラムの最初に1回だけ呼び出す必要があります(できればの最初の呼び出しですmain())。コードはそのままで、タイトループで呼び出されると、多くの同一の「ランダム」文字列を生成します。
Galik 2018

4

ここに面白いワンライナーがあります。ASCIIが必要です。

void gen_random(char *s, int l) {
    for (int c; c=rand()%62, *s++ = (c+"07="[(c+16)/26])*(l-->0););
}

2
#include <iostream>
#include <string>
#include <random>

std::string generateRandomId(size_t length = 0)
{
    static const std::string allowed_chars {"123456789BCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz"};

    static thread_local std::default_random_engine randomEngine(std::random_device{}());
    static thread_local std::uniform_int_distribution<int> randomDistribution(0, allowed_chars.size() - 1);

    std::string id(length ? length : 32, '\0');

    for (std::string::value_type& c : id) {
        c = allowed_chars[randomDistribution(randomEngine)];
    }

    return id;
}

int main()
{
    std::cout << generateRandomId() << std::endl;
}

1
randomDistribution(0、sizeof(allowed_chars)-2);であ​​る必要があります。
Archie

@Archieなんで?ルックスの罰金(minIndex、maxIndex)en.cppreference.com/w/cpp/numeric/random/...
オレグ

1
allowed_chars []には '\ 0'文字も含まれているためです。
Archie

@Archieあなたは正しいwandbox.org/permlink/pxMJfSbhI4MxLGESありがとう!
Oleg

std::string代わりに使用するソリューションを更新しましたstd::string::value_type[]
Oleg

1

文字列に印刷可能な文字が含まれている場合に備えて、さらにシンプルで基本的なものを次に示します。

#include <time.h>   // we'll use time for the seed
#include <string.h> // this is for strcpy

void randomString(int size, char* output) // pass the destination size and the destination itself
{
    srand(time(NULL)); // seed with time

    char src[size];
    size = rand() % size; // this randomises the size (optional)

    src[size] = '\0'; // start with the end of the string...

    // ...and work your way backwards
    while(--size > -1)
        src[size] = (rand() % 94) + 32; // generate a string ranging from the space character to ~ (tilde)

    strcpy(output, src); // store the random string
}

1
これが最も簡単な解決策であり、指定された文字セットのケースに絶対的に適していると思います
VolAnd

1

ランダム文字列、すべての実行ファイル=異なる文字列

        auto randchar = []() -> char
    {
        const char charset[] =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            "abcdefghijklmnopqrstuvwxyz";

        const size_t max_index = (sizeof(charset) - 1);

        return charset[randomGenerator(0, max_index)];
    };
            std::string custom_string;
            size_t LENGTH_NAME = 6 // length of name
    generate_n(custom_string.begin(), LENGTH_NAME, randchar);

には長さstd::generate_nがあると想定されるため、これは未定義の動作ですが、そうではありません。custom_stringLENGTH_NAME
Cornstalks

1

Qtの使用例:)

QString random_string(int length=32, QString allow_symbols=QString("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")) {
    QString result;
    qsrand(QTime::currentTime().msec());
    for (int i = 0; i < length; ++i) {            
        result.append(allow_symbols.at(qrand() % (allow_symbols.length())));
    }
    return result;
}

答えを詳しく説明できますか?コードの一部だけを投稿しても、あまり役に立たないことがよくあります。
Noel Widmer 2017

1

ランダムをまた便利にしよう!

私は素晴らしいC ++ 11ヘッダーのみのソリューションを作りました。プロジェクトに1つのヘッダーファイルを簡単に追加してから、テストを追加したり、別の目的でランダムな文字列を使用したりできます。

これは簡単な説明ですが、リンクをクリックして完全なコードを確認できます。ソリューションの主要部分は、Randomerクラスです。

class Randomer {
    // random seed by default
    std::mt19937 gen_;
    std::uniform_int_distribution<size_t> dist_;

public:
    /* ... some convenience ctors ... */

    Randomer(size_t min, size_t max, unsigned int seed = std::random_device{}())
        : gen_{seed}, dist_{min, max} {
    }

    // if you want predictable numbers
    void SetSeed(unsigned int seed) {
        gen_.seed(seed);
    }

    size_t operator()() {
        return dist_(gen_);
    }
};

Randomerすべてのランダムなものをカプセル化し、独自の機能を簡単に追加できます。我々が持っている後Randomer、それは文字列を生成することは非常に簡単です。

std::string GenerateString(size_t len) {
    std::string str;
    auto rand_char = [](){ return alphabet[randomer()]; };
    std::generate_n(std::back_inserter(str), len, rand_char);
    return str;
}

以下に改善のための提案を書いてください。 https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad


0

答えのどれもが私のニーズを満たしていないので、さらに別の適応。まず、rand()を使用して乱数を生成すると、実行ごとに同じ出力が得られます。乱数ジェネレータのシードは、何らかのランダムである必要があります。C ++ 11では、「ランダム」ライブラリを含めることができ、random_deviceとmt19937を使用してシードを初期化できます。このシードはOSによって提供され、私たちにとっては十分ランダムです(例:クロック)。私の場合、範囲の境界が含まれる[0,25]を指定できます。そして最後に、私は小文字のランダムな文字列だけが必要だったので、charの追加を利用しました。キャラクターのプールでは、アプローチはうまくいきませんでした。

#include <random>    
void gen_random(char *s, const int len){
    static std::random_device rd;
    static std::mt19937 mt(rd());
    static std::uniform_int_distribution<int> dist(0, 25);
    for (int i = 0; i < len; ++i) {
        s[i] = 'a' + dist(mt);
    }
    s[len] = 0;
}

0
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<char> alphanum =
    {'0','1','2','3','4',
'5','6','7','8','9',
'A','B','C','D','E','F',
'G','H','I','J','K',
'L','M','N','O','P',
'Q','R','S','T','U',
'V','W','X','Y','Z',
'a','b','c','d','e','f',
'g','h','i','j','k',
'l','m','n','o','p',
'q','r','s','t','u',
'v','w','x','y','z'
};
string s="";
int len=5;
srand(time(0)); 
for (int i = 0; i <len; i++) {
    int t=alphanum.size()-1;
    int idx=rand()%t;
    s+= alphanum[idx];
}
cout<<s<<" ";
return 0;
}


-1

関数を呼び出すときは注意してください

string gen_random(const int len) {
static const char alphanum[] = "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

stringstream ss;

for (int i = 0; i < len; ++i) {
    ss << alphanum[rand() % (sizeof(alphanum) - 1)];
}
return ss.str();
}

@Ates Goralを採用)毎回同じ文字シーケンスになります。使用する

srand(time(NULL));

関数を呼び出す前。ただし、rand()関数には常に1 つの@kjfletchがシードされます。

例えば:

void SerialNumberGenerator() {

    srand(time(NULL));
    for (int i = 0; i < 5; i++) {
        cout << gen_random(10) << endl;
    }
}

-1
#include <iostream>
#include <string>
#include <stdlib.h>
int main()
{
    int size;
    std::cout << "Enter size : ";
    std::cin >> size;
    std::string str;
    for (int i = 0; i < size; i++)
    {
        auto d = rand() % 26 + 'a';
        str.push_back(d);
    }
    for (int i = 0; i < size; i++)
    {
        std::cout << str[i] << '\t';
    }

    return 0;
}

-2
void strGetRandomAlphaNum(char *sStr, unsigned int iLen)
{
  char Syms[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  unsigned int Ind = 0;
  srand(time(NULL) + rand());
  while(Ind < iLen)
  {
    sStr[Ind++] = Syms[rand()%62];
  }
  sStr[iLen] = '\0';
}

トップランクの回答とほぼ同じように見えます。この答えが何らかの価値を追加するかどうかはわかりません。
jm。

はい、そうです "srand(time(NULL));"インデックスはすべての反復でランダムになり、文字列がよりランダムになりますxD文字列は、関数を実行するたびに異なります...また、Symsの文字は、文字列へのポインタの配列ではなく、単一の配列。
ДеянДобромиров

1
試しましたか?srand(time(NULL))は、ランダムジェネレータをすべてのサイクルで同じにリセットするため、基本的には同じシンボルの行を出力します。
OO Tiib

グッドジョブが、固定:)
ДеянДобромиров

私のSTM32F4のxD上でそれを実行します
ДеянДобромиров
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.