In my program, I receive a NSString like this one : AA010158AA7D385002. And I need to pass it to a method which accept a char byte array, as below :
char[9] = {0xAA, 0x01, 0x01, 0x58, 0xAA, 0x7D, 0x38, 0x50, 0x02};
How to convert my NSString to char byte array like this one?
Thanks!
NSString *strCharData = #"AA010158AA7D385002";
const char *characterRes = [strCharData cStringUsingEncoding:NSUTF8StringEncoding];
or
NSString *strCharData = #"AA010158AA7D385002";
const char *characterRes = [strCharData UTF8String];
Use this answer if i am correct,i did little coding but might be there are possibilities of simpler solutions also like #user3182143
NSString * inputStr = #"AA010158AA7D385002";
NSMutableArray *charByteArray = [[NSMutableArray alloc]initWithCapacity:1];
int i = 0;
for (i = 0; i+2 <= inputStr.length; i+=2) {
NSRange range = NSMakeRange(i, 2);
NSString* charStr = [inputStr substringWithRange:range];
[charByteArray addObject:[NSString stringWithFormat:#"0x%#",charStr]];
}
Output :
char[9] = (
0xAA,
0x01,
0x01,
0x58,
0xAA,
0x7D,
0x38,
0x50,
0x02
)
Since your text is hex and you want actual bytes out (which each correspond to two hex characters), you'll have to manually convert each character into the corresponding number, and then add them together into the correct numerical value.
To do this, I'm taking advantage of the fact that, in ASCII characters, a...z are in a row, as are 0...9. I'm also taking advantage of the fact that hexadecimal is valid ASCII, and that Unicode characters from 0...127 are identical to their corresponding ASCII characters.
Below is a program that does this and prints out the original string's characters as well as the calculated bytes (as hex again):
#import <Foundation/Foundation.h>
int main(int argc, char *argv[])
{
#autoreleasepool
{
NSString *hexStr = #"1234567890abcdef12";
unsigned char theBytes[9] = {};
for( NSUInteger x = 0; x < sizeof(theBytes); x++ )
{
unsigned char digitOne = [hexStr characterAtIndex: x * 2];
if( digitOne >= 'a' )
digitOne -= 'a' -10;
else
digitOne -= '0';
unsigned char digitTwo = [hexStr characterAtIndex: (x * 2) +1];
if( digitTwo >= 'a' )
digitTwo -= 'a' -10;
else
digitTwo -= '0';
printf("%01x%01x",digitOne,digitTwo);
theBytes[x] = (digitOne << 4) | digitTwo;
}
printf("\n");
for( int x = 0; x < sizeof(theBytes); x++ )
printf("%02x",theBytes[x]);
printf("\n");
}
}
Note: This code naïvely assumes that you are providing a correct string. I.e. your input has to consist of lowercase characters and numbers only, and exactly 18 characters. Anything else and you get a wrong result or an exception.
I finally managed to find the answer to my own question. I am posting it here in case it helps someone else.
So I use a method to convert an NSString hex to bytes :
#implementation NSString (HexToBytes)
- (NSData *)hexToBytes
{
NSMutableData *data = [NSMutableData data];
int idx;
for (idx = 0; idx + 2 <= self.length; idx += 2) {
NSRange range = NSMakeRange(idx, 2);
NSString *hexStr = [self substringWithRange:range];
NSScanner *scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
#end
And then, I simply use it like that :
NSString *str = #"AA010158AA7D385002";
NSData *databytes = [str hexToBytes];
char *bytePtr = (char *)[databytes bytes];
And I finally get my char array. Hope it helps someone else.
If I have this:
int toSplit = 208;
What's the best way to split it so I get:
2
0
8
Method would be like this
- (NSMutableArray *) toCharArray : (NSString *) str
{
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[str length]];
for (int i=0; i < [str length]; i++)
{
NSString *ichar = [NSString stringWithFormat:#"%c", [str characterAtIndex:i]];
[characters addObject:ichar];
}
return characters;
}
do {
int digit = toSplit % 10;
toSplit /= 10;
printf(#"%i", digit);
} while (toSplit > 0);
I hope it's not a homework.
EDIT: it's backwards so it's not a valid answer... However, leaving it here because it can still be useful for others.
Sort it into a string then pull it apart. So like this:
int toSplit = 208;
NSString *string = [NSString stringWithFormat: #"%i", toSplit];
NSMutableString *splitApartString = [[NSMutableString alloc] init];
for (int i = 0; i < [string length]; i++) {
NSString *substring = [string substringFromIndex: i];
[splitApartString appendFormat: #"%#\n", substring];
}
NSLog(#"%#", splitApartString); //YAY!
So what this does, is puts this int into a string, splits it apart, then iterates through each character and gets a string out of that character. Then it appends that substring to a NEW string.
Another alternative, is instead of getting a substring just get the char and use the %c operator. Also if you take a look at this code you will see this output:
> 2
> 0
> 8
> // extra space here
You could just add a condition to check if i is the string length - 1 and not add a space or you could just remove the last character!
I'm not familiar with Objective-C syntax, but something like:
void split(int toSplit)
{
if (!toSplit)
{
return;
}
split(toSplit / 10);
int digit = toSplit % 10;
printf(#"%i", digit);
}
Given a sentence composing of X number of Chinese characters. I want to parse each character out in Objective-C or C++.
I tried:
NSString * nsText = [NSString stringWithFormat:#"你好吗"];
for (int i = 0; i < [nsText length]; i++)
{
char current = [nsText characterAtIndex:i];
printf("%i: %c\n", i, current);
}
But I'm not getting the right characters, I got index 0 = ', index 1 = }, etc. The length is returned correctly, which equals 3. I need UTF8 encoding to display it to the UI.
Any tips will be helpful.
Thank you
Three things wrong. First, characterAtIndex: returns a unichar, which is bigger than the char to which you're assigning. You're losing information there. Second, %c is the format specifier for printing an ASCII value (8 bits). You want %C (uppercase 'C') to print a 16-bit unichar. Finally, printf() doesn't seem to accept %C, so you need to use NSLog() instead. Rewritten, then, we have:
NSString * nsText = [NSString stringWithFormat:#"你好吗"];
for (int i = 0; i < [nsText length]; i++)
{
unichar current = [nsText characterAtIndex:i];
NSLog(#"%i: %C\n", i, current);
}
Can this solve your problem?
NSString * nsText = [NSString stringWithFormat:#"你好吗"];
for (int i = 0; i < [nsText length]; i++) {
NSString *str = [nsText substringToIndex:i+1];
NSString *str2 =[str substringFromIndex:i];
NSLog(#"%#",str2);
}
How can iterate through an NSString object in Objective c whiling maintaining an index for the character I am currently at?
I want to increment the ASCII value of every third character by 3, and then print this incremented character in a label in my user interface.
Wasn't clear whether you just wanted to print the incremented characters or all. If the former, here's is how you would do it:
NSString *myString = #"myString";
NSMutableString *newString = [NSMutableString string];
for (int i = 0; i < [myString length]; i++)
{
int ascii = [myString characterAtIndex:i];
if (i % 3 == 0)
{
ascii++;
[newString appendFormat:#"%c",ascii];
}
}
myLabel.text = newString;
Will this do the trick?
NSString *incrementString(NSString *input)
{
const char *inputUTF8 = [input UTF8String]; // notice we get the buffers so that we don't have to deal with the overhead of making many message calls.
char *outputUTF8 = calloc(input.length + 1, sizeof(*outputUTF8));
for (int i = 0; i < input.length; i++)
{
outputUTF8[i] = i % 3 == 0 ? inputUTF8[i] + 3 : inputUTF8[i];
}
NSString *ret = [NSString stringWithUTF8String:outputUTF8];
free(outputUTF8); // remember to free the buffer when done!
return ret;
}
I want to call a method, pass it the length and have it generate a random alphanumeric string.
Are there any utility libraries out there that may have a bunch of these types of functions?
Here's a quick and dirty implementation. Hasn't been tested.
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;
}
Not exactly what you ask, but still useful:
[[NSProcessInfo processInfo] globallyUniqueString]
Sample output:
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];
}
Surely you can make this shorter:
+(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;
}
If you're willing to limit yourself to hex characters only, then the simplest option is to generate a UUID:
NSString *uuid = [NSUUID UUID].UUIDString;
Example output: 16E3DF0B-87B3-4162-A1A1-E03DB2F59654.
If you want a smaller random string then you can grab just the first 8 characters.
It's a version 4 UUID which means the first character in the 3rd and 4th group is not random (they will always be 4 and one of 8, 9, A or B).
Every other character in the string is fully random and you can generate millions of UUIDs every second for hundreds of years without much risk of the same UUID being generated twice.
A category version of Jeff B's answer.
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
You could also just generate a UUID. While not truly random, they are complex and unique which makes them appear random for most uses. Generate one as a string and then take a range of characters equal to the passed length.
Swift
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)))]
})
}
Here's a different way to tackle it. Instead of using a prepared string of characters, you can cast between integers and characters, and generate a dynamic list of characters to select. It's pretty lean and fast, but has a bit more code.
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);
When I'm doing random character generation, I prefer to work directly with integers and cast them over, instead of writing out the list of chars that I want to draw from. Declaring the variables at the top makes it more system independent, but this code assumes that numbers will have a lower value than letters, and that uppercase letters will have a lower value than lowercase letters.
Alternative solution in 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)
}
Modification of a few ideas here, and in done 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))]
})
}
}
Usage:
let myHexString = String.Random()
let myLongHexString = String.Random(length:64)
let myLettersString = String.Random(length:32, alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZ")
If you want a random unicode string, you can create random bytes and then use the valid ones.
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];
The conversion from NSString to NSData and back is necessary to get a valid UTF-8 string.
Be aware that length will not necessarily be the length of the the NSString created in the end.
I did this using a simple char[] instead of an NSString * for the alphabet. I added this to a NSString category.
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;
}
Adding to good answer given by Melvin, here is a function I made (in SWIFT!) to get a random string:
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
}
Here is a test result from calling randomStringOfLength(10): uXa0igA8wm
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])]];
}
Generates lowercase alphanumeric random string with given length:
-(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;
}
Method to call:
NSString *string = [self stringWithRandomSuffixForFile:#"file.pdf" withLength:4]
Method:
- (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;
}
Results:
## randomString: file_Msci.pdf ##
## randomString: file_xshG.pdf ##
## randomString: file_abAD.pdf ##
## randomString: file_HVwV.pdf ##
for 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;
}
Modification for keithyip's answer:
+ (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;
}