PDA

View Full Version : Obj-c finding index of character in NSString




Dav-id
Sep 1, 2008, 10:41 AM
I am pretty new to Objective-c but have been using Java and C# for a while so please bear with me if what I am asking is quite obvious.

In c# there is a method for strings where it is possible to get the index for a given character:

int index = myString.IndexOf(':');

I ideally would prefer not to loop through each character to find this index but I suppose as a last resort I may do so.

Any advice?

Thanks



robbieduncan
Sep 1, 2008, 10:46 AM
As with most basic questions the answer is in the documentation.

As a favour I'll give you step by step instructions on how to use the documentation:

Open the NSString documentation (http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html)

Scroll down till you find the method you need. In this case something from the section "Finding Characters and Substrings" is probably what you want.

Dav-id
Sep 1, 2008, 10:54 AM
I think possibly I was expecting something that was more of a direct equivalent to within Java/C# but I understand now that I should be looking at something more like the following method

- (NSRange)rangeOfString:(NSString *)aString

Thanks

lee1210
Sep 1, 2008, 10:57 AM
robbieduncan pointed you towards what you need to do exactly what you requested, but you may want to consider a different tact for your problem.

Why do you need to find the index of a character? Are you just splitting on it? Do you just want to see if a character is present? There are a lot of things NSString supports, and one of them may be a better fit than just finding the first occurrence of a character.

Also, some of this might be helpful while you're working with the NSString methods, though they are linked in most cases:
http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSCharacterSet_Class/Reference/Reference.html#//apple_ref/occ/clm/NSCharacterSet/characterSetWithCharactersInString:

http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_DataTypes/Reference/reference.html#//apple_ref/doc/c_ref/NSRange

-Lee

Dav-id
Sep 1, 2008, 11:33 AM
I was looking to get the length of a substring without actually breaking the string.

NSRange appears to have provided me with the solution I was looking for.

Sayer
Sep 1, 2008, 11:56 AM
Yeah its simple once you know how:

// tmityok: This will allow us to open specific URIs in Safari instead of WebNode

NSMutableString *subs = [NSMutableString stringWithString:[[request URL] absoluteString]];

// scan for openInSafari, with or without value, remove from URL and launch Safari
NSRange toprange = [subs rangeOfString: @"openInSafari"];

lee1210
Sep 1, 2008, 03:50 PM
Not that anyone asked, but this also seemed like a case that you could extend NSString to provide extra functionality.

I then found out that actually extending NSString is a really bad idea (but not until I had done so and had this working), so I made a class using composition instead.

Using NS for your own classes isn't a good idea, I was just playing with this.

The result:

NSExtendedString.m:

#import "NSExtendedString.h"

@implementation NSExtendedString

-(unsigned int) indexOf:(char) searchChar {
NSRange searchRange;
searchRange.location=(unsigned int)searchChar;
searchRange.length=1;
NSRange foundRange = [backingString rangeOfCharacterFromSet:[NSCharacterSet characterSetWithRange:searchRange]];
return foundRange.location;
}

-(NSExtendedString *) initWithString: (NSString *) origString {
if(self = [super init]) {
backingString = [[NSString alloc] initWithString:origString];
}
return self;
}
-(NSExtendedString *) initWithExtendedString: (NSExtendedString *) origString {
if(self = [super init]) {
backingString = [[origString string] copy];
}
return self;
}

-(NSString *) string {
return backingString;
}
@end


NSExtendedString.h:

#import <Foundation/Foundation.h>

@interface NSExtendedString : NSObject {
NSString *backingString;
}
- (unsigned int) indexOf:(char) searchChar;
-(NSExtendedString *) initWithString: (NSString *) origString;
-(NSExtendedString *) initWithExtendedString: (NSExtendedString *) origString;
-(NSString *) string;


@end


TestNewString.m:

#import <Foundation/Foundation.h>
#import "NSExtendedString.h"

int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSExtendedString *myString = [[NSExtendedString alloc] initWithString:@"Test:string+number-one"];
unsigned int colonPosition = [myString indexOf:':'];
unsigned int plusPosition = [myString indexOf:'+'];
unsigned int minusPosition = [myString indexOf:'-'];
NSLog(@"The position of the first colon is: %u, the position of the first plus is: %u, the position of the first minus is: %u",colonPosition,plusPosition,minusPosition);
NSExtendedString *stringTwo = [[NSExtendedString alloc] initWithExtendedString:myString];
unsigned int plusPositionTwo = [stringTwo indexOf:'+'];
NSLog(@"Testing copy: %u",plusPositionTwo);
[pool release];
return 0;
}


I'm on 10.4, so the proper type for most everything in 10.5 and above would be NSUInteger rather than unsigned int.

-Lee

Door
Dec 27, 2010, 01:36 PM
Having spent painful hours in many programming languages trying to use the native string parsing functionality, I've found that if you're doing any serious parsing of strings it's best just to go the regular expression route. I've not done much with the Objective C regex library yet but I'm starting to and it will definitely solve the problem specified in this thread.
Here's the class reference link:

