Gere uma seqüência alfanumérica aleatória no cacau

145

Quero chamar um método, passar o comprimento e gerar uma string alfanumérica aleatória.

Existem bibliotecas de utilidade por aí que podem ter um monte desses tipos de funções?

enfermaria
fonte

Respostas:

312

Aqui está uma implementação rápida e suja. Não foi testado.

NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

-(NSString *) randomStringWithLength: (int) len {

    NSMutableString *randomString = [NSMutableString stringWithCapacity: len];

    for (int i=0; i<len; i++) {
         [randomString appendFormat: @"%C", [letters characterAtIndex: arc4random_uniform([letters length])]];
    }

    return randomString;
}
Jeff B
fonte
1
genRandStringLength deve retornar apenas randomString. Não há razão para alocar e iniciar (e não autorelease!) Uma sequência totalmente nova.
Kevingessner
5
Só vou colocar isso lá fora. Não há razão para usar um NSStringpara lettersquando uma charmatriz simples funcionaria bem. De fato, o uso [letters characterAtIndex:(rand() % [letters length])]me parece menos conciso do que justo letters[rand() % strlen(letters)]. As classes da Foundation são realmente úteis, mas, para as coisas mais simples, elas podem servir para confundir nosso código em vez de aprimorá-lo.
Jonathan Sterling
3
você pode querer em %Cvez de %c, porque characterAtIndex:retorna aunichar
user102008 4/11/11
8
Usar arc4random geraria um resultado tendencioso quando o comprimento da matriz não fosse uma potência de dois. arc4random_uniform corrige isso.
Jlukanta # 21/13
9
oh o compilador daria um aviso para perder precisão, portanto, melhor elenco para intarc4random_uniform((int)[letters length])
knshn
103

Não é exatamente o que você pede, mas ainda é útil:

[[NSProcessInfo processInfo] globallyUniqueString]

Saída de amostra:

450FEA63-2286-4B49-8ACC-9822C7D4356B-1376-00000239A4AC4FD5
myeyesareblind
fonte
2
Esta é de longe a maneira mais curta e direta de abordar a questão.
adib
Mesmo que tenha hífens - se isso não for uma preocupação, então incrível!
Fatuhoku
Melhor resposta por uma milha
Rambatino
Perfeito para a minha necessidade de "gerar uma sequência alfanumérica aleatória no cacau". Não é exatamente o que o OP pede apenas porque ele adiciona o requisito de "ultrapassar o comprimento" que YAGNI!
Jkoreska #
5
Provavelmente, isso é bom para a maioria dos usos, mas NÃO USE se você precisar de uma sequência aleatória para fins de segurança. Único! = Aleatório. O comprimento é constante, o intervalo de caracteres usado é limitado (0-9, AF, - = 17, vs 62 para aZ. 0-9). Essa sequência é única, mas previsível.
AMCC
67
NSString *alphabet  = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:20];
for (NSUInteger i = 0U; i < 20; i++) {
    u_int32_t r = arc4random() % [alphabet length];
    unichar c = [alphabet characterAtIndex:r];
    [s appendFormat:@"%C", c];
}
Melvin
fonte
13
Você realmente precisa consultar a duração de alphabetcada vez? É constante e não depende do loop.
Jv42
1
Testado pela geração de senhas de 1 milhão de 10 caracteres cada e funciona muito bem.
NaXir
1
NSArrayarmazena em cache o seu length, não deve ser um gargalo de desempenho.
22615 Pascal
Concordo. É um acesso simples à propriedade. Não está contando a si mesma toda vez que você pergunta.
Devios1 31/03
45

Certamente você pode fazer isso mais curto:

