PDA

View Full Version : Cocoa:NSString Search Methods Question




Soulstorm
Jul 3, 2006, 03:54 AM
I have an NSArray which holds NSString objects.

I want to write a search method that will return similar (NOT exact) matches of a given NSStsing.

For example I want the search for "Nick" to return results for "Nickolas", "Nickolette", "Parnickette", etc.

I am having difficulties to do that because by looking at Apple's documentation, NSString doesn't seem to have such a comparison function. Can anyone tell me how to do this?



robbieduncan
Jul 3, 2006, 04:25 AM
I'd use one of the available regexp (http://www.cocoadev.com/index.pl?RegularExpressions) libraries.

Soulstorm
Jul 3, 2006, 04:44 AM
I can't even read the first one. It's written in Japanese. And the second one concerns PHP.

Isn't there any way to do this using plain Cocoa?

HexMonkey
Jul 3, 2006, 04:50 AM
You can use rangeOfString to check if a string contains another, which would result in a match for all your examples. For example:

BOOL match = ([aString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound);

Soulstorm
Jul 3, 2006, 05:18 AM
You can use rangeOfString to check if a string contains another, which would result in a match for all your examples. For example:

BOOL match = ([aString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound);
Simple and fast. Thanks a lot, that worked out quite nicely.

Also, robbieduncan, I hadn't looked well the link you gave me. Although my problem has been solved, you have given me a good starting point for other things, thanks a lot!

caveman_uk
Jul 3, 2006, 06:44 AM
If you need rather more than 'is this a substring of this string' then there are a range of algorithms you can use. I implemented one of them in my program that gives a similarity score based on adjacent letter pairs and it seems to work pretty well. If you're interested I can post it...

Soulstorm
Jul 3, 2006, 07:29 AM
Any code resource would be nice, caveman. If you want, I am interested in seeing the code.

BTW, has anyone been able to compile the Omnigroup's Foundation sourcecode (http://www.omnigroup.com/developer/sourcecode/) on his/her Mac? When I try to do it, I always end up in an error in the terminal, like this:

/Users/soulstorm/Desktop/OmniGroup/Frameworks/OmniFoundation/Tests/OFSetTests.m: In function '-[OFSetTests testSetFromArray]':
/Users/soulstorm/Desktop/OmniGroup/Frameworks/OmniFoundation/Tests/OFSetTests.m:33: warning: implicit declaration of function 'shouldBeEqual'

Ld /Users/Shared/soulstorm/Products/Debug/OFUnitTests.otest/Contents/MacOS/OFUnitTests normal ppc
cd /Users/soulstorm/Desktop/OmniGroup/Frameworks/OmniFoundation
/usr/bin/gcc-4.0 -o /Users/Shared/soulstorm/Products/Debug/OFUnitTests.otest/Contents/MacOS/OFUnitTests -L/Users/Shared/soulstorm/Products/Debug -F/Users/Shared/soulstorm/Products/Debug -F/Developer/SDKs/MacOSX10.4u.sdk/Library/Frameworks -filelist /Users/soulstorm/xcode/intermediate\ files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFUnitTests.LinkFileList -framework OmniBase -framework Foundation -framework SenTestingKit -framework OmniFoundation -arch ppc -Wl,-Y,1455 -bundle -mmacosx-version-min=10.3 -isysroot /Developer/SDKs/MacOSX10.4u.sdk
/usr/bin/ld: Undefined symbols:
_should
_shouldBeEqual
_fail1
_shouldBeEqual1
_should1
_shouldnt
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFXMLDocumentTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFXMLDocumentTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFDateTestCase.o reference to undefined _fail1
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFDateTestCase.o reference to undefined _shouldBeEqual1
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFHeapTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFHeapTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFBTreeTest.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFBTreeTest.o reference to undefined _should1
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFRegexpTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFRegexpTests.o reference to undefined _should1
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFRegexpTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFHashTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFHashTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFStringEncodingTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFStringEncodingTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFStringEncodingTests.o reference to undefined _shouldBeEqual1
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFXMLCursorTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFXMLCursorTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFArrayTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFArrayTests.o reference to undefined _should1
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFArrayTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFArrayTests.o reference to undefined _shouldnt
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFSearchingTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFSearchingTests.o reference to undefined _should1
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFSearchingTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFSearchingTests.o reference to undefined _shouldnt
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFNumberFormatterTest.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFNumberFormatterTest.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFStringScannerTest.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFStringScannerTest.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFStringScannerTest.o reference to undefined _shouldnt
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFAliasTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFAliasTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFCompressionTest.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFCompressionTest.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFStringExtensionsTest.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFStringExtensionsTest.o reference to undefined _should1
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFStringExtensionsTest.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFMutableAttributedStringExtensionsTest.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFMutableAttributedStringExtensionsTest.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFVersionNumberTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFVersionNumberTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFAttributedStringExtensionsTest.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFTimeSpanFormatterTest.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFErrorExtensionTests.o reference to undefined _should
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFErrorExtensionTests.o reference to undefined _shouldBeEqual
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFErrorExtensionTests.o reference to undefined _shouldnt
/Users/soulstorm/xcode/intermediate files/OmniFoundation.build/Debug/OFUnitTests.build/Objects-normal/ppc/OFSetTests.o reference to undefined _shouldBeEqual
collect2: ld returned 1 exit status
** BUILD FAILED **
Build failed in (OmniGroup/Frameworks/OmniFoundation(OFUnitTests))
G5:~/Desktop/OmniGroup soulstorm$

caveman_uk
Jul 3, 2006, 04:09 PM
OK then, here you go. It's a category on NSString. The actual method to use is

-(float) similarityWithString:(NSString*) otherString;

It returns a float between 0 and 1.0 with better matches being nearer 1.0.

NSStringExtensions.h

#import <Cocoa/Cocoa.h>

@interface NSString (NSStringExtensions)

-(float) similarityWithString:(NSString*) otherString;

-(NSMutableArray*) _letterPairs:(NSString*) string;

-(NSMutableArray*) _wordLetterPairs:(NSString*) string;

@end

NSStringExtensions.m

#import "NSStringExtensions.h"

@implementation NSString (NSStringExtensions)

-(float) similarityWithString:(NSString*) otherString;
{
NSMutableArray* pairs1=[self _wordLetterPairs:[self uppercaseString]];
NSMutableArray* pairs2=[otherString _wordLetterPairs:[otherString uppercaseString]];

int intersection=0;
int u=([pairs1 count]+[pairs2 count]);
int i=0;
int j;
for (; i<[pairs1 count]; i++)
{
j=0;
for (; j<[pairs2 count]; j++)
{
if ([[pairs1 objectAtIndex:i] isEqualTo:[pairs2 objectAtIndex:j]])
{
intersection++;
[pairs2 removeObjectAtIndex:j];
}
}
}
return (2.0*intersection)/u;
}

-(NSMutableArray*) _letterPairs:(NSString*) string;
{
int numPairs=[string length]-1;
NSMutableArray* pairs=[NSMutableArray arrayWithCapacity:numPairs];

int i=0;
for (;i<numPairs; i++)
[pairs addObject:[string substringWithRange:NSMakeRange(i,2)]];
return pairs;
}

-(NSMutableArray*) _wordLetterPairs:(NSString*) string;
{
NSMutableArray* allPairs=[NSMutableArray array];
NSArray* words=[string componentsSeparatedByString:@" "];
int w=0;
for (; w<[words count]; w++)
[allPairs addObjectsFromArray:[self _letterPairs:[words objectAtIndex:w]]];
return allPairs;
}

@end


This code is my attempt at an objective-C version of the method and example code presented here. (http://www.catalysoft.com/articles/StrikeAMatch.html)