http://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html

I would be interested in knowing though whether on these smaller devices use of the regex library would hog significantly more memory. I suppose I can run the tools ...

jared_kipe
Dec 27, 2010, 06:58 PM
Not that anyone asked, but this also seemed like a case that you could extend NSString to provide extra functionality.

I then found out that actually extending NSString is a really bad idea (but not until I had done so and had this working), so I made a class using composition instead.

Using NS for your own classes isn't a good idea, I was just playing with this.

The result:

NSExtendedString.m:

#import "NSExtendedString.h"

@implementation NSExtendedString

-(unsigned int) indexOf:(char) searchChar {
NSRange searchRange;
searchRange.location=(unsigned int)searchChar;
searchRange.length=1;
NSRange foundRange = [backingString rangeOfCharacterFromSet:[NSCharacterSet characterSetWithRange:searchRange]];
return foundRange.location;
}

-(NSExtendedString *) initWithString: (NSString *) origString {
if(self = [super init]) {
backingString = [[NSString alloc] initWithString:origString];
}
return self;
}
-(NSExtendedString *) initWithExtendedString: (NSExtendedString *) origString {
if(self = [super init]) {
backingString = [[origString string] copy];
}
return self;
}

-(NSString *) string {
return backingString;
}
@end


NSExtendedString.h:

#import <Foundation/Foundation.h>

@interface NSExtendedString : NSObject {
NSString *backingString;
}
- (unsigned int) indexOf:(char) searchChar;
-(NSExtendedString *) initWithString: (NSString *) origString;
-(NSExtendedString *) initWithExtendedString: (NSExtendedString *) origString;
-(NSString *) string;


@end


TestNewString.m:

#import <Foundation/Foundation.h>
#import "NSExtendedString.h"

int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSExtendedString *myString = [[NSExtendedString alloc] initWithString:@"Test:string+number-one"];
unsigned int colonPosition = [myString indexOf:':'];
unsigned int plusPosition = [myString indexOf:'+'];
unsigned int minusPosition = [myString indexOf:'-'];
NSLog(@"The position of the first colon is: %u, the position of the first plus is: %u, the position of the first minus is: %u",colonPosition,plusPosition,minusPosition);
NSExtendedString *stringTwo = [[NSExtendedString alloc] initWithExtendedString:myString];
unsigned int plusPositionTwo = [stringTwo indexOf:'+'];
NSLog(@"Testing copy: %u",plusPositionTwo);
[pool release];
return 0;
}


I'm on 10.4, so the proper type for most everything in 10.5 and above would be NSUInteger rather than unsigned int.

-Lee

To be fair, not that anyone asked, I don't really see the reason to extend NSString at all in this case to provide this functionality. Well not by subclassing anyway since Objective-C has such a nice way of giving existing classes new methods.


@interface NSString (indexOfChar)
- (unsigned int) indexOfChar: (char) toFind;
@end

@implementation NSString (indexOfChar)
// will return NSNotFound if not in the string
- (unsigned int) indexOfChar: (char) toFind {
// you could experiment with this, I suspect linear searching each
// character would be about as fast as it can get.
NSString *substring = [NSString stringWithFormat: @"%c", toFind];
NSRange range = [self rangeOfString: substring];
return range.location;
}
@end

// call like...
NSString *s = @"some string";
unsigned int index = [s indexOfChar: 'm'];
if (index != NSNotFound) {
...

lee1210
Dec 27, 2010, 07:32 PM
To be fair, not that anyone asked, I don't really see the reason to extend NSString at all in this case to provide this functionality. Well not by subclassing anyway since Objective-C has such a nice way of giving existing classes new methods.


@interface NSString (indexOfChar)
- (unsigned int) indexOfChar: (char) toFind;
@end

@implementation NSString (indexOfChar)
// will return NSNotFound if not in the string
- (unsigned int) indexOfChar: (char) toFind {
// you could experiment with this, I suspect linear searching each
// character would be about as fast as it can get.
NSString *substring = [NSString stringWithFormat: @"%c", toFind];
NSRange range = [self rangeOfString: substring];
return range.location;
}
@end

// call like...
NSString *s = @"some string";
unsigned int index = [s indexOfChar: 'm'];
if (index != NSNotFound) {
...


To be fair (to me) I wrote that in 2008. I was embarrassed to see that not-category business when I looked at this thread, but feel better that it was so old (if you're not getting better...).

-Lee

jared_kipe
Dec 28, 2010, 10:55 AM
To be fair (to me) I wrote that in 2008. I was embarrassed to see that not-category business when I looked at this thread, but feel better that it was so old (if you're not getting better...).

-Lee

Ha, I rarely notice the dates on old resurrected threads.

In 2008 I didn't know anything about programming and was merely an Apple Genius fixing broken computers.