+(NSString*)generateRandomString:(int)num {
    NSMutableString* string = [NSMutableString stringWithCapacity:num];
    for (int i = 0; i < num; i++) {
        [string appendFormat:@"%C", (unichar)('a' + arc4random_uniform(26))];
    }
    return string;
}
John Riselvato
fonte
2
por que o -1? Não há nada de errado nisso. É como a menor e mais otimizada de todas as respostas.
John Riselvato
5
Nada de errado com este. É uma solução agradável e concisa. (Eu desejo que isso seria impor um comentário sobre downvotes.)
alvi
Melhor solução. O único comentário, eu faria método estático.
Andrei Tchijov
9
A única desvantagem é que não é realmente alfanumérico, mas apenas letras minúsculas. ;-)
PrimaryFeather
Eu acho que você precisa mudar de 25 para 26, caso contrário você nunca terá 'z'.
Marcus Adams
28

Se você deseja limitar-se apenas a caracteres hexadecimais, a opção mais simples é gerar um UUID:

NSString *uuid = [NSUUID UUID].UUIDString;

Exemplo de saída: 16E3DF0B-87B3-4162-A1A1-E03DB2F59654.

Se você deseja uma sequência aleatória menor, pode pegar apenas os 8 primeiros caracteres.

É um UUID versão 4 que significa que o primeiro caractere no 3º e 4º grupo não é aleatório (eles estarão sempre 4e um dos 8, 9, Aou B).

Todos os outros caracteres da sequência são totalmente aleatórios e você pode gerar milhões de UUIDs a cada segundo por centenas de anos, sem muito risco de o mesmo UUID ser gerado duas vezes.

Abhi Beckert
fonte
1
Você pode simplesmente usarNSString *uuid = [UUID UUID]
orkoden
@orkoden obrigado, meu código era de algum código iOS 5. Atualizarei minha resposta para usar a API mais recente do iOS 6 / OS X 10.8.
Abhi Beckert 24/02
@AbhiBeckert é seguro usar apenas os 8 primeiros caracteres sem o risco de obter os mesmos 8 primeiros caracteres?
Vishal Singh
1
@VishalSingh sim, é seguro, embora, obviamente, quanto menor o tempo, maior o risco de colisões.
Abhi Beckert 28/05
3
NSString * uuid = [UUID UUID] .UUIDString; exibirá o erro "Uso do identificador não declarado UUID"; portanto, apenas uma pequena alteração no código usa NSString * uuid = [NSUUID UUID] .UUIDString;
Abbas Mulani 27/10/16
24

Uma versão de categoria da resposta de Jeff B.

NSString + Random.h

#import <Foundation/Foundation.h>

@interface NSString (Random)

+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length;

@end

NSString + Random.m

#import "NSString+Random.h"

 @implementation NSString (Random)

+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length
{ 
    NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    NSMutableString *randomString = [NSMutableString stringWithCapacity:length];

    for (int i = 0; i < length; i++) {
        [randomString appendFormat:@"%C", [letters characterAtIndex:arc4random() % [letters length]]];
    }

    return randomString;
}

@end
keithyip
fonte
1
Este é um ótimo exemplo de como usar categorias!
ElmerCat
7

Você também pode apenas gerar um UUID. Embora não sejam verdadeiramente aleatórios, eles são complexos e únicos, o que os faz parecer aleatórios para a maioria dos usos. Gere um como uma sequência e, em seguida, escolha um intervalo de caracteres igual ao comprimento passado.

TechZen
fonte
Eu recomendaria fortemente contra isso por qualquer coisa relacionada à segurança. A pseudo-aleatoriedade é uma das maiores recompensas que os hackers usam em sistemas penetrantes, porque fornecem previsibilidade. Use o mais próximo possível do real-aleatório.
Shayne
5

Rápido

