C ++에서 임의의 영숫자 문자열을 어떻게 만듭니 까?


180

영숫자 문자로 구성된 임의의 문자열을 만들고 싶습니다. 문자열의 길이를 지정할 수 있기를 원합니다.

C ++에서 어떻게해야합니까?

답변:


288

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 팀이 그렇게했습니다. ;-)
Konrad Rudolph

11
모듈러스와 함께 간단한 rand ()를 사용하고 싶지 않을 것입니다. 참조 : c-faq.com/lib/randrange.html
랜디 프록터에게

5
s[len] = 0이 잘못 되었다고 생각합니다 . 경우 s는 C 문자열 (NULL 종료)는 다음 메소드의 서명이 있어야하지 않을 len그것의 매개 변수를. Imo, 길이를 인수로 전달하는 경우 배열이 C 문자열이 아니라고 가정합니다. 따라서 C 문자열을 함수에 전달하지 않으면 s[len] = 0배열이 0에서 len-1로 이동하므로 행 이 중단 될 수 있습니다. 그리고 C 문자열을 함수에 전달하더라도 줄 s[len] = 0은 중복됩니다.
Felipe

16
C ++ 11을 사용하거나 무작위로 부스트하십시오. 우리는 지금 2016 년입니다
Nikko

13
우리는 stackoverflow에서 쓸모없는 답변을 싱크하는 방법이 필요합니다.
Velkan

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. 유니 코드를 지원하므로 국제화 된 버전으로 변경할 수 있습니다.

예를 들면 다음과 같습니다.

#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에서는 auto randSeed = std :: random_device ()를 구성한 다음 randSeed를 std :: default_random_engine ()에 전달해야합니다. std :: random_device {} ()는이 버전으로 컴파일 할 수 없습니다.
NuSkooler

8
C ++ 11을 사용하는 경우 rand()첫 번째 코드 스 니펫에 사용하지 않는 것이 낫지 않습니까?
Ehtesh Choudhury

C ++ 11을 사용하면 발전기와 엔진을 분리 할 수 ​​있지만 가장 좋은 것은 응용 프로그램의 요구 사항에 따라 다릅니다. 이것이 첫 번째 스 니펫이 랜드를 사용하고 두 번째 스 니펫은 그렇지 않은 이유입니다.
Carl

7
더 이상 사용하는 것이 결코 옳지 않다고 주장합니다 rand(). 큰 소리로 외치는 것도 균일하지 않습니다.
jeremyong

1
@Carl 저는 C ++ 커뮤니티에서 rand는 비 균일 성 (non-uniformity)을 제외하고는 여러 가지 이유로 더 이상 사용되지 않으며 잘 알려진 안티 패턴이라고 생각합니다 (STL의 "유해한 랜드"). 뷰에서 생성기의 추상화는 C ++의 실무자와 학생들에게 배우는 것이 중요하다고 생각하는 일반적인 C ++ 개념입니다 (std :: chrono, std :: string_view 등으로 전달하는 방법을 고려하십시오).
jeremyong

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

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 : 사실이지만 다른 문자 세트는 무엇입니까? (EBCDIC에는 연속 문자가 없습니다).
Greg Hewgill

1
음 내가 잡힌 것 같아 교수님이 한 번 말씀하신 것을 앵무새
dmckee --- 전 운영자 고양이

표준에 대한 빠른 점검은 섹션 2.2에서 그러한 연속성 요구 사항을 보여주지 않습니다.
David Thornley

2
그러나 0..9는 연속적이어야합니다. 섹션 번호는 없지만 확실합니다.
Johannes Schaub-litb

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

9

오히려 수동 루프보다 적절한 사용을 선호 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변수 를 초기화하는 데 사용 되므로 스레드 당 한 번만 호출됩니다.

마지막으로 위의 필수 항목은 다음과 같습니다.

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

위의 코드는 클래스 템플릿 인수 공제 를 사용하므로 C ++ 17이 필요합니다. 필요한 템플릿 인수를 추가하여 이전 버전에 맞게 간단하게 조정할 수 있습니다.


그것은 단지 추론됩니다 std::size_t에 대한 std::uniform_int_distribution?
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

2
이 코드는 여전히 손상되었으며 몇 가지 문제가 있습니다. 가장 중요한 것은 프로그램 시작시 std::srand()실제로 한 번만 호출해야합니다 (바람직하게의 첫 번째 항목 main()). 코드는있는 그대로 타이트 루프에서 호출되면 동일한 "임의의"문자열을 많이 생성합니다.
Galik

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/…
Oleg

1
allowed_chars []에도 '\ 0'문자가 포함되어 있습니다.
Archie

@Archie 당신이 맞습니다 wandbox.org/permlink/pxMJfSbhI4MxLGES 감사합니다!
Oleg

내가 사용하는 솔루션 업데이트 std::string대신std::string::value_type[]
올렉

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);

has length 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

1

무작위로 다시 편리하게합시다!

나는 멋진 C ++ 11 헤더 전용 솔루션을 구성했습니다. 하나의 헤더 파일을 프로젝트에 쉽게 추가 한 다음 테스트를 추가하거나 다른 목적으로 임의의 문자열을 사용할 수 있습니다.

간단한 설명이지만 링크를 따라 전체 코드를 확인할 수 있습니다. 솔루션의 주요 부분은 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
//C++ Simple Code
#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))은 랜덤 생성기를 모든 사이클과 동일하게 재설정하므로 기본적으로 동일한 기호의 행을 인쇄합니다.
Öö Tiib

잘 했어요, 고정 :)
Деян Добромиров

그것은 내 STM32F4의 xD에서 실행
Деян Добромиров
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.