[javascript] JavaScript에서 임의의 문자열 / 문자 생성

세트에서 무작위로 선택한 문자로 구성된 5 개의 문자열을 원합니다 [a-zA-Z0-9].

JavaScript로 이것을 수행하는 가장 좋은 방법은 무엇입니까?



답변

나는 이것이 당신에게 효과가 있다고 생각합니다.

function makeid(length) {
   var result           = '';
   var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
   var charactersLength = characters.length;
   for ( var i = 0; i < length; i++ ) {
      result += characters.charAt(Math.floor(Math.random() * charactersLength));
   }
   return result;
}

console.log(makeid(5));


답변

let r = Math.random().toString(36).substring(7);
console.log("random", r);

참고 : 위 알고리즘에는 다음과 같은 약점이 있습니다.

  • 부동 소수점을 스트링화할 때 후행 0이 제거되므로 0에서 6 문자 사이에서 생성됩니다.
  • 부동 소수점 숫자를 문자열 화하는 데 사용되는 알고리즘에 크게 의존합니다. ( “부동 소수점 숫자를 정확하게 인쇄하는 방법” 종이 참조 )
  • Math.random()구현에 따라 예측 가능한 ( “임의의 외형”이지만 실제로는 무작위가 아닌) 출력을 생성 할 수 있습니다. 결과 문자열은 고유성 또는 예측 불가능 성을 보장해야 할 때 적합하지 않습니다.
  • 6 개의 균일하고 무작위로 예측할 수없는 문자를 생성하더라도 생일 역설 로 인해 약 50,000 개의 문자열 만 생성 한 후에 복제본을 볼 수 있습니다 . (sqrt (36 ^ 6) = 46656)

답변

Math.random 은 이런 종류의 일에 좋지 않습니다.

옵션 1

서버 쪽 을 수행 할 수 있다면 암호화 모듈을 사용하십시오.

var crypto = require("crypto");
var id = crypto.randomBytes(20).toString('hex');

// "bb5dc8842ca31d4603d6aa11448d1654"

결과 문자열은 생성하는 임의 바이트의 두 배입니다. 16 진으로 인코딩 된 각 바이트는 2 자입니다. 20 바이트는 16 진수 40 자입니다.


옵션 2

클라이언트 측 을 수행 해야하는 경우 uuid 모듈을 사용해보십시오-

var uuid = require("uuid");
var id = uuid.v4();

// "110ec58a-a0f2-4ac4-8393-c866d813b8d1"

옵션 3

클라이언트 측을 수행해야하고 이전 브라우저를 지원할 필요가없는 경우 종속성없이 수행 할 수 있습니다.

// dec2hex :: Integer -> String
// i.e. 0-255 -> '00'-'ff'
function dec2hex (dec) {
  return ('0' + dec.toString(16)).substr(-2)
}

// generateId :: Integer -> String
function generateId (len) {
  var arr = new Uint8Array((len || 40) / 2)
  window.crypto.getRandomValues(arr)
  return Array.from(arr, dec2hex).join('')
}

console.log(generateId())
// "82defcf324571e70b0521d79cce2bf3fffccd69"

console.log(generateId(20))
// "c1a050a4cd1556948d41"


자세한 내용은 crypto.getRandomValues

crypto.getRandomValues()방법을 사용하면 암호화 적으로 강력한 임의 값을 얻을 수 있습니다. 매개 변수로 제공된 배열은 난수 (암호화 의미에서 임의)로 채워집니다.

다음은 약간의 콘솔 예입니다.

> var arr = new Uint8Array(4) # make array of 4 bytes (values 0-255)
> arr
Uint8Array(4) [ 0, 0, 0, 0 ]

> window.crypto
Crypto { subtle: SubtleCrypto }

> window.crypto.getRandomValues()
TypeError: Crypto.getRandomValues requires at least 1 argument, but only 0 were passed

> window.crypto.getRandomValues(arr)
Uint8Array(4) [ 235, 229, 94, 228 ]

IE11 지원을 위해 다음을 사용할 수 있습니다.

(window.crypto || window.msCrypto).getRandomValues(arr)

브라우저 적용 범위는 https://caniuse.com/#feat=getrandomvalues를 참조 하십시오.


답변

짧고 쉽고 안정적 ​​임

여기에있는 최고 등급의 답변과 달리 정확히 5 개의 임의의 문자를 반환합니다.

Math.random().toString(36).substr(2, 5);


답변

다음은 doubletap의 우수 답변 개선 사항입니다 . 원본에는 다음과 같은 두 가지 단점이 있습니다.

첫째, 다른 사람들이 언급했듯이 짧은 문자열이나 빈 문자열 (임의의 숫자가 0 인 경우)을 생성 할 가능성이 적으므로 응용 프로그램이 중단 될 수 있습니다. 해결책은 다음과 같습니다.

(Math.random().toString(36)+'00000000000000000').slice(2, N+2)

둘째, 위의 원본과 솔루션은 문자열 크기 N을 16 자로 제한합니다. 다음은 N에 대해 크기가 N 인 문자열을 반환합니다 (그러나 N> 16을 사용하더라도 임의성이 증가하거나 충돌 가능성이 감소하지는 않습니다).

