Okay, so this is a bit confusing (well to me). I have a string that has a single number I want out of it. I have surrounded this number with '/' so that I will be able to get that number out of it later.
Here is how I am getting the number out of it:
if ([MYSTRING hasSuffix:#"mp"]) {
int start = 0;
int end = 0;
char looking = '/';
for(int i=0; i < MYSTRING.length; i++){
if (looking == [MYSTRING characterAtIndex:i]) {
if (start == 0) {
start = i;
}
else{
end = i + 1;
}
}
}
NSLog(#"%#", MYSTRING); //When i NSLOG here i get '2012-06-21 03:58:00 +0000/1/mp', 1 is the number i want out of the string, but this number could also change to 55 or whatever the user has
NSLog(#"start: %i, end: %i", start, end); //When i NSLOG here i get 'start: 25, end: 28'
NSString *number = [MYSTRING substringWithRange:NSMakeRange(start, end)];
number = [number stringByReplacingOccurrencesOfString:#"/" withString:#""];
if ([number intValue] > numberInt) {
numberInt = [number intValue];
}
It keeps crashing and the console says:
* Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString substringWithRange:]: Range or index out of bounds'
* First throw call stack:
(0x1875d72 0x106ce51 0x1875b4b 0x184ea64 0x3a6c 0x1080713 0x1bf59 0x1bef1 0xd532e 0xd588c 0xd49f5 0x49a2f 0x49c42 0x290fe 0x1b3fd 0x17d2f39 0x17d2c10 0x17ebda5 0x17ebb12 0x181cb46 0x181bed4 0x181bdab 0x17d1923 0x17d17a8 0x18e71 0x200d 0x1f35)
libc++abi.dylib: terminate called throwing an exception
From my counting the range is within the bounds, I dont get why I am getting this error?
Any help would be appreciated.
Thanks
Your NSMakeRange(start, end) should be NSMakeRange(start, end- start);
I think you have confusion in syntax of NSMakeRange. It is something like this
NSMakeRange(<#NSUInteger loc#>, <#NSUInteger len#>)
<#NSUInteger loc#>: It is the location from where you want to start picking or substring.
<#NSUInteger len#>: This is the length of your output or substring.
Example:
Mytest12test
Now I want to pick'12'
so:
NSString *t=#"Mytest12test";
NSString *x=[t substringWithRange:NSMakeRange(6, 2)] ;
In your code instead of length you are passing index of end character that is your mistake.
I don't know why your are using this approach, but iOS provides a string function which separates a string with respect to another string and returns an array of the components. See the following example:
NSString * str = #"dadsada/2/dsadsa";
NSArray *listItems = [str componentsSeparatedByString:#"/"];
NSString *component = [listItems objectAtIndex:1];
Now your component string should have 2 store in it.
When the compiler runs into this code...
else{
end = i + 1;
}
... in the last iteration of the loop, it sets the end variable to one more then the range of MYSTRING. This is why you are getting that error. To fix it, just do this:
else{
end = i;
}
Hope this helps!
P.S. Saleh's approach is a simpler way of accomplishing what you want
------UPDATE------
You should do it like this actually:
NSMutableArray *occurencesOfSlashes = [[NSMutableArray alloc] init];
char looking = '/';
for(int i=0; i < MYSTRING.length; i++){
if ([MYSTRING characterAtIndex:i] == looking) {
[occurencesOfSlashes addObject:[NSNumber numberWithInt:i]];
}
NSString *finalString = [MYSTRING substringWithRange:NSMakeRange([occurencesOfSlashes objectAtIndex:0],[occurencesOfSlashes objectAtIndex:1])];
Related
Here's my program so far. My intention is to have it so the if statement compares the letter in the string letterGuessed to a character in the string userInputPhraseString. Here's what I have. While coding in xCode, I get an "expected '['"error. I have no idea why.
NSString *letterGuessed = userInputGuessedLetter.text;
NSString *userInputPhraseString = userInputPhraseString.text;
int loopCounter = 0;
int stringLength = userInputPhraseString.length;
while (loopCounter < stringLength){
if (guessedLetter isEqualToString:[userInputPhraseString characterAtIndex:loopIndexTwo])
{
//if statement true
}
loopCounter++;
}
You are missing enclosing square brackets on this line:
if (guessedLetter isEqualToString:[userInputPhraseString characterAtIndex:loopIndexTwo])
It should be:
if ([guessedLetter isEqualToString:[userInputPhraseString characterAtIndex:loopIndexTwo]])
Edit that won’t fix your problem, though, because characterAtIndex: returns a unichar, not an NSString.
It's not clear what you are trying to do.. But I suppose that letterGuessed has one character... And that userInputPhraseString has many characters. So you want to know if letterGuessed is inside userInputPhraseString correct?
This is one solution without loops involved.. I replaced the input with fixed values for testing and tested the code.. It works.
NSString *letterGuessed = #"A"; //Change to your inputs
NSString *userInputPhraseString = #"BBBA"; //Since it has A it will be true in the test
NSCharacterSet *cset = [NSCharacterSet characterSetWithCharactersInString:letterGuessed];
NSRange range = [userInputPhraseString rangeOfCharacterFromSet:cset];
if (range.location != NSNotFound) { //Does letterGuessed is in UserInputPhraseString?
NSLog(#"YES"); //userInput Does contain A...
} else {
NSLog(#"NO");
}
In regards to your code... I fixed a couple of errors, first you are trying to get a UniChar (Integer) value for the character and want to compare it to a NSString which is an Object. Also fixed a couple of issues with syntax you had and used the right approach which is to return a range of characters. Again for doing what you want to accomplish the example above is the best approach I know, but for the sake of learning, here is your code fixed.
NSString *letterGuessed = #"A"; //Change to your inputs
NSString *userInputPhraseString = #"BBBA"; //Since it has A it will be true in the test
NSInteger loopCounter = 0; //Use NSInteger instead of int.
NSInteger stringLength = userInputPhraseString.length;
BOOL foundChar = NO; //Just for the sake of returning NOT FOUND in NSLOG
while (loopCounter < stringLength){
//Here we will get a letter for each iteration.
NSString *scannedLetter = [userInputPhraseString substringWithRange:NSMakeRange(loopCounter, 1)]; // Removed loopCounterTwo
if ([scannedLetter isEqualToString:letterGuessed])
{
NSLog(#"FOUND CHARACTER");
foundChar = YES;
}
loopCounter++;
}
if (!foundChar) NSLog(#"NOT FOUND");
NSRange holds the position, length.. So we move to a new position on every iteration and then get 1 character.
Also if this approach is what you want, I would strongly suggest a for-loop.
please help me with this problem.
I want to check if the targetString match the keyword or not. Consider some character may different, but should still return true.
Example:
targetString = #"#ß<"
keyword = #"abc", #"∂B(", #"#Aß<"
result: all must return true.
(Matched.targetString and all keyword are the same.)
Consider me have an array, contains list of character set that can be the same:
NSArray *variants = [NSArray arrayWithObjects:#"aA#∂", #"bBß", #"c©C<(", nil]
So that when matching, with this rule, it can match as the example above.
Here is what i've done so far (using recursion):
- (BOOL) test:(NSString*)aString include:(NSString*) keyWord doTrim:(BOOL)doTrim {
// break recursion.
if([aString length] < [keyWord length]) return false;
// First, loop through each keyword's character
for (NSUInteger i = 0; i < [keyWord length]; i++) {
// Get #"aA#∂", #"bBß", #"c©C<(" or only the character itself.
// like, if the keyword's character is A, return the string #"aA#∂".
// If the character is not in the variants set, eg. P, return #"P"
char c = [keyWord characterAtIndex:i];
NSString *rs = [self variantsWithChar:c];
// Check if rs (#"aA#∂" or #"P") contains aString[i] character
if([rs rangeOfString:[NSString stringWithCharacters:[aString characterAtIndex:i] length:1]].location == NSNotFound) {
// If not the same char, remove first char in targetString (aString), recursion to match again.
return [self test:[aString substringFromIndex:1] include:keyWord doTrim:NO];
}
}
// If all match with keyword, return true.
return true;
}
- (NSString *) variantsWithChar:(char) c {
for (NSString *s in self.variants) {
if ([s rangeOfString:[NSString stringWithFormat:#"%c",c]].location != NSNotFound) {
return s;
}
}
return [NSString stringWithFormat:#"%c", c];
}
The main problem is, variantsWithChar: doesn't return the correct string. I don't know which datatype and which function should I use here. Please help.
For thou who know ruby, here's the example in ruby. It work super fine!
require 'test/unit/assertions'
include Test::Unit::Assertions
class String
def matching?(keyword)
length >= keyword.length && (keyword.chars.zip(chars).all? { |cs| variants(cs[0]).include?(cs[1]) } || slice(1, length - 1).matching?(keyword))
end
private
VARIANTS = ["aA#∂", "bBß", "c©C<("]
def variants(c)
VARIANTS.find { |cs| cs.include?(c) } || c
end
end
assert "abc".matching?("#ß<")
PS: The fact is, it's containt a japanese character set that sounds the same (like あア, いイ... for thou who know japanese)
PS 2: Please feel free to edit this Question, since my engrish is sooo bad. I may not tell all my thought.
PS 3: And, maybe some may comment about the performance. Like, search about 10,000 target words, with nearly 100 variants, each variant have at most 4 more same characters.
So first off, ignore comments about ASCII and stop using char. NSString and CFString use unichar
If what you really want to do is transpose hiragana and katakana you can do that with CFStringTransform()
It wraps the ICU libraries included in OS X and iOS.
It makes it very simple.
Search for that function and you will find examples of how to use it.
After a while (a day) working on the code above, I finally get it through. But don't know about the performance. Someone comment and help me improve about performance, please. Thanks.
- (BOOL) test:(NSString*)aString include:(NSString*) keyWord doTrim:(BOOL)doTrim {
// break recursion.
if([aString length] < [keyWord length]) return false;
// First, loop through each keyword's character
for (NSUInteger i = 0; i < [keyWord length]; i++) {
// Get #"aA#∂", #"bBß", #"c©C<(" or only the character itself.
// like, if the keyword's character is A, return the string #"aA#∂".
// If the character is not in the variants set, eg. P, return #"P"
NSString* c = [NSString stringWithFormat:#"%C", [keyWord characterAtIndex:i]];
NSString *rs = [self variantsWithChar:c];
NSString *theTargetChar = [NSString stringWithFormat:#"%C", [aString characterAtIndex:i]];
// Check if rs (#"aA#∂" or #"P") contains aString[i] character
if([rs rangeOfString:theTargetChar].location == NSNotFound) {
// If not the same char, remove first char in targetString (aString), recursion to match again.
return [self test:[aString substringFromIndex:1] include:keyWord doTrim:NO];
}
}
// If all match with keyword, return true.
return true;
}
If you remove all comment, it'll be pretty short...
////////////////////////////////////////
- (NSString *) variantsWithChar:(NSString *) c{
for (NSString *s in self.variants) {
if ([s rangeOfString:c].location != NSNotFound) {
return s;
}
}
return c;
}
You could try comparing ascii values of the japanese characters in the variants's each character's ascii value. These japanese characters aren't treated like usual characters or string. Hence, string functions like rangeOfString won't work on them.
to be more precise: have a look at the following code.
it will search for "∂" in the string "aA#∂"
NSString *string = #"aA#∂";
NSMutableSet *listOfAsciiValuesOfString = [self getListOfAsciiValuesForString:string]; //method definition given below
NSString *charToSearch = #"∂";
NSNumber *ascii = [NSNumber numberWithInt:[charToSearch characterAtIndex:0]];
int countBeforeAdding = [listOfAsciiValuesOfString count],countAfterAdding = 0;
[listOfAsciiValuesOfString addObject:ascii];
countAfterAdding = [listOfAsciiValuesOfString count];
if(countAfterAdding == countBeforeAdding){ //element found
NSLog(#"element exists"); //return string
}else{
NSLog(#"Doesnt exists"); //return char
}
===================================
-(NSMutableSet*)getListOfAsciiValuesForString:(NSString*)string{
NSMutableSet *set = [[NSMutableSet alloc] init];
for(int i=0;i<[string length];i++){
NSNumber *ascii = [NSNumber numberWithInt:[string characterAtIndex:i]];
[set addObject:ascii];
}
return set;
}
How do I properly compare a string that I am retrieving from an NSArray to a literal string? So far, I have filled an NSArray up with three blank spaces, " " in one method and now I am trying to replace 10 random indexes in the NSArray with the string "C10", but I don't want to replace what is there unless it is " " still.
Here I created the array of size 100 and filled each spot with 3 blank spaces.
-(void) initBoard{
_board = [board initWithCapacity: 100];
for(int i =0; i < 100; i++){
[_board addObject:#" "];
}
}
Here is the method that I'm having problems with the equality comparison.
-(void)makeChutes: (int) numOfChutes {
//Make argument number of Chutes randomly across the board.
for(int i = 0; i < numOfChutes || i>(-100);){
int random = arc4random_uniform(101);
if ([[_board objectAtIndex:random] isEqual:#" "]) {
NSString *fString = [NSString stringWithFormat:#"C%d", 10];
[_board replaceObjectAtIndex:random withObject:fString];
i++;//Only increments i if 3 blank spaces were at random index..
}
else{//Used to attempt to stop my accidental infinite loop.
i--;
NSLog(#"I, loop, ran %i times.", i);//Attempt failed:-(
}
}
}
I know the above code is a mess. In an attempt to stop the looping I made the i decrement every time it did not meet the for condition and then added an OR condition to my for loop, using ||, to try and stop it after 100 cycles. For some reason the || condition does not stop it from looping even while i is well south of -100.
My first question is how do I properly compare the string stored in the array at index "random" with the literal string of 3 blank spaces? I also tried the method isEqualToString, but it worked the same.
Secondly and less importantly, since I don't need it now, how do I properly code a bi-conditional for loop? I don't get any errors or warnings from Xcode with my for loop syntax and it compiles and runs, so I don't really get why it ignores my second conditions and keeps iterating even while i is < -100.
to know the exist or not and index of it simply use ContainsObject property over NSArray
[array containsObject:#"text"];
int indexOfObject = [array indexOfObject:#"text"];
Use this method for string comparison
[[_board objectAtIndex:random] isEqualToString:#" "]
Modified your code. I think this is what you are looking for
-(void)makeChutes: (int) numOfChutes
{
for(int i = 0; i < numOfChutes ;i++){
int random = arc4random_uniform(101);
if ([[_board objectAtIndex:random] isEqualToString:#" "])
{
[_board replaceObjectAtIndex:random withObject:#"C10"];
i++;
}
}
}
EDIT :
Solution from what you said in comments
-(void)makeChutes: (int) numOfChutes
{
int i=0;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[cd] ' '"];
NSArray *filteredArray = [_board filteredArrayUsingPredicate:predicate];
int arrayCount=[filteredArray count];
do {
int random = arc4random_uniform(101);
if ([[_board objectAtIndex:random] isEqualToString:#" "])
{
[_board replaceObjectAtIndex:random withObject:#"C10"];
i++;
if (arrayCount == i) {
i=numOfChutes;
}
}
} while (i<numOfChutes);
}
EDIT
From the DOCS
isEqualToString: Returns a Boolean value that indicates whether a
given string is equal to the receiver using a literal Unicode-based
comparison.
(BOOL)isEqualToString:(NSString *)aString Parameters aString The string with which to compare the receiver. Return Value YES if aString
is equivalent to the receiver (if they have the same id or if they are
NSOrderedSame in a literal comparison), otherwise NO.
Discussion The comparison uses the canonical representation of
strings, which for a particular string is the length of the string
plus the Unicode characters that make up the string. When this method
compares two strings, if the individual Unicodes are the same, then
the strings are equal, regardless of the backing store. “Literal” when
applied to string comparison means that various Unicode decomposition
rules are not applied and Unicode characters are individually
compared. So, for instance, “Ö” represented as the composed character
sequence “O” and umlaut would not compare equal to “Ö” represented as
one Unicode character.
My "initBoard" method was broken, causing the "makeChutes" method not to work as expected. Here is the correct initBoard:
-(void) initBoard{
_board = [[NSMutableArray alloc] initWithCapacity:100];
for(int i =0; i < 100; i++){
[_board addObject:#" "];
}
}
And the corrected makeChutes:
-(void)makeChutes: (int) numOfChutes{
//Make argument number of Chutes randomly across the board.
for(int i = 0; i < numOfChutes;){
int random = arc4random_uniform(100);//+1 of max index
if ([[_board objectAtIndex:random] isEqualTo:#" "]){
NSString *fString = [NSString stringWithFormat:#"C%d", 10];
[_board replaceObjectAtIndex:random withObject:fString];
i++;//Only increments i if 3 blank spaces were at random index.
}
}
}
hi here is my function, but everytime when i try to init and alloc foo it falls, can you tell me why?
-(NSString*)modifyTheCode:(NSString*) theCode{
if ([[theCode substringToIndex:1]isEqualToString:#"0"]) {
if ([theCode length] == 1 ) {
return #"0000000000";
}
NSString* foo = [[NSString alloc]initWithString:[theCode substringWithRange:NSMakeRange(2, [theCode length]-1)]];
return [self modifyTheCode:foo];
} else {
return theCode;
}
}
the error message:
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.2 (8H7)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
replace this line
NSString* foo = [[NSString alloc]initWithString:[theCode substringWithRange:NSMakeRange(2, [theCode length]-1)]];
with this line
NSString* foo = [[NSString alloc]initWithString:[theCode substringWithRange:NSMakeRange(1, [theCode length]-1)]];
and try..
What is the error message?
If you are working with NSRange maybe you should check the length of theCode first.
Because the range is invalid. NSRange has two members, location and length. The range you give starts at the third character of the string and has the length of the string minus one. So your length is one character longer than the amount of characters left in the string.
Suppose theCode is #"0123". The range you create is { .location = 2, .length = 3 } This represents:
0123
^ start of range is here
^ start of range + 3 off the end of the string.
By the way, you'll be pleased to know that there are convenience methods so you don't have to mess with ranges. You could do:
if ([theCode hasPrefix: #"0"])
{
NSString* foo = [theCode substringFromIndex: 1]; // assumes you just want to strip off the leading #"0"
return [self modifyTheCode:foo];
} else {
return theCode;
}
By the way, your original code leaked foo because you never released it.
I need to pick string valur from an NSMutableArray then save it into a plist. I've builded an NSMutableArray to display infos in table View. Maximum allowed index is 8. (paste just two in example)
The problem if the String doesn't exist, I get the following error:
sDict is a dictionary for saving datas to a property list file.
the code:
- (IBAction)save:(id)sender {
(...)
NSString *One;
NSString *Two;
...etc
if ([self.smOne objectAtIndex:0])
One = [self.smOne objectAtIndex:0];
if ([self.smOne objectAtIndex:1])
Two = [self.smOne objectAtIndex:1];
...etc
if (One)
[sDict setObject:[self.smTwo objectAtIndex:0]
forKey:[UserM stringByAppendingString:One]];
[sDict setObject:[self.smThree objectAtIndex:0]
forKey:[UserS stringByAppendingString:One]];
[sDict setObject:[self.smFour objectAtIndex:0]
forKey:[UserP stringByAppendingString:One]];
if (Two)
[sDict setObject:[self.smTwo objectAtIndex:1]
forKey:[UserM stringByAppendingString:Two]];
[sDict setObject:[self.smThree objectAtIndex:1]
forKey:[UserS stringByAppendingString:Two]];
[sDict setObject:[self.smFour objectAtIndex:1]
forKey:[UserParM stringByAppendingString:Two]];
...etc
}
This code works if all objects are present, but fails if it miss one of the object at index.
I really don't know how to check properly if the object is present or not, cause code above seem's to don't works well.
I've tried with [self.smOne count] but as problem to pass as a Int or String to make conditions with.
Thanks for answer.
it looks like you're explicitly checking smOne from indices 1 through 8. But you also mentioned that the array can have up to 8. So if it's missing, say, 6, 7 and 8, you'd still be calling [smOne objectAtIndex:6], which would result in an NSRangeException being raised as 6 is out of bounds for the array.
try this instead:
int i = 0;
for ( NSString *aString in self.smOne )
{
[sDict setObject:[self.smTwo objectAtIndex:i]
forKey:[UserM stringByAppendingSting:aString]];
[sDict setObject:[self.smThree objectAtIndex:i]
forKey:[UserS stringByAppendingString:aString]];
[sDict setObject:[self.smFour objectAtIndex:i]
forKey:[UserP stringByAppendingString:aString]];
i++;
}
it'll go through each object in the smOne array and add the object into sDict regardless of how many items you have in smOne.
also, be careful with how you're generating your keys. there's the possibility that [UserM stringByAppendingSting:aString] won't always be unique.
Sorry to ask again but i have dificulties to find how to rebuild arrays from the key/string couple saved with the loop.
i've tried this:
int i = 0;
for (NSString *SMServ in [temp objectForKey:
[UserMen stringByAppendingFormat:#"%d",i]]){
NSString *SMMem[i];
SMMem[i] = [temp objectForKey:[UserMen stringByAppendingFormat:#"%d",i]];
NSArray *theArray = [ NSArray arrayWithObjects:SMMem count:i];
i++;
}
But nothing happens.
if i try with for (i = 0; i < 9; i ++) and (i + 1) instead of [i], i get same bounds errors in the first example.
thanks again for help.
Well, finally it ,works. Thanks for link to the documentation, i read too fast last time.
I'm sure this is not the cleanest way, but it works with this loop:
for (key in sDict) {
if ([sDict valueForKey:[UserMen stringByAppendingFormat:#"%d",i]]) {
tempMe = [sDict valueForKey:[UserMen stringByAppendingFormat:#"%d",i]];
if (tempMe) {
[manArray insertObject:tempMe atIndex:(0 + a)];
[bankArray insertObject:[NSString stringWithFormat:#"%d",i] atIndex:(0 + a)];
a++;
}
}
if ([sDict valueForKey:[UserSerial stringByAppendingFormat:#"%d",i]]) {
SMSer = [sDict valueForKey:[UserSerial stringByAppendingFormat:#"%d",i]];
if (SMSer) {
[serArray insertObject:SMSer atIndex:(0 + b)];
b++;
}
}
if ([sDict valueForKey:[UserPart stringByAppendingFormat:#"%d",i]]) {
SMPart = [sDict valueForKey:[UserPart stringByAppendingFormat:#"%d",i]];
if (SMPart) {
[partArray insertObject:SMPart atIndex:(0 + c)];
c++;
}
}
i++;
}