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?
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?
Respostas:
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;
}
NSString
para letters
quando uma char
matriz 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.
%C
vez de %c
, porque characterAtIndex:
retorna aunichar
arc4random_uniform((int)[letters length])
Não é exatamente o que você pede, mas ainda é útil:
[[NSProcessInfo processInfo] globallyUniqueString]
Saída de amostra:
450FEA63-2286-4B49-8ACC-9822C7D4356B-1376-00000239A4AC4FD5
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];
}
alphabet
cada vez? É constante e não depende do loop.
NSArray
armazena em cache o seu length
, não deve ser um gargalo de desempenho.
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;
}
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 4
e um dos 8
, 9
, A
ou 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.
NSString *uuid = [UUID UUID]
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
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.
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)))]
})
}
64
por um computado upperBound
. Eu computo upperBound
fora do bloco porque acho que tem um desempenho melhor.
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.
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)
}
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
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;
}
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")
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.
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;
}
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])]];
}
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 ##
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
}
#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:¤tChar 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;
}
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;
}