How to parse out each Chinese character? - objective-c

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);
}

Related

Uppercase random characters in a NSString

I'm trying to figure out the best approach to a problem. I have an essentially random alphanumeric string that I'm generating on the fly:
NSString *string = #"e04325ca24cf20ac6bd6ebf73c376b20ac57192dad83b22602264e92dac076611b51142ae12d2d92022eb2c77f";
You can see that there are no special characters, just numbers and letters, and all the letters are lowercase. Changing all the letters in this string to uppercase is easy:
[string capitalizedString];
The hard part is that I want to capitalize random characters in this string, not all of them. For example, this could be the output on one execution:
E04325cA24CF20ac6bD6eBF73C376b20Ac57192DAD83b22602264e92daC076611b51142AE12D2D92022Eb2C77F
This could be the output on another, since it's random:
e04325ca24cf20aC6bd6eBF73C376B20Ac57192DAd83b22602264E92dAC076611B51142AE12D2d92022EB2c77f
In case it makes this easier, let's say I have two variables as well:
int charsToUppercase = 12;//hardcoded value for how many characters to uppercase here
int totalChars = 90;//total string length
In this instance it would mean that 12 random characters out of the 90 in this string would be uppercased. What I've figured out so far is that I can loop through each char in the string relatively easily:
NSUInteger len = [string length];
unichar buffer[len+1];
[string getCharacters:buffer range:NSMakeRange(0, len)];
NSLog(#"loop through each char");
for(int i = 0; i < len; i++) {
NSLog(#"%C", buffer[i]);
}
Still stuck with selecting random chars in this loop to uppercase, so not all are uppercased. I'm guessing a condition in the for loop could do the trick well, given that it's random enough.
Here's one way, not particularly concerned with efficiency, but not silly efficiency-wise either: create an array characters in the original string, building an index of which ones are letters along the way...
NSString *string = #"e04325ca24cf20ac6bd6ebf73c376b20ac57192dad83b22602264e92dac076611b51142ae12d2d92022eb2c77f";
NSMutableArray *chars = [#[] mutableCopy];
NSMutableArray *letterIndexes = [#[] mutableCopy];
for (int i=0; i<string.length; i++) {
unichar ch = [string characterAtIndex:i];
// add each char as a string to a chars collection
[chars addObject:[NSString stringWithFormat:#"%c", ch]];
// record the index of letters
if ([[NSCharacterSet letterCharacterSet] characterIsMember:ch]) {
[letterIndexes addObject:#(i)];
}
}
Now, select randomly from the letterIndexes (removing them as we go) to determine which letters shall be upper case. Convert the member of the chars array at that index to uppercase...
int charsToUppercase = 12;
for (int i=0; i<charsToUppercase && letterIndexes.count; i++) {
NSInteger randomLetterIndex = arc4random_uniform((u_int32_t)(letterIndexes.count));
NSInteger indexToUpdate = [letterIndexes[randomLetterIndex] intValue];
[letterIndexes removeObjectAtIndex:randomLetterIndex];
[chars replaceObjectAtIndex:indexToUpdate withObject:[chars[indexToUpdate] uppercaseString]];
}
Notice the && check on letterIndexes.count. This guards against the condition where charsToUppercase exceeds the number of chars. The upper bound of conversions to uppercase is all of the letters in the original string.
Now all that's left is to join the chars array into a string...
NSString *result = [chars componentsJoinedByString:#""];
NSLog(#"%#", result);
EDIT Looking discussion in OP comments, you could, instead of acharsToUppercase input parameter, be given a probability of uppercase change as an input. That would compress this idea into a single loop with a little less data transformation...
NSString *string = #"e04325ca24cf20ac6bd6ebf73c376b20ac57192dad83b22602264e92dac076611b51142ae12d2d92022eb2c77f";
float upperCaseProbability = 0.5;
NSMutableString *result = [#"" mutableCopy];
for (int i=0; i<string.length; i++) {
NSString *chString = [string substringWithRange:NSMakeRange(i, 1)];
BOOL toUppercase = arc4random_uniform(1000) / 1000.0 < upperCaseProbability;
if (toUppercase) {
chString = [chString uppercaseString];
}
[result appendString:chString];
}
NSLog(#"%#", result);
However this assumes a given uppercase probability for any character, not any letter, so it won't result in a predetermined number of letters changing case.

divide string into characters

I have an NSString *titleName which changes according to an if statement. So the length (number of characters) in the string changes. I would like to divide titleName into a MutableArray of separate strings consisting of its individual characters. I would then like to use these separate strings as the text in different UILabels. I am not sure as how to go about this.
Through some research I have tried to create the NSMutable array like this
NSMutableArray *letterArray = substringWithRange:((i = 0);i<[titleName2 length];i++));
but this gives me an error Use of undeclared identifier 'substringWithRange.
Can someone help me.
I decided to use componentsSeparatedByString instead and just created my various strings with a , between each letter. Thanks for anybody's thoughts though.
The code you pasted is not valid objective-C.
To keep the same algorithm you should write something like :
NSMutableArray *letterArray = [NSMutableArray array];
NSUInteger length = [titleName2 length];
for (NSUInteger i = 0; i < length; ++i) {
[letterArray addObject:[titleName2 substringWithRange:NSMakeRange(i, 1)]];
}
It's probably much "cheaper" to hold a C-array of unichar characters that make-up the string. It will also be quicker to create:
NSString *input = #"How now brown cow?";
unichar chars[[input length]];
for (NSInteger i = 0; i < [input length]; i++)
chars[i] = [input characterAtIndex:i];
Alternatively you could use malloc() to create the C-array:
NSString *input = #"How now brown cow?";
unichar *chars = (unichar *)malloc([input length]);
for (NSInteger i = 0; i < [input length]; i++)
chars[i] = [input characterAtIndex:i];
and then use free(), later, to, err, free the memory:
free(chars);
Cheaper still, would be to not split-up the string at all...
Try this below code
NSMutableArray *letterArray = [NSMutableArray array];
for (int i = 0;i<[titleName2 length];i++)
{
[letterArray addObject: [titleName2 substringWithRange:NSMakeRange(i,1)]];
}
DLog(#"%#", letterArray);
Other option to get characters of string
NSMutableArray *letterArray = [NSMutableArray array];
for (int i=0; i < [titleName2 length]; i++)
{
[letterArray addObject:[NSString stringWithFormat:#"%c", [titleName2 characterAtIndex:i]]];
}
DLog(#"characters - %#", letterArray);

Best way to split integers in Objective C

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);
}

How do I iterate through an NSString in objective c?

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;
}

Convert NSString to C string, increment and come back to NSString

I'm trying to develop a simple application where i can encrypt a message. The algorithm is Caesar's algorithm and for example, for 'Hello World' it prints 'KHOOR ZRUOG' if the increment is 3 (standard).
My problem is how to take each single character and increment it...
I've tried this:
NSString *text = #"hello";
int q, increment = 3;
NSString *string;
for (q = 0; q < [text length]; q++) {
string = [text substringWithRange:NSMakeRange(q, 1)];
const char *c = [string UTF8String] + increment;
NSLog(#"%#", [NSString stringWithUTF8String:c]);
}
very simple but it doesn't work.. My theory was: take each single character, transform into c string and increment it, then return to NSString and print it, but xcode print nothing, also if i print the char 'c' i can't see the result in console. Where is the problem?
First of all, incrementing byte by byte only works for ASCII strings. If you use UTF-8, you will get garbage for glyphs that have multi-byte representations.
With that in mind, this should work (and work faster than characterAtIndex: and similar methods):
NSString *foo = #"FOOBAR";
int increment = 3;
NSUInteger bufferSize = [foo length] + 1;
char *buffer = (char *)calloc(bufferSize, sizeof(char));
if ([foo getCString:buffer maxLength:bufferSize encoding:NSASCIIStringEncoding]) {
int bufferLen = strlen(buffer);
for (int i = 0; i < bufferLen; i++) {
buffer[i] += increment;
if (buffer[i] > 'Z') {
buffer[i] -= 26;
}
}
NSString *encoded = [NSString stringWithCString:buffer
encoding:NSASCIIStringEncoding];
}
free(buffer);
first of all replace your code with this:
for (q = 0; q < [text length]; q++) {
string = [text substringWithRange:NSMakeRange(q, 1)];
const char *c = [string UTF8String];
NSLog(#"Addr: 0x%X", c);
c = c + increment;
NSLog(#"Addr: 0x%X", c);
NSLog(#"%#", [NSString stringWithUTF8String:c]);
}
Now you can figure out your problem. const char *c is a pointer. A pointer saves a memory address.
When I run this code the first log output is this:
Addr: 0x711DD10
that means the char 'h' from the NSString named string with the value #"h" is saved at address 0x711DD10 in memory.
Now we increment this address by 3. Next output is this:
Addr: 0x711DD13
In my case at this address there is a '0x00'. But it doesn't matter what is actually there because a 'k' won't be there (unless you are very lucky).
If you are happy there is a 0x00 too. Because then nothing bad will happen. If you are unlucky there is something else. If there is something other than 0x00 (or the string delimiter or "end of string") NSString will try to convert it. It might crash while trying this, or it might open a huge security hole.
so instead of manipulating pointers you have to manipulate the values where they point to.
You can do this like this:
for (q = 0; q < [text length]; q++) {
string = [text substringWithRange:NSMakeRange(q, 1)];
const char *c = [string UTF8String]; // get the pointer
char character = *c; // get the character from this pointer address
character = character + 3; // add 3 to the letter
char cString[2] = {0, 0}; // create a cstring with length of 1. The second char is \0, the delimiter (the "end marker") of the string
cString[0] = character; // assign our changed character to the first character of the cstring
NSLog(#"%#", [NSString stringWithUTF8String:cString]); // profit...
}