Array(N+1).join((Math.random().toString(36)+'00000000000000000').slice(2, 18)).slice(0, N)

설명:

  1. [0,1) 범위에서 0 (포함)과 1 (제외) 사이의 난수를 선택하십시오.
  2. 숫자를 밑이 36 인 문자열로 변환하십시오 (예 : 문자 0-9 및 az 사용).
  3. 0으로 채워진 패드 (첫 번째 문제 해결).
  4. 선행 ‘0’을 잘라냅니다. 접두사 및 추가 패딩 0.
  5. 빈 문자열을 구분 기호로 사용되는 임의의 짧은 임의 문자열로 결합하여 N 자 이상이되도록 문자열을 충분히 반복하십시오.
  6. 문자열에서 정확히 N자를 자릅니다.

추가 생각 :

  • 이 솔루션은 대문자를 사용하지 않지만, 거의 모든 경우 (말장난 의도가 없음)는 중요하지 않습니다.
  • 원래 답변에서 N = 16의 최대 문자열 길이는 Chrome에서 측정됩니다. Firefox의 경우 N = 11입니다. 그러나 설명 된 것처럼 두 번째 솔루션은 임의성을 추가하는 것이 아니라 요청 된 문자열 길이를 지원하는 것이므로 큰 차이가 없습니다.
  • 반환 된 모든 문자열은 적어도 Math.random ()에 의해 반환 된 결과가 균등하게 분배되는 한 반환 확률이 동일합니다 (어쨌든 암호 강도 난수가 아님).
  • 크기가 N 인 모든 가능한 문자열이 리턴되는 것은 아닙니다. 두 번째 솔루션에서는 이것이 분명합니다 (작은 문자열이 단순히 복제되기 때문에). 그러나 원래의 대답에서는 base-36으로 변환 할 때 마지막 몇 비트가 원래 임의 비트의 일부가 아닐 수 있기 때문에 이것은 사실입니다. 특히 Math.random (). toString (36)의 결과를 보면 마지막 문자가 고르게 분포되지 않은 것을 알 수 있습니다. 다시 말하지만, 거의 모든 경우에 중요하지 않지만 무작위 문자열의 끝이 아니라 처음부터 마지막 ​​문자열을 슬라이스하여 짧은 문자열 (예 : N = 1)이 영향을받지 않도록합니다.

최신 정보:

여기에 내가 생각해 낸 몇 가지 다른 기능 스타일 원 라이너가 있습니다. 그것들은 위의 해결책과 다릅니다.

  • 그들은 명백한 임의의 알파벳을 사용합니다 (보다 일반적이며 대문자와 소문자 모두를 요구 한 원래 질문에 적합 함).
  • 길이가 N 인 모든 문자열은 리턴 될 확률이 같습니다 (즉, 문자열에 반복이 포함되지 않음).
  • toString (36) 트릭이 아닌 맵 함수를 기반으로하므로보다 간단하고 이해하기 쉽습니다.

그래서, 당신이 선택한 알파벳이

var s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

그런 다음이 두 가지는 서로 동일하므로 더 직관적 인 것을 선택할 수 있습니다.

Array(N).join().split(',').map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('');

Array.apply(null, Array(N)).map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('');

편집하다:

내가 좋아하는 것 같다 qubyte마티 드 Milliano은 어떻게 든 놓친 후자의 유사 (명성!) 솔루션을 함께했다. 그들은 한 눈에 짧게 보이지 않기 때문에 누군가가 실제로 하나의 라이너를 원할 경우를 대비하여 여기에 남겨 두겠습니다. 🙂

또한 모든 솔루션에서 ‘new Array’를 ‘Array’로 바꾸어 몇 바이트를 더 줄였습니다.


답변

보다 컴팩트 한 솔루션 slice은보다 짧습니다 substring. 문자열의 끝에서 빼면 random함수에 의해 생성 된 부동 소수점 기호를 피할 수 있습니다.

Math.random().toString(36).slice(-5);

또는

(+new Date).toString(36).slice(-5);

업데이트 : 방법을 사용 btoa하는 또 다른 접근법이 추가되었습니다 .

btoa(Math.random()).slice(0, 5);
btoa(+new Date).slice(-7, -2);
btoa(+new Date).substr(-7, 5);

// Using Math.random and Base 36:
console.log(Math.random().toString(36).slice(-5));

// Using new Date and Base 36:
console.log((+new Date).toString(36).slice(-5));

// Using Math.random and Base 64 (btoa):
console.log(btoa(Math.random()).slice(0, 5));

// Using new Date and Base 64 (btoa):
console.log(btoa(+new Date).slice(-7, -2));
console.log(btoa(+new Date).substr(-7, 5));


답변

이런 식으로 작동해야합니다

function randomString(len, charSet) {
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var randomString = '';
    for (var i = 0; i < len; i++) {
        var randomPoz = Math.floor(Math.random() * charSet.length);
        randomString += charSet.substring(randomPoz,randomPoz+1);
    }
    return randomString;
}

기본 문자셋 [a-zA-Z0-9]로 전화하거나 직접 보내십시오.

var randomValue = randomString(5);

var randomValue = randomString(5, 'PICKCHARSFROMTHISSET');