How to reverse letter capitalization in an NSString (Objective-C) - objective-c

I was wondering how I would go about reversing the capitalization of the characters in an NSString or NSMutableString, ignoring non-letter characters. For example, "HeLLO jIM66" would become "hEllo Jim66".
I know about uppercaseString, lowercaseString and capitalizedString but I haven't been able to figure out how to REVERSE the capitalization of ALL the letters in the string.
Thanks for your help!

Just iterate through all of the characters in the string. If a character is uppercase, replace it with a lowercase letter; if it's lowercase, replace it with an uppercase letter; otherwise, leave it alone. For example:
+ (NSString *) reverseCase:(NSString *)str
{
int length = [str length];
NSMutableString *result = [NSMutableString stringWithCapacity:length];
for (int i = 0; i < length; i++)
{
unichar ch = [str characterAtIndex:i];
if (islower(ch))
ch = toupper(ch);
else if (isupper(ch))
ch = tolower(ch);
[result appendString:[NSString stringWithCharacters:&ch length:1]];
}
return result;
}

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.

Check if NSString only contains one character repeated

I want to know a simple and fast way to determine if all characters in an NSString are the same.
For example:
NSString *string = "aaaaaaaaa"
=> return YES
NSString *string = "aaaaaaabb"
=> return NO
I know that I can achieve it by using a loop but my NSString is long so I prefer a shorter and simpler way.
you can use this, replace first character with null and check lenght:
-(BOOL)sameCharsInString:(NSString *)str{
if ([str length] == 0 ) return NO;
return [[str stringByReplacingOccurrencesOfString:[str substringToIndex:1] withString:#""] length] == 0 ? YES : NO;
}
Here are two possibilities that fail as quickly as possible and don't (explicitly) create copies of the original string, which should be advantageous since you said the string was large.
First, use NSScanner to repeatedly try to read the first character in the string. If the loop ends before the scanner has reached the end of the string, there are other characters present.
NSScanner * scanner = [NSScanner scannerWithString:s];
NSString * firstChar = [s substringWithRange:[s rangeOfComposedCharacterSequenceAtIndex:0]];
while( [scanner scanString:firstChar intoString:NULL] ) continue;
BOOL stringContainsOnlyOneCharacter = [scanner isAtEnd];
Regex is also a good tool for this problem, since "a character followed by any number of repetitions of that character" is in very simply expressed with a single back reference:
// Match one of any character at the start of the string,
// followed by any number of repetitions of that same character
// until the end of the string.
NSString * patt = #"^(.)\\1*$";
NSRegularExpression * regEx =
[NSRegularExpression regularExpressionWithPattern:patt
options:0
error:NULL];
NSArray * matches = [regEx matchesInString:s
options:0
range:(NSRange){0, [s length]}];
BOOL stringContainsOnlyOneCharacter = ([matches count] == 1);
Both these options correctly deal with multi-byte and composed characters; the regex version also does not require an explicit check for the empty string.
use this loop:
NSString *firstChar = [str substringWithRange:NSMakeRange(0, 1)];
for (int i = 1; i < [str length]; i++) {
NSString *ch = [str substringWithRange:NSMakeRange(i, 1)];
if(![ch isEqualToString:firstChar])
{
return NO;
}
}
return YES;

Generate a random string from NSCharacterSet

I have the following NSCharacterSet and want to generate a random string valid for that character set.
NSMutableCharacterSet *characterSet = [NSMutableCharacterSet alphanumericCharacterSet];
[characterSet formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
[NSCharacterSet characterSetWithCharactersInString:] produces a character set out of a string. I want a method that does the opposite. Something like [NSString stringWithCharacterSet:]
I don't think NSCharacterSet is the best way to store the list of valid characters as it doesn't provide convenient methods to get its length or access a character at a particular index. Use NSString instead:
+ (NSString *)randomStringFromCharacters:(NSString *)chars
ofLength:(NSUInteger)length
{
unichar str[length];
for (NSUInteger i = 0; i < length; i++)
str[i] = [chars characterAtIndex:arc4random() % [chars length]];
return [NSString stringWithCharacters:str length:length];
}

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 to parse out each Chinese character?

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