func randomStringWithLength(length: Int) -> String {
    let alphabet = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    let upperBound = UInt32(count(alphabet))
    return String((0..<length).map { _ -> Character in
        return alphabet[advance(alphabet.startIndex, Int(arc4random_uniform(upperBound)))]
    })
}
ma11hew28
fonte
1
Curto e doce. Funcionou para mim, exceto quando alterei o alfabeto, ele travou porque o comprimento do alfabeto é codificado. Substituí o 64 pelo UInt32 (count (alphabet)) #
scootermg
ESTÁ BEM. Troquei o codificado 64por um computado upperBound. Eu computo upperBoundfora do bloco porque acho que tem um desempenho melhor.
ma11hew28
Não é possível invocar 'count' com uma lista de argumentos do tipo '(String)' alças usando 'alphabet.characters.count'
Zaporozhchenko Oleksandr
return alphabet [alphabet.startIndex.advancedBy (Int (arc4random_uniform (upperBound))))
Zaporozhchenko Oleksandr
4

Aqui está uma maneira diferente de lidar com isso. Em vez de usar uma sequência de caracteres preparada, você pode converter entre números inteiros e caracteres e gerar uma lista dinâmica de caracteres para selecionar. É bem enxuto e rápido, mas tem um pouco mais de código.

int charNumStart = (int) '0';
int charNumEnd = (int) '9';
int charCapitalStart = (int) 'A';
int charCapitalEnd = (int) 'Z';
int charLowerStart = (int) 'a';
int charLowerEnd = (int) 'z';

int amountOfChars = (charNumEnd - charNumStart) + (charCapitalEnd - charCapitalStart) + (charLowerEnd - charLowerStart); // amount of the characters we want.
int firstGap = charCapitalStart - charNumEnd; // there are gaps of random characters between numbers and uppercase letters, so this allows us to skip those.
int secondGap = charLowerStart - charCapitalEnd; // similar to above, but between uppercase and lowercase letters.

// START generates a log to show us which characters we are considering for our UID.
NSMutableString *chars = [NSMutableString stringWithCapacity:amountOfChars];
for (int i = charNumStart; i <= charLowerEnd; i++) {
    if ((i >= charNumStart && i <= charNumEnd) || (i >= charCapitalStart && i <= charCapitalEnd) || (i >= charLowerStart && i <= charLowerEnd)) {
        [chars appendFormat:@"\n%c", (char) i];
    }
}
NSLog(@"chars: %@", chars);
// END log

// Generate a uid of 20 characters that chooses from our desired range.
int uidLength = 20;
NSMutableString *uid = [NSMutableString stringWithCapacity:uidLength];
for (int i = 0; i < uidLength; i++) {
    // Generate a random number within our character range.
    int randomNum = arc4random() % amountOfChars;
    // Add the lowest value number to line this up with a desirable character.
    randomNum += charNumStart;
    // if the number is in the letter range, skip over the characters between the numbers and letters.
    if (randomNum > charNumEnd) {
        randomNum += firstGap;
    }
    // if the number is in the lowercase letter range, skip over the characters between the uppercase and lowercase letters.
    if (randomNum > charCapitalEnd) {
        randomNum += secondGap;
    }
    // append the chosen character.
    [uid appendFormat:@"%c", (char) randomNum];
}
NSLog(@"uid: %@", uid);

// Generate a UID that selects any kind of character, including a lot of punctuation. It's a bit easier to do it this way.
int amountOfAnyCharacters = charLowerEnd - charNumStart; // A new range of characters.
NSMutableString *multiCharUid = [NSMutableString stringWithCapacity:uidLength];
for (int i = 0; i < uidLength; i++) {
    // Generate a random number within our new character range.
    int randomNum = arc4random() % amountOfAnyCharacters;
    // Add the lowest value number to line this up with our range of characters.
    randomNum += charNumStart;
    // append the chosen character.
    [multiCharUid appendFormat:@"%c", (char) randomNum];
}
NSLog(@"multiCharUid: %@", multiCharUid);

