i'm java programmer that 'must' move on to obj-C for a while,
i got some confuse when generating random alphanumeric code... here my javacode:
PS: i want to generate code like this :Gh12PU67, AC88pP13, Bk81gH89
private String generateCode(){
String code = "";
Random r = new Random();
char[] c = new char[]{'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'};
for(int i = 0; i<4; i++){
int uplow = r.nextInt(2);
String temp = ""+ c[r.nextInt(c.length)];
if(uplow==1)
code = code + temp.toUpperCase();
else
code = code + temp;
if((i+1)%2==0){
code += r.nextInt(10);
code += r.nextInt(10);
}
}
return code;
}
then i create on OBJ-C
-(void)generateCode{
NSString *alphabet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:4];
for (NSUInteger i = 0U; i < 4; i++) {
u_int32_t r = arc4random() % [alphabet length];
unichar c = [alphabet characterAtIndex:r];
[s appendFormat:#"%C", c];
}
NSLog(#"s-->%#",s);
}
but i got "HpNz" for result AC88pP13 insted that hve pattern String,string, numeric,numeric, lowescase string,numeric,numeric...
that case screw my life for 3 days...
Your Objective-C code looks good, but (as #Wain correctly said in a comment above),
the Java function function contains logic to insert 2 digits after 2 letters, which you
have not replicated in the Objective-C method.
I would make that logic slightly less obscure and write it as
- (void)generateCode
{
static NSString *letters = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY";
static NSString *digits = #"0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:8];
for (NSUInteger i = 0; i < 2; i++) {
uint32_t r;
// Append 2 random letters:
r = arc4random_uniform((uint32_t)[letters length]);
[s appendFormat:#"%C", [letters characterAtIndex:r]];
r = arc4random_uniform((uint32_t)[letters length]);
[s appendFormat:#"%C", [letters characterAtIndex:r]];
// Append 2 random digits:
r = arc4random_uniform((uint32_t)[digits length]);
[s appendFormat:#"%C", [digits characterAtIndex:r]];
r = arc4random_uniform((uint32_t)[digits length]);
[s appendFormat:#"%C", [digits characterAtIndex:r]];
}
NSLog(#"s-->%#",s);
}
Remark (from the man page):
arc4random_uniform(length) is preferred over arc4random() % length,
as it avoids "modulo bias" when the upper bound is not a power of two.
Remark: A more verbatim translation of the Java code code += r.nextInt(10);
to Objective-C would be
r = arc4random_uniform(10);
[s appendString:[#(r) stringValue]];
which creates a NSNumber object #(r) from the random number, and then
converts that to a string.
if you want a secure random string you should use this code:
#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) { // A to Z
[result appendString:s];
continue;
}
if (currentChar > ASCII_START_LETTERS_a && currentChar < ASCII_END_LETTERS_z) { // a to z
[result appendString:s];
continue;
}
}
return result;
}
Related
i have an NSString with hex value
NSString* someString = #"AAB827EB5A6E225CAA
i want to extract from b (the second char) to 2 (-5 char)
make an addition of all extracted char and i have to find the 5C as result (-4 and -3 char)
i have tried this :
NSMutableArray *hex = [[NSMutableArray alloc]init];
unichar firstChar = [[someString uppercaseString] characterAtIndex:0];
unichar seconChar = [[someString uppercaseString] characterAtIndex:1];
unichar lastChar = [[someString uppercaseString] characterAtIndex:[print length]-1];
unichar beforeLastChar = [[someString uppercaseString] characterAtIndex:[print length]-2];
if (firstChar == 'A' && seconChar == 'A' && lastChar =='A' && beforeLastChar=='A') {
for (int i=2;i< [print length]-4; i++) {
NSString *decim =[NSString stringWithFormat:#"%hu",[someString characterAtIndex:i]];
[hex addObject:decim];
}
NSLog(#"hex : %#",hex);
}
but the log is
hex : (
98,
56,
50,
55,
101,
98,
53,
97,
54,
101,
50,
50, )
i've tried to covert it to string then int for calculation but if i can avoid conversion and continue with hex i would prefer
thanks for help
The code could be probably simplifed even more but one possibility:
NSString *someString = #"AAB827EB5A6E225CAA";
// I have improved a bit your check for prefix and suffix
if ([someString hasPrefix:#"AA"] && [someString hasSuffix:#"AA"]) {
NSMutableArray *hexNumbers = [[NSMutableArray alloc] init];
for (int i = 2; i < [someString length] - 4; i++) {
unichar digit = [someString characterAtIndex:i];
NSUInteger value;
// we have to convert the character into its numeric value
// we could also use NSScanner for it but this is a simple way
if (digit >= 'A') {
value = digit - 'A' + 10;
} else {
value = digit - '0';
}
// add the value to the array
[hexNumbers addObject:#(value)];
}
NSLog(#"hex : %#", hexNumbers);
// a trick to get the sum of an array
NSNumber *sum = [hexNumbers valueForKeyPath:#"#sum.self"];
// print the sum in decadic and in hexadecimal
NSLog(#"Sum: %#, in hexa: %X", sum, [sum integerValue]);
}
I'm trying to build up an NSMutableDictionary to be converted to be json'ed. One of my key-values are the bytes for a png representation of a picture. So I have something like
NSMutableDictionary *jsonDict = [[NSMutableDictionary alloc] init];
....
if ([self hasPhoto])
{
result[#"photo"] = UIImagePNGRepresentation(self.photo);
}
This later blows up, because NSJSONSerialization doesn't do things like NSData objects which is what UIImagePNGRepresenation returns. What is a good way to encode the data? Just UTF8'ing would likely be bad. I'm not that familiar with the guts of what are legal string representations in json.
Update:
I ended up finding this link about using Apple's builtin but unadvertised functions. The code was longer, but I was 2 files less:
NSData *data = UIImageJPEGRepresentation(self.photo, 0.5);
NSString *base64 = nil;
NSUInteger sourceLength = data.length;
NSUInteger encodeBufferLength = ((sourceLength + 2) / 3) * 4 + 1;
char *encodeBuffer = malloc(encodeBufferLength);
int encodedRealLength = b64_ntop(data.bytes, sourceLength, encodeBuffer, encodeBufferLength);
if (encodedRealLength >= 0)
{
base64 = [[NSString alloc] initWithBytesNoCopy: encodeBuffer length: encodedRealLength + 1 encoding: NSASCIIStringEncoding freeWhenDone: YES];
}
else
{
free(encodeBuffer);
}
result[#"photo-jpeg"] = base64;
This also runs about 7X faster than the Base64 solution below. Not that speed mattered AT ALL in this particular case, but someone asked.
You need to convert your image to base64 string .So that you can pass transmit using JSON. Here is the link to download base64 class files.
Then initialize this in your view controller.m:
[Base64 initialize];
After that convert your image to NSData and use this code:
NSString *strEncoded = [Base64 encode:webDat];
where webdat is an NSData.
Typically, images are encoded as a base64 string for JSON. There is no built-in way to encode NSData to a base64 string, but the algorithm to do so is fairly well known. Create an NSData category like so:
static char encodingTable[64] = {
'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','0','1','2','3','4','5','6','7','8','9','+','/' };
#implementation NSData (Base64)
- (NSString *) base64EncodingWithLineLength:(unsigned int) lineLength {
const unsigned char *bytes = [self bytes];
NSMutableString *result = [NSMutableString stringWithCapacity:[self length]];
unsigned long ixtext = 0;
unsigned long lentext = [self length];
long ctremaining = 0;
unsigned char inbuf[3], outbuf[4];
short i = 0;
short charsonline = 0, ctcopy = 0;
unsigned long ix = 0;
while( YES ) {
ctremaining = lentext - ixtext;
if( ctremaining <= 0 ) break;
for( i = 0; i < 3; i++ ) {
ix = ixtext + i;
if( ix < lentext ) inbuf[i] = bytes[ix];
else inbuf [i] = 0;
}
outbuf [0] = (inbuf [0] & 0xFC) >> 2;
outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
outbuf [3] = inbuf [2] & 0x3F;
ctcopy = 4;
switch( ctremaining ) {
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for( i = 0; i < ctcopy; i++ )
[result appendFormat:#"%c", encodingTable[outbuf[i]]];
for( i = ctcopy; i < 4; i++ )
[result appendFormat:#"%c",'='];
ixtext += 3;
charsonline += 4;
if( lineLength > 0 ) {
if (charsonline >= lineLength) {
charsonline = 0;
[result appendString:#"\n"];
}
}
}
return result;
}
#end
Encoding for JSON then becomes trivial:
NSData *imageData = UIImagePNGRepresentation(self.photo);
NSString *base64String = [imageData base64EncodingWithLineLength:0];
result[#"photo] = base64String;
Note that images taken with iOS devices are quite large. The number of bytes you are transmitting is equal to the width x height x 3. For example an iPhone 5 has an 8MP camera, that is 3264 x 2448 x 3 = 23MB of data. You almost never want to transmit that much data via JSON. So, you'll want to crop the photo or resize it down to something more manageable before sending.
I spent much too much time trying to find an implementation for base 62 conversion for Objective-C. I am sure this is a terrible example and there must be an elegant, super-efficient way to do this, but this works, please edit or answer to improve it! But I wanted to help people searching for this to have something that will work. There doesn't appear to be anything specific to be found for an Objective-C implementation.
#implementation Base62Converter
+(int)decode:(NSString*)string
{
int num = 0;
NSString * alphabet = #"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0, len = [string length]; i < len; i++)
{
NSRange range = [alphabet rangeOfString:[string substringWithRange:NSMakeRange(i,1)]];
num = num * 62 + range.location;
}
return num;
}
+(NSString*)encode:(int)num
{
NSString * alphabet = #"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
NSMutableString * precursor = [NSMutableString stringWithCapacity:3];
while (num > 0)
{
[precursor appendString:[alphabet substringWithRange:NSMakeRange( num % 62, 1 )]];
num /= 62;
}
// http://stackoverflow.com/questions/6720191/reverse-nsstring-text
NSMutableString *reversedString = [NSMutableString stringWithCapacity:[precursor length]];
[precursor enumerateSubstringsInRange:NSMakeRange(0,[precursor length])
options:(NSStringEnumerationReverse |NSStringEnumerationByComposedCharacterSequences)
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[reversedString appendString:substring];
}];
return reversedString;
}
#end
Your code is fine. If anything, make it more generic. Here is a recursive version for any base (same code):
#import <Foundation/Foundation.h>
#interface BaseConversion : NSObject
+(NSString*) formatNumber:(NSUInteger)n toBase:(NSUInteger)base;
+(NSString*) formatNumber:(NSUInteger)n usingAlphabet:(NSString*)alphabet;
#end
#implementation BaseConversion
// Uses the alphabet length as base.
+(NSString*) formatNumber:(NSUInteger)n usingAlphabet:(NSString*)alphabet
{
NSUInteger base = [alphabet length];
if (n<base){
// direct conversion
NSRange range = NSMakeRange(n, 1);
return [alphabet substringWithRange:range];
} else {
return [NSString stringWithFormat:#"%#%#",
// Get the number minus the last digit and do a recursive call.
// Note that division between integer drops the decimals, eg: 769/10 = 76
[self formatNumber:n/base usingAlphabet:alphabet],
// Get the last digit and perform direct conversion with the result.
[alphabet substringWithRange:NSMakeRange(n%base, 1)]];
}
}
+(NSString*) formatNumber:(NSUInteger)n toBase:(NSUInteger)base
{
NSString *alphabet = #"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 62 digits
NSAssert([alphabet length]>=base,#"Not enough characters. Use base %ld or lower.",(unsigned long)[alphabet length]);
return [self formatNumber:n usingAlphabet:[alphabet substringWithRange:NSMakeRange (0, base)]];
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSLog(#"%#",[BaseConversion formatNumber:3735928559 toBase:16]); // deadbeef
return EXIT_SUCCESS;
}
}
A Swift 3 version: https://gist.github.com/j4n0/056475333d0ddfe963ac5dc44fa53bf2
You could improve your encode method in such a way that reversing the final string is not necessary:
+ (NSString *)encode:(NSUInteger)num
{
NSString *alphabet = #"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSUInteger base = [alphabet length];
NSMutableString *result = [NSMutableString string];
while (num > 0) {
NSString *digit = [alphabet substringWithRange:NSMakeRange(num % base, 1)];
[result insertString:digit atIndex:0];
num /= base;
}
return result;
}
Of course, this could also be generalized for arbitrary bases or alphabets, as suggested by #Jano in his answer.
Note that this method (as well as your original encode method) returns an empty string for num = 0, so you might want to consider this case separately (or just replace while (num > 0) { ... } by do { ... } while (num > 0).
For more efficiency, one could avoid all intermediate NSString objects altogether, and work with plain C strings:
+ (NSString *)encode:(NSUInteger)num
{
static const char *alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSUInteger base = 62;
char result[20]; // sufficient room to encode 2^64 in Base-62
char *p = result + sizeof(result);
*--p = 0; // NULL termination
while (num > 0) {
*--p = alphabet[num % base];
num /= base;
}
return [NSString stringWithUTF8String:p];
}
I need to parse an NSString to a byte array and am having some trouble doing it. I have a padded byte array in a method and convert that into a mutablestring, then I have a method that needs to place those numbers back into a byte array.
In C# it would be as simple as:
do
{
val = byte.Parse(str.Substring(i, 3));
byteArr[j++] = val;
i += 3;
}
Here is the code snippit Note** Ive been trying a lot of different things in the do loop so its a mess in there right now:
-(NSData*) StrToByteArray: (NSString*)str
{
NSLog(#"StrToByteArray. String: %#", str);
if([str length]==0)
NSLog(#"Invailid String");
int val;
Byte byteArr[[str length]/3];
int i = 0;
int j = 0;
NSRange range;
do {
range = NSMakeRange(i, 3);
val = (int)[str substringFromIndex:i];
NSLog(#"StrToByteArray. VAR: %i", val);
byteArr[j++] = val;
NSLog(#"byteArr: %i",byteArr[i]);
i+=3;
}while(i<str.length);
NSData* wrappedByteArr = [NSData dataWithBytes:&byteArr length: sizeof(byteArr)];
return wrappedByteArr;
}
Here is the loop that makes the padded string:
for(int i = 0; i<=len;i++)
{
val = byteArr[i];
NSLog(#"byteArr to string original: %i", val);
if(val<(Byte)10)
{
[tempStr appendString:(#"00")];
[tempStr appendString:[NSString stringWithFormat:#"%d",val]];
}
else if(val<(Byte)100)
{
[tempStr appendString:(#"0")];
[tempStr appendString:[NSString stringWithFormat:#"%d",val]];
}
else {
[tempStr appendString:[NSString stringWithFormat:#"%d",val]];
}
}
NSLog(#"string: %#", tempStr);
return tempStr;
Take 2
Now that I know what the data looks like and how you want to parse it, I would approach it like this:
- (NSData *) parseStringToData:(NSString *) str
{
if ([str length] % 3 != 0)
{
// raise an exception, because the string's length should be a multiple of 3.
}
NSMutableData *result = [NSMutableData dataWithLength:[str length] / 3];
unsigned char *buffer = [result mutableBytes];
for (NSUInteger i = 0; i < [result length]; i++)
{
NSString *byteString = [str substringWithRange:NSMakeRange(i * 3, 3)];
buffer[i] = [byteString intValue];
}
return result;
}
Edit:
Your padding method could be simplified as well by providing the correct format specifier that automatically pads integers.
for(int i = 0; i<=len;i++)
{
val = byteArr[i];
NSLog(#"byteArr to string original: %i", val);
[tempStr appendFormat:#"%03d", val];
}
I have a random number generator method in iOS that I am currently using. While it is working fine, I would like to modify it such that in its output, it ALWAYS includes at least one number. How would I do this? Here is the random number method that I am using:
- (NSString *)generateRandString {
NSString *alphabet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:5];
for (NSUInteger i = 0U; i < 5; i++) {
u_int32_t r = arc4random() % [alphabet length];
unichar c = [alphabet characterAtIndex:r];
[s appendFormat:#"%C", c];
}
return s;
}
Thanks in advance to all who reply.
This is my edited and checked solution:
- (NSString *)generateRandString {
NSString *alphabet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s;
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
do
{
s = [NSMutableString stringWithCapacity:5];
for (NSUInteger i = 0U; i < 5; i++)
{
u_int32_t r = arc4random() % [alphabet length];
unichar c = [alphabet characterAtIndex:r];
[s appendFormat:#"%C", c];
}
}
while ([s rangeOfCharacterFromSet:set].location == NSNotFound);
return s;
}
I've also implemented the solution suggested by Dan Dyer (and it's obviously better than mine). My implementation is probably not perfect ( i use the same functionality few times instead of creating a separate function for it, but i believe it's not difficult to implement for you) but it works exactly as Dan has proposed.
NSString *alphabet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s = [NSMutableString string];
NSCharacterSet *set = [NSCharacterSet decimalDigitCharacterSet];
NSString *digits = #"0123456789";
for (NSUInteger i = 0U; i < 4; i++)
{
u_int32_t r = arc4random() % [alphabet length];
unichar c = [alphabet characterAtIndex:r];
[s appendFormat:#"%C", c];
}
if ([s rangeOfCharacterFromSet:set].location == NSNotFound)
{
u_int32_t r = arc4random() % [digits length];
unichar c = [digits characterAtIndex:r];
[s appendFormat:#"%C", c];
}
else
{
u_int32_t r = arc4random() % [alphabet length];
unichar c = [alphabet characterAtIndex:r];
[s insertString:[NSString stringWithFormat:#"%C", c] atIndex:arc4random() % s.length];
}
Rather than generating the whole string and then rejecting it if it doesn't contain any digits, which could take many iterations before it generates a valid string (there is a 41.5% chance that any 5-character string you generate won't contain a digit), a more efficient approach would be to keep track while generating the string.
If you want to generate a 5-character string, first generate 4 characters. If at least one of these is a digit you can generate the fifth character normally. If it's not, select only from the set of digits for the fifth character. If you want to avoid biasing the position of the numeric digits, you can insert this fifth character at a random position rather than tacking it on the end.