string formatting in a cocoa tutorial - objective-c

I am doing a Cocoa tutorial where I need to count the characters in a field, then output something like 'the_string_i_am_count' has 21 characters.
I have managed to get the string, count it, and output the count but I have no idea how to output the count along with the string and the other info.
How would I do this?
-(IBAction)countCharacters:(id)sender
{
//i had to connect this to the class also to make it get the value.
//NSString *string = [inputField stringValue];
//get the number of chars
NSUInteger length = [[inputField stringValue] length];
[outputField setIntValue:length]; //string];
//[outputField setStringValue: #"'s' has %d characters.", string, length];
}
Semi working code:
-(IBAction)countCharacters:(id)sender
{
//i had to connect this to the class also to make it get the value.
NSString *string = [inputField stringValue];
//get the number of chars
NSUInteger length = [[inputField stringValue] length];
[outputField setStringValue:[NSString stringWithFormat:#"'%s' has %d characters.", string, length]];
}

[outputField setStringValue:[NSString stringWithFormat:#"%# has %# characters.", string, length]];

Related

Get a substring from an NSString until arriving to any letter in an NSArray - objective C

I am trying to parse a set of words that contain -- first greek letters, then english letters. This would be easy if there was a delimiter between the sets.That is what I've built so far..
- (void)loadWordFileToArray:(NSBundle *)bundle {
NSLog(#"loadWordFileToArray");
if (bundle != nil) {
NSString *path = [bundle pathForResource:#"alfa" ofType:#"txt"];
//pull the content from the file into memory
NSData* data = [NSData dataWithContentsOfFile:path];
//convert the bytes from the file into a string
NSString* string = [[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSUTF8StringEncoding];
//split the string around newline characters to create an array
NSString* delimiter = #"\n";
incomingWords = [string componentsSeparatedByString:delimiter];
NSLog(#"incomingWords count: %lu", (unsigned long)incomingWords.count);
}
}
-(void)parseWordArray{
NSLog(#"parseWordArray");
NSString *seperator = #" = ";
int i = 0;
for (i=0; i < incomingWords.count; i++) {
NSString *incomingString = [incomingWords objectAtIndex:i];
NSScanner *scanner = [NSScanner localizedScannerWithString: incomingString];
NSString *firstString;
NSString *secondString;
NSInteger scanPosition;
[scanner scanUpToString:seperator intoString:&firstString];
scanPosition = [scanner scanLocation];
secondString = [[scanner string] substringFromIndex:scanPosition+[seperator length]];
// NSLog(#"greek: %#", firstString);
// NSLog(#"english: %#", secondString);
[outgoingWords insertObject:[NSMutableArray arrayWithObjects:#"greek", firstString, #"english",secondString,#"category", #"", nil] atIndex:0];
[englishWords insertObject:[NSMutableArray arrayWithObjects:secondString,nil] atIndex:0];
}
}
But I cannot count on there being delimiters.
I have looked at this question. I want something similar. This would be: grab the characters in the string until an english letter is found. Then take the first group to one new string, and all the characters after to a second new string.
I only have to run this a few times, so optimization is not my highest priority.. Any help would be appreciated..
EDIT:
I've changed my code as shown below to make use of NSLinguisticTagger. This works, but is this the best way? Note that the interpretation for english characters is -- for some reason "und"...
The incoming string is: άγαλμα, το statue, only the last 6 characters are in english.
int j = 0;
for (j=0; j<incomingString.length; j++) {
NSString *language = [tagger tagAtIndex:j scheme:NSLinguisticTagSchemeLanguage tokenRange:NULL sentenceRange:NULL];
if ([language isEqual: #"und"]) {
NSLog(#"j is: %i", j);
int k = 0;
for (k=0; k<j; k++) {
NSRange range = NSMakeRange (0, k);
NSString *tempString = [incomingString substringWithRange:range ];
NSLog (#"tempString: %#", tempString);
}
return;
}
NSLog (#"Language: %#", language);
}
Alright so what you could do is use NSLinguisticTagger to find out the language of the word (or letter) and if the language has changed then you know where to split the string. You can use NSLinguisticTagger like this:
NSArray *tagschemes = #[NSLinguisticTagSchemeLanguage];
NSLinguisticTagger *tagger = [[NSLinguisticTagger alloc] initWithTagSchemes:tagschemes options: NSLinguisticTagPunctuation | NSLinguisticTaggerOmitWhitespace];
[tagger setString:#"This is my string in English."];
NSString *language = [tagger tagAtIndex:0 scheme:NSLinguisticTagSchemeLanguage tokenRange:NULL sentenceRange:NULL];
//Loop through each index of the string's characters and check the language as above.
//If it has changed then you can assume the language has changed.
Alternatively you can use NSSpellChecker's requestCheckingOfString to get teh dominant language in a range of characters:
NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker];
[spellChecker setAutomaticallyIdentifiesLanguages:YES];
NSString *spellCheckText = #"Guten Herr Mustermann. Dies ist ein deutscher Text. Bitte löschen Sie diesen nicht.";
[spellChecker requestCheckingOfString:spellCheckText
range:(NSRange){0, [spellCheckText length]}
types:NSTextCheckingTypeOrthography
options:nil
inSpellDocumentWithTag:0
completionHandler:^(NSInteger sequenceNumber, NSArray *results, NSOrthography *orthography, NSInteger wordCount) {
NSLog(#"dominant language = %#", orthography.dominantLanguage);
}];
This answer has information on how to detect the language of an NSString.
Allow me to introduce two good friends of mine.
NSCharacterSet and NSRegularExpression.
Along with them, normalization. (In Unicode terms)
First, you should normalize strings before analyzing them against a character set.
You will need to look at the choices, but normalizing to all composed forms is the way I would go.
This means an accented character is one instead of two or more.
It simplifies the number of things to compare.
Next, you can easily build your own NSCharacterSet objects from strings (loaded from files even) to use to test set membership.
Lastly, regular expressions can achieve the same thing with Unicode Property Names as classes or categories of characters. Regular expressions could be more terse but more expressive.

Counting occurrences of capital letters and numbers in an NSString

In PHP I am using the following code...
$passwordCapitalLettersLength = strlen(preg_replace("![^A-Z]+!", "", $password));
$passwordNumbersLength = strlen(preg_replace("/[0-9]/", "", $password));
...to count how many times capital letters and numbers appear in the password.
What is the equivalent of this in Objective C?
You can use the NSCharacterSet:
NSString *password = #"aas2dASDasd1asdASDasdas32D";
int occurrenceCapital = 0;
int occurenceNumbers = 0;
for (int i = 0; i < [password length]; i++) {
if([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[password characterAtIndex:i]])
occurenceCapital++;
if([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[password characterAtIndex:i]])
occurenceNumbers++;
}
This can be done fairly concisely using the abilities of NSString and NSCharacterSet, instead of the need to iterate manually.
A decrement of 1 is required as componentsSeparatedByCharactersInSet: will always return at least one element, and that one element won't count your separations.
NSString* password = #"dhdjGHSJD7d56dhHDHa7d5bw3/%£hDJ7hdjs464525";
NSArray* capitalArr = [password componentsSeparatedByCharactersInSet:[NSCharacterSet uppercaseLetterCharacterSet]];
NSLog(#"Number of capital letters: %ld", (unsigned long) capitalArr.count - 1);
NSArray* numericArr = [password componentsSeparatedByCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]];
NSLog(#"Number of numeric digits: %ld", (unsigned long) numericArr.count - 1);
Original answer: Whilst the code you've provided won't cover all bases, if you need to keep using those regular expressions for safety/risk reasons, you can do so below.
You can use RegEx in Objective-C. Saves manually iterating through the String, and keeps the code concise. It also means because you aren't iterating manually, you could potentially get a performance boost, as you can let the compiler/framework writer optimize it.
// Testing string
NSString* password = #"dhdjGHSJD7d56dhHDHa7d5bw3/%£hDJ7hdjs464525";
NSRegularExpression* capitalRegex = [NSRegularExpression regularExpressionWithPattern:#"[A-Z]"
options:0
error:nil];
NSRegularExpression* numbersRegex = [NSRegularExpression regularExpressionWithPattern:#"[0-9]"
options:0
error:nil];
NSLog(#"Number of capital letters: %ld", (unsigned long)[capitalRegex matchesInString:password
options:0
range:NSMakeRange(0, password.length)].count);
NSLog(#"Number of numeric digits: %ld", (unsigned long)[numbersRegex matchesInString:password
options:0
range:NSMakeRange(0, password.length)].count);

How do I split a string with special characters into a NSMutableArray

I'am trying to seperate a string with danish characters into a NSMutableArray. But something is not working. :(
My code:
NSString *danishString = #"æøå";
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[danishString length]];
for (int i=0; i < [danishString length]; i++)
{
NSString *ichar = [NSString stringWithFormat:#"%c", [danishString characterAtIndex:i ]];
[characters addObject:ichar];
}
If I do at NSLog on the danishString it works (returns æøå);
But if I do a NSLog on the characters (the array) I get some very stange characters - What is wrong?
/Morten
First of all, your code is incorrect. characterAtIndex returns unichar, so you should use #"%C"(uppercase) as the format specifier.
Even with the correct format specifier, your code is unsafe, and strictly speaking, still incorrect, because not all unicode characters can be represented by a single unichar. You should always handle unicode strings per substring:
It's common to think of a string as a sequence of characters, but when
working with NSString objects, or with Unicode strings in general, in
most cases it is better to deal with substrings rather than with
individual characters. The reason for this is that what the user
perceives as a character in text may in many cases be represented by
multiple characters in the string.
You should definitely read String Programming Guide.
Finally, the correct code for you:
NSString *danishString = #"æøå";
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[danishString length]];
[danishString enumerateSubstringsInRange:NSMakeRange(0, danishString.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[characters addObject:substring];
}];
If with NSLog(#"%#", characters); you see "strange character" of the form "\Uxxxx", that's correct. It's the default stringification behavior of NSArray by description method. You can print these unicode characters one by one if you want to see the "normal characters":
for (NSString *c in characters) {
NSLog(#"%#", c);
}
In your example, ichar isn't type of NSString, but unichar. If you want NSStrings try getting a substring instead :
NSString *danishString = #"æøå";
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[danishString length]];
for (int i=0; i < [danishString length]; i++)
{
NSRange r = NSMakeRange(i, 1);
NSString *ichar = [danishString substringWithRange:r];
[characters addObject:ichar];
}
You could do something like the following, which should be fine with Danish characters, but would break down if you have decomposed characters. I suggest reading the String Programming Guide for more information.
NSString *danishString = #"æøå";
NSMutableArray* characters = [NSMutableArray array];
for( int i = 0; i < [danishString length]; i++ ) {
NSString* subchar = [danishString substringWithRange:NSMakeRange(i, 1)];
if( subchar ) [characters addObject:subchar];
}
That would split the string into an array of individual characters, assuming that all the code points were composed characters.
It is printing the unicode of the characters. Anyhow, you can use the unicode (with \u) anywhere.

Objective C - OSX NSInterger to NSString

Hi i am reading a book by aaron hillegass on cococa programming and I doing one of the mini tasks he asks us to do.
the task is to create an application that has one window open and has 1 input text field, a button and a label.
when a user inputs some text and presses the button, the label displays the text and the length of the text inputted.
Here is what I have got so far
//retrieve text from textfield
NSString *string = [textFieldInput stringValue];
//retrieve length of text and store in NSInteger called length
NSInteger length = [string length];
//store length in string format
NSString *string_length = [NSString stringWithFormat:#"%d", length];
//join strings
NSString *full_string = [string stringByAppendingString:(#"has ",string_length,#" characters")];
//set label text
[textField setStringValue:full_string];
however the actual string is shown and the characters string is shown, just not the string_length. any suggestions and am i going about this in the right way? Thanks.
NSString *fullString = [string stringByAppendingFormat:#"has %# characters", string_length];
//retrieve text from textfield
NSString *string = [textFieldInput stringValue];
NSString *fullString = [string stringByAppendingFormat:#" has %d characters", [string length]];
//set label text
[textField setStringValue:fullString];
Your usage of stringByAppendingString: is wrong.
If I understand you correctly, you are trying to pass a list of strings that should be appended to string but that method only takes a single string argument.
You can try the following:
NSString* fullString = [string stringByAppendingString:[NSString stringWithFormat:#"%# %# %#", #"has ", string_length, #" characters"]];

Reading ints from NSData?

I think I am getting a little confused here, what I have is a plain text file with the numbers "5 10 2350" in it. As you can see below I am trying to read the first value using readDataOfLength, I think maybe where I am getting muddled is that I should be reading as chars, but then 10 is 2 chars and 2350 is 4. Can anyone point m in the right direction to reading these.
NSString *dataFile_IN = #"/Users/FGX/Documents/Xcode/syntax_FileIO/inData.txt";
NSFileHandle *inFile;
NSData *readBuffer;
int intBuffer;
int bufferSize = sizeof(int);
inFile = [NSFileHandle fileHandleForReadingAtPath:dataFile_IN];
if(inFile != nil) {
readBuffer = [inFile readDataOfLength:bufferSize];
[readBuffer getBytes: &intBuffer length: bufferSize];
NSLog(#"BUFFER: %d", intBuffer);
[inFile closeFile];
}
EDIT_001
Both excellent answers from Jarret and Ole, here is what I have gone with. One final question "METHOD 02" picks up a carriage return to a blank line at the bottom of the text file, returns it as a subString, which in turn gets converted to "0" can I set the NSCharacterSet to stop that, currently I just added a length check on the string.
NSInteger intFromFile;
NSScanner *scanner;
NSArray *subStrings;
NSString *eachString;
// METHOD 01 Output: 57 58 59
strBuffer = [NSString stringWithContentsOfFile:dataFile_IN encoding:NSUTF8StringEncoding error:&fileError];
scanner = [NSScanner scannerWithString:strBuffer];
while ([scanner scanInteger:&intFromFile]) NSLog(#"%d", intFromFile);
// METHOD 02 Output: 57 58 59 0
strBuffer = [NSString stringWithContentsOfFile:dataFile_IN encoding:NSUTF8StringEncoding error:&fileError];
subStrings = [strBuffer componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
for(eachString in subStrings) {
if ([eachString length] != 0) {
NSLog(#"{%#} %d", eachString, [eachString intValue]);
}
}
gary
There are several conveniences in Cocoa that can make your life a bit easier here:
NSString *dataFile_IN = #"/Users/FGX/Documents/Xcode/syntax_FileIO/inData.txt";
// Read all the data at once into a string... an convenience around the
// need the open a file handle and convert NSData
NSString *s = [NSString stringWithContentsOfFile:dataFile_IN
encoding:NSUTF8StringEncoding
error:nil];
// Use a scanner to loop over the file. This assumes there is nothing in
// the file but integers separated by whitespace and newlines
NSInteger anInteger;
NSScanner *scanner = [NSScanner scannerWithString:s];
while (![scanner isAtEnd]) {
if ([scanner scanInteger:&anInteger]) {
NSLog(#"Found an integer: %d", anInteger);
}
}
Otherwise, using your original approach, you'd pretty much have to read character-by-character, adding each character to a "buffer" and then evaluating your integer when you encounter a space (or newline, or some other separator).
If you read the file's contents into a string as Jaret suggested, and assuming the string only contains numbers and whitespace, you can also call:
NSArray *substrings = [s componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
This will split the string at whitespace and newline characters and return an array of the substrings. You would then have to convert the substrings to integers by looping over the array and calling [substring integerValue].
One way to do it would be first to first turn your readBuffer into a string as follows:
NSString * dataString = [[NSString alloc] initWithData:readBuffer encoding:NSUTF8StringEncoding];
Then split the string into values:
NSString *dataString=#"5 10 2350"; // example string to split
NSArray * valueStrings = [dataString componentsSeparatedByString:#" "];
for(NSString *valueString in valueStrings)
{
int value=[valueString intValue];
NSLog(#"%d",value);
}
Output of this is
5
10
2350