Quando estou gerando caracteres aleatórios, prefiro trabalhar diretamente com números inteiros e convertê-los em vez de escrever a lista de caracteres dos quais quero extrair. Declarar as variáveis ​​na parte superior o torna mais independente do sistema, mas esse código pressupõe que os números terão um valor menor que as letras e que as maiúsculas terão um valor menor que as minúsculas.

rjferguson
fonte
3

Solução alternativa em Swift

func generateString(len: Int) -> String {
    let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    let lettersLength = UInt32(countElements(letters))
    let result = (0..<len).map { _ -> String in
        let idx = Int(arc4random_uniform(lettersLength))
        return String(letters[advance(letters.startIndex, idx)])
    }
    return "".join(result)
}
Gralex
fonte
2

Adicionando uma boa resposta dada por Melvin, aqui está uma função que eu criei ( em SWIFT! ) Para obter uma sequência aleatória:

func randomStringOfLength(length:Int)->String{
    var wantedCharacters:NSString="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789"
    var s=NSMutableString(capacity: length)
    for (var i:Int = 0; i < length; i++) {
        let r:UInt32 = arc4random() % UInt32( wantedCharacters.length)
        let c:UniChar = wantedCharacters.characterAtIndex( Int(r) )
        s.appendFormat("%C", c)
    }
    return s
}

Aqui está um resultado de teste da chamada randomStringOfLength(10): uXa0igA8wm

Stan Tatarnykov
fonte
2

Gera uma sequência aleatória alfanumérica em minúscula com um determinado comprimento:

-(NSString*)randomStringWithLength:(NSUInteger)length
{
    NSMutableString* random = [NSMutableString stringWithCapacity:length];

    for (NSUInteger i=0; i<length; i++)
    {
        char c = '0' + (unichar)arc4random()%36;
        if(c > '9') c += ('a'-'9'-1);
        [random appendFormat:@"%c", c];
    }

    return random;
}
erkanyildiz
fonte
2

Modificação de algumas idéias aqui e pronto Swift 4.0

extension String
{
    subscript (i: Int) -> Character
    {
        return self[index(startIndex, offsetBy:i)]
    }

    static func Random(length:Int=32, alphabet:String="ABCDEF0123456789") -> String
    {
        let upperBound = UInt32(alphabet.count)
        return String((0..<length).map { _ -> Character in
            return alphabet[Int(arc4random_uniform(upperBound))]
        })
    }
}

Uso:

let myHexString = String.Random()
let myLongHexString = String.Random(length:64)
let myLettersString = String.Random(length:32, alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZ")
Wex
fonte
1

Se você deseja uma sequência unicode aleatória, pode criar bytes aleatórios e, em seguida, usar os válidos.

    OSStatus sanityCheck = noErr;
    uint8_t * randomBytes = NULL;
    size_t length = 200; // can of course be variable

    randomBytes = malloc( length * sizeof(uint8_t) );
    memset((void *)randomBytes, 0x0, length);

    sanityCheck = SecRandomCopyBytes(kSecRandomDefault, length, randomBytes);

    if (sanityCheck != noErr) NSLog(@"Error generating random bytes, OSStatus == %ld.", sanityCheck);

    NSData* randomData = [[NSData alloc] initWithBytes:(const void *)randomBytes length: length];
    if (randomBytes) free(randomBytes);

    NSString* dataString = [[NSString alloc] initWithCharacters:[randomData bytes] length:[randomData length]];  // create an NSString from the random bytes
    NSData* tempData = [dataString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];             // remove illegal characters from string
    NSString* randomString = [[NSString alloc] initWithData:tempData encoding:NSUTF8StringEncoding];

A conversão de NSString para NSData e de volta é necessária para obter uma sequência UTF-8 válida. Esteja ciente de que o comprimento não será necessariamente o comprimento do NSString criado no final.

orkoden
fonte
1

Eu fiz isso usando um simples em char[]vez de um NSString *para o alfabeto. Eu adicionei isso a uma categoria NSString.

static const char __alphabet[] =
    "0123456789"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz";
+ (NSString *)randomString:(int)length
{
    NSMutableString *randomString = [NSMutableString stringWithCapacity:length];
    u_int32_t alphabetLength = (u_int32_t)strlen(__alphabet);
    for (int i = 0; i < length; i++) {
        [randomString appendFormat:@"%c", __alphabet[arc4random_uniform(alphabetLength)]];
    }
    return randomString;
}
Mr. T
fonte
1
static NSUInteger length = 32;
static NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
NSMutableString * randomString = [NSMutableString stringWithCapacity:length];
for (NSInteger i = 0; i < length; ++i) {
    [randomString appendFormat: @"%C", [letters characterAtIndex:(NSUInteger)arc4random_uniform((u_int32_t)[letters length])]];
}
Peter Lapisu
fonte
1

Método para chamar:


NSString *string = [self stringWithRandomSuffixForFile:@"file.pdf" withLength:4]

Método:


- (NSString *)stringWithRandomSuffixForFile:(NSString *)file withLength:(int)length
{
    NSString *alphabet = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    NSString *fileExtension = [file pathExtension];
    NSString *fileName = [file stringByDeletingPathExtension];
    NSMutableString *randomString = [NSMutableString stringWithFormat:@"%@_", fileName];

    for (int x = 0; x < length; x++) {
        [randomString appendFormat:@"%C", [alphabet characterAtIndex: arc4random_uniform((int)[alphabet length]) % [alphabet length]]];
    }
    [randomString appendFormat:@".%@", fileExtension];

    NSLog(@"## randomString: %@ ##", randomString);
    return randomString;
}

Resultados:


## randomString: file_Msci.pdf ##
## randomString: file_xshG.pdf ##
## randomString: file_abAD.pdf ##
## randomString: file_HVwV.pdf ##
emotalidade
fonte
1

para Swift 3.0

func randomString(_ length: Int) -> String {

    let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    let len = UInt32(letters.length)

    var randomString = ""

    for _ in 0 ..< length {
        let rand = arc4random_uniform(len)
        var nextChar = letters.character(at: Int(rand))
        randomString += NSString(characters: &nextChar, length: 1) as String
    }

    return randomString
}
S1LENT WARRIOR
fonte
0
#define ASCII_START_NUMERS 0x30
#define ASCII_END_NUMERS 0x39
#define ASCII_START_LETTERS_A 0x41
#define ASCII_END_LETTERS_Z 0x5A
#define ASCII_START_LETTERS_a 0x61
#define ASCII_END_LETTERS_z 0x5A

-(NSString *)getRandomString:(int)length {
    NSMutableString *result = [[NSMutableString alloc]init];
    while (result.length != length) {
        NSMutableData* data = [NSMutableData dataWithLength:1];
        SecRandomCopyBytes(kSecRandomDefault, 1, [data mutableBytes]);
        Byte currentChar = 0;
        [data getBytes:&currentChar length:1];
        NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        if (currentChar > ASCII_START_NUMERS && currentChar < ASCII_END_NUMERS) { // 0 to 0
            [result appendString:s];
            continue;
        }
        if (currentChar > ASCII_START_LETTERS_A && currentChar < ASCII_END_LETTERS_Z) { // 0 to 0
            [result appendString:s];
            continue;
        }
        if (currentChar > ASCII_START_LETTERS_a && currentChar < ASCII_END_LETTERS_z) { // 0 to 0
            [result appendString:s];
            continue;
        }
    }
    return result;
}
TtheTank
fonte
0

Modificação da resposta de keithyip:

+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length
{
    static NSString * const letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        srand(time(NULL));
    });

    NSMutableString *randomString = [NSMutableString stringWithCapacity:length];

    for (int i = 0; i < length; i++) {
        [randomString appendFormat:@"%C", [letters characterAtIndex:arc4random() % [letters length]]];
    }

    return randomString;
}
iutinvg
fonte