NSInvalidArgumentException with "stringwithformat" - objective-c

I'm trying to write in an array, but I have the problem "NSInvalidArgumentException"
I'm beginning in objective C.
Here's a part of my code :
int charIndex;
unichar testChar1, testChar2;
NSString *valeur1, *valeur2;
NSMutableArray* tableau1 = [NSMutableArray arrayWithCapacity:4];
NSMutableArray* tableau2 = [NSMutableArray arrayWithCapacity:4];
for(charIndex=0; charIndex < 4; charIndex++) {
testChar1 = [_saisie.text characterAtIndex:charIndex];
testChar2 = [[NSString stringWithFormat:#"%d", nombreChoisi] characterAtIndex:charIndex];
NSLog(#"%C", testChar1);
valeur1 = [NSString stringWithFormat:#"%C", testChar1];
valeur2 = [NSString stringWithFormat:#"%C", testChar2];
[tableau1 replaceObjectAtIndex:charIndex withObject:valeur1];
[tableau2 replaceObjectAtIndex:charIndex withObject:valeur2];
}
Everything is working until the line 14, where the variable valeur1 take the value nil. I don't know where the problem is.
Edit : The line NSLog was just here to test the { #"%C", value } and it works. The value "nombreChoisi" is chosen before with a random function, and "_saisie.text" comes from a text field.

It looks like you are using a capital %C when building valeur1 and valeur2. Shouldn't you be using a lower case %c?

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.

addObject replaces the previous values

In the following code i am trying to add the user selected names in arrayDoctors, say A,B and then i add it to selectedDoctors array. But the 2nd time i select doctors C,D and add it to selectedDoctors array it replaces the previous objects A,B to C and D.
- (void)doneDoctorSelection:(id)sender
{
[pop3 dismissPopoverAnimated:YES];
NSString *str = [arrayDoctors objectAtIndex:0];
NSString *str1 = [str stringByAppendingString:[NSString stringWithFormat:#" + %d",arrayDoctors.count-1]];
if([arrayDoctors count] == 1)
lblDoctor.text = str;
else
lblDoctor.text = str1;
[selectedDoctors addObject:arrayDoctors];
[selectedDoctorIdList addObject:arrayDoctorsId];
NSLog(#"selectedDoneDoctors %# ",selectedDoctors);
}
What am i doing wrong?
Instead of this part
NSMutableArray *tempDoctor = [[NSMutableArray alloc]initWithArray:arrayDoctors];
[selectedDoctors addObject:tempDoctor];
You can use
[selectedDoctors addObject:[arrayDoctors mutableCopy]];
Ah!! finally found the solution. I was removing the objects from arrayDoctors before putting new values in it, and i had initialized it in viewDidLoad method. So what was happening is when i did [selectedDoctors addObject:arrayDoctors]; the second time it was replacing the same object at 1st place also since its uses the same memory location. The solution was to create a temporary object. The following is the changed code.
- (void)doneDoctorSelection:(id)sender
{
[pop3 dismissPopoverAnimated:YES];
NSString *str = [arrayDoctors objectAtIndex:0];
NSString *str1 = [str stringByAppendingString:[NSString stringWithFormat:#" + %d",arrayDoctors.count-1]];
NSMutableArray *tempDoctor = [[NSMutableArray alloc]initWithArray:arrayDoctors];
NSMutableArray *tempDocorId = [[NSMutableArray alloc]initWithArray:arrayDoctorsId
];
if([arrayDoctors count] == 1)
lblDoctor.text = str;
else
lblDoctor.text = str1;
NSLog(#"Before Adding %# ",selectedDoctors);
[selectedDoctors addObject:tempDoctor];
[selectedDoctorIdList addObject:tempDocorId];
//[selectedDoctors addObjectsFromArray:arrayDoctors];
//[selectedDoctorIdList addObjectsFromArray:arrayDoctorsId];
NSLog(#"selectedDoneDoctors %# ",selectedDoctors);
}
Thanx for pointing me in right direction.

Objective C - Split NSString into Array, max count

I am new to Objective-C, so I am trying to split an String into an Array in this format:
NSString *str = #":49:DE:Bahnhofsstr:12:39:11";
NSArray *arr = [str componentsSeparatedByString:#":"];
I receive the following objects in arr:
[#"", #"49", #"DE", #"Bahnhofsstr", #"12", #"39", #"11"]
But I need it in this format:
[#"", #"49", #"DE", #"Bahnhofsstr:12:39:11"]
Anyone have any ideas?
You can use a regular expression. The one you want is this:
^([^:]*):([^:]*):([^:]*):(.*)$
The above matches three sequences of characters without colons in separated by colons and then a fourth group consisting of any kind of character. The ^ at the front and the $ at the end match the beginning and the end of the string respectively otherwise nonsense like 1:2:3:4:49:DE:Bahnhofsstr:12:39:11 would match because there is a match embedded in the string.
The parenthesis delimit capture groups which will be returned to you once the regular expression matching has been done. The first capture group is all the characters up to the first colon. The second capture group is all the characters between the first and second colons. The third capture group is all the characters between the second and third colons and the fourth capture group is all the characters after the third colon.
There is also a zeroth capture group which is the entire matching sequence.
Here's how to use this in Objective-C:
NSString* pattern = #"^([^:]*):([^:]*):([^:]*):(.*)$";
NSString* line = #":49:DE:Bahnhofsstr:12:39:11";
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern: pattern
options: 0
error: &error];
if (regex == nil)
{
NSLog(#"Invalid regular expression %#, %#", pattern, error);
}
else
{
NSArray* matches = [regex matchesInString: line
options: 0
range: NSMakeRange(0, [line length])];
if ([matches count] == 1)
{
// Should only be one match
NSTextCheckingResult* result = [matches objectAtIndex: 0];
NSMutableArray* captureGroups = [[NSMutableArray alloc] init];
// Omit capture group 0 because it will be the whole string
for (int i = 1 ; i < [result numberOfRanges] ; i++)
{
NSRange groupRange = [result rangeAtIndex: i];
NSString* captureGroup = [line substringWithRange: groupRange];
[captureGroups addObject: captureGroup];
}
NSLog(#"The fields are %#", captureGroups);
}
else
{
// match error
}
}
Regular expressions, as proposed by JeremyP, are an obvious solution to this sort of problem.
Some people don't like regexes, though, so another solution is to use NSScanner which is also made to scan strings and read the result into variables. Given that the delimiter is the same for all fields, it even lends itself to use a nice loop, reducing the tedious scanning code.
Here is an example:
NSString *str = #":49:DE:Bahnhofsstr:12:39:11";
const NSUInteger nFields = 4;
NSScanner *myScanner = [NSScanner scannerWithString: str];
NSMutableArray *arr = [NSMutableArray array];
for (NSUInteger i = 0; i < nFields - 1; i++) {
NSString *field;
// The BOOLs here really ought to be checked
BOOL found = [myScanner scanUpToString: #":" intoString: &field];
BOOL passedDelimiter = [myScanner scanString: #":" intoString: NULL];
[arr addObject: field ?: #"" ];
}
NSString *lastField = [[myScanner string] substringFromIndex:[myScanner scanLocation]];
[arr addObject: lastField];
That last line to read the remainder of the string is taken straight from the docs for NSScanner.

Making a backspace button for a calculator

I am making an iOS calculator and it I'm having minor difficulties with the backspace button (for deleting the last number of the value displayed on a label).
To get the current value on the label I use
double currentValue = [screenLabel.text doubleValue]
Following other questions, I tried something like
-(IBAction)backspacePressed:(id)sender
{
NSMutableString *string = (NSMutableString*)[screenLabel.text];
int length = [string length];
NSString *temp = [string substringToIndex:length-1]
;
[screenLabel.text setText:[NSString stringWithFormat:#"%#",temp]];
}
But it does not work,
(Xcode says "setText is deprecated", "NSString may not respond to setText" and that an identifier is expected in the first line of code inside the IBAction)
and I do not really understand this code to make it work by myself.
What should I do?
It should be
[screenLabel setText:[NSString stringWithFormat:#"%#",temp]];
Your Xcode clearly says that you are trying to call setText' method on anNSStringwhere as you should be calling that on aUILabel. YourscreenLabel.textis retuning anNSString. You should just usescreenLabelalone and should callsetText` on that.
Just use,
NSString *string = [screenLabel text];
The issue with that was that, you are using [screenLabel.text]; which is not correct as per objective-c syntax to call text method on screenLabel. Either you should use,
NSString *string = [screenLabel text];
or
NSString *string = screenLabel.text;
In this method, I dont think you need to use NSMutableString. You can just use NSString instead.
In short your method can be written as,
-(IBAction)backspacePressed:(id)sender
{
NSString *string = [screenLabel text];
int length = [string length];
NSString *temp = [string substringToIndex:length-1];
[screenLabel setText:temp];
}
As per your question in comments(which is deleted now), if you want to display zero when there are no strings present, try,
-(IBAction)backspacePressed:(id)sender
{
NSString *string = [screenLabel text];
int length = [string length];
NSString *temp = [string substringToIndex:length-1];
if ([temp length] == 0) {
temp = #"0";
}
[screenLabel setText:temp];
}

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