CocoaDev

Edit AllPages

GormanChristian thought it would be a good idea to start a page with useful string methods. Now, anyone in the community can feel free to add a method or two (or more)! (Functions are also acceptable.) Refactoring is also always welcome.

Be careful when using methods that return non-class types (such as int or NSRange). You’ll need to #import the category’s header file or declare the method some other way, or else the compiler will consider the return type to be id and complain

NSString category CocoaDevUsersAdditions:

NSString+CocoaDevUsersAdditions.h

#import <Foundation/Foundation.h>

@interface NSString (CocoaDevUsersAdditions)

-(NSArray *) splitToSize:(unsigned)size; //returns NSArray of <= size character strings -(NSString *)removeTabsAndReturns; -(NSString *)newlineToCR;

-(NSString *)safeFilePath;

-(NSRange)whitespaceRangeForRange:(NSRange) characterRange; //returns the range of characters around characterRange, extended out to the nearest whitespace

// returns an array of strings corresponding to matches to subexpressions within a regular expression

-(BOOL)isValidURL;

-(OSStatus)pathToFSRef:(FSRef)ref; +(NSString)pathFromFSRef:(FSRef*)ref;

@end

NSString+CocoaDevUsersAdditions.m

#import “NSString+CocoaDevUsersAdditions.h”

@implementation NSString (CocoaDevUsersAdditions)

// Returns size of string, including length byte (i.e. conversion to “hi” returns 3), or 0 if failed.

-(int)occurencesOfSubstring:(NSString *)substr { //consider that for this, it may be(though I’m not sure) faster to use the less-robust outlined below. return [self occurencesOfSubstring:substr options:NSCaseInsensitiveSearch]; }

-(int)occurencesOfSubstring:(NSString )substr options:(int)opt { / if one wanted to make a much shorter(is it faster?), but rather less robust implementation, one would do: return [[self componentsSeparatedByString:substr] count] - 1; */ int strlen = [self length]; int position = 0; NSRange currentRange; BOOL flag = YES; int count = 0; do { currentRange = [self rangeOfString:substr options:opt range:NSMakeRange(position, strlen-position)]; if (currentRange.location == NSNotFound) { flag = NO; } else { count++; position = currentRange.location + currentRange.length; } } while (flag == YES);

return count; }

//be careful if you’re using SenTe’s SenFoundation. It implements -words as well, //and you may become confused in seeking bugs.

//NSTextStorage implements a -words method as well (in 10.3, at least). You may be able to use that instead.

// Useful for checking for illegal characters.

// Useful for replacing illegal characters with “?” or something.

-(NSArray *)linesSortedByLength { return self componentsSeparatedByString:@”\n”] sortedArrayUsingSelector:@selector(compareLength:)]; }

-(NSComparisonResult)compareLength:(NSString *)otherString { if([self length] < [otherString length]) { return NSOrderedAscending; } else if([self length] > [otherString length]) { return NSOrderedDescending; } //if same length, use alphabetical ordering. else { return [self compare:otherString]; } }

-(NSArray *) splitToSize:(unsigned)size { NSMutableArray *splitStrings = [NSMutableArray array];

int count = 0; int i = 0; unsigned loc = 0; NSString *tempString;

count = [self length] / size;

for (i=0; i < count; i++) { loc = size * i;

 tempString = [self substringWithRange:NSMakeRange(loc,size)];
 [splitStrings addObject: [tempString copy]];    }

loc = size * count;

tempString = [self substringFromIndex:loc];

[splitStrings addObject: [tempString copy]];

return splitStrings; }

-(NSString *)removeTabsAndReturns { NSMutableString *outputString = [NSMutableString string]; NSCharacterSet *charSet; NSString *temp;

NSScanner *scanner = [NSScanner scannerWithString:self];

charSet = [NSCharacterSet characterSetWithCharactersInString:@”\n\r\t”];

while ([scanner scanUpToCharactersFromSet:charSet intoString:&temp]) { [outputString appendString:temp];

} return outputString copy] autorelease]; }

-(NSString*)newlineToCR { NSMutableString *str = [NSMutableString string]; [str setString: self];

[str replaceOccurrencesOfString:@”\n” withString:@”\r” options:NSLiteralSearch range:NSMakeRange (0, [str length])]; return [[str copy] autorelease]; }

-(NSString *)safeFilePath { int numberWithName = 1; BOOL isDir; NSString *safePath = [[NSString alloc] initWithString:self];

if ([[NSFileManager defaultManager] fileExistsAtPath:safePath isDirectory:&isDir]) { while ([[NSFileManager defaultManager] fileExistsAtPath:safePath isDirectory:&isDir]) { [safePath release]; safePath = [[NSString alloc] initWithFormat:@”%@ %d.%@”, [self stringByDeletingPathExtension], numberWithName,[self pathExtension;

   numberWithName++;
 }    }

return safePath; }

-(NSRange)whitespaceRangeForRange:(NSRange)characterRange { NSString *string = self copy] autorelease]; NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; unsigned int areamax = NSMaxRange(characterRange); unsigned int length = [string length];

NSRange start = [string rangeOfCharacterFromSet:whitespaceSet options:NSBackwardsSearch range:NSMakeRange(0, characterRange.location)];

if (start.location == NSNotFound) { start.location = 0; } else { start.location = NSMaxRange(start); }

NSRange end = [string rangeOfCharacterFromSet:whitespaceSet options:0 range:NSMakeRange(areamax, length - areamax)];

if (end.location == NSNotFound) end.location = length;

NSRange searchRange = NSMakeRange(start.location, end.location - start.location); //last whitespace to next whitespace return searchRange; }

// Useful for parsing strings, in conjunction with rangeOf… methods.

#include

/*

static void raise_reg_error_exception(const char* name, int errorcode, regex_t* regex) { NSMutableData* errorString = [NSMutableData data];

[errorString setLength:regerror(errorcode, regex, NULL, 0)];

size_t errorSize = regerror(errorcode, regex, [errorString mutableBytes], [errorString length]);

regfree(regex);

NSCAssert2(errorSize == [errorString length], @”Unexpected size in raise_reg_error_exception: %d, %d”, errorSize, [errorString length]);

[NSException raise: NSInvalidArgumentException format: @”%s: %s”, name, [errorString bytes; }

-(BOOL)isValidURL { return ([NSURL URLWithString:self] != nil); }

// Replaces all XML/HTML reserved chars with entities.

-(OSStatus)pathToFSRef:(FSRef*)ref { return( FSPathMakeRef( (const UInt8 *)[self fileSystemRepresentation], ref, NULL ) ); }

+(NSString)pathFromFSRef:(FSRef)ref { NSString *path = nil; CFURLRef url = CFURLCreateFromFSRef( kCFAllocatorDefault, ref ); if ( url != NULL ) { path = (NSString *)CFURLCopyFileSystemPath( url, kCFURLPOSIXPathStyle ); [path autorelease]; CFRelease( url ); }

return( path ); }

@end


NSString category CocoaDevUsersAdditionsTest using ObjcUnit framework:

NSString+CocoaDevUsersAdditionsTest.h

#import <ObjcUnit/ObjcUnit.h>

@interface NSString+CocoaDevUsersAdditionsTest: TestCase { }

@end

NSString+CocoaDevUsersAdditionsTest.m

#import “NSString+CocoaDevUsersAdditionsTest.h” #import “NSString+CocoaDevUsersAdditions.h”

@implementation NSString+CocoaDevUsersAdditionsTest

@end


Revision History

Adjusted indentation, spacing, braces. – DustinVoss

Added header and implemetation files for unit tesing using ObjcUnit. I think it should be a part of any code. – NirSoffer

Added someone’s containsString:. – DustinVoss

7 November 2003 - added splitToSize:(unsigned)size, removeTabsAndReturns, newlineToCR methods

25 November 2003 - added GormanChristian’s safeFilePath method from the SafelyNamingFiles page

7 June 2004 - added whitespaceRangeForRange: adapted from code by MikeTrent over at ImplementSyntaxHighlighting

13 June 2004 - added findRegularExpression: – PerryClarke

16 March 2005 - added -(BOOL)isValidURL

16 March 2005 - added containsCharacterFromSet:, stringWithSubstitute:forCharactersFromSet:, stringSafeForXML, and substringBefore/ AfterRange: – DustinVoss

9 October 2005 - cleaned up and modified -tokensSeparatedByCharactersFromSet: to behave as expected, that is, to return tokens separated by characters from specified set, instead of tokens separated by the inverse of the specified set. Updated -words and -objCTokens accordingly and fixed compile error in -words, though I question the usefulness of these methods. Corrected misuse of NULL in containsString: and eliminated C99 scoping in for loop within -findRegularExpression:ignoreCase: to eliminate compiler warnings. Fixed bug in findRegularExpression:ignoreCase: where for loop would be exited prematurely if a subexpression was not matched; instead, now returns [NSNull null] in this case. Also rewrote this method to use NSMutableData, removing hard-coded space allocation, and added raise_reg_error_exception function to raise an exception on error. – TkM


NSString (rot13)

This is a simple category to add a class function that allows ROT13 encoding to the string class. A friend asked for a simple ROT13 encoder/decoder, so I hacked this together real quick while having my morning coffee. I am sure I could probably have written this a touch cleaner, but as of now it works and is compliant with ROT13 standards, and most of all, it’s easy to use.

Example:

NSString *rotted = [NSString rot13:@”This text is encoded in ROT13 format”];

The same function encoded and decodes, so it’s easy to use.

NSString+rot13.h

// // rot13.h // iROT13 // // Created by David Giffin on 11/9/04. // Copyright 2004 David Giffin http://www.davtri.com. All rights reserved. //

#import <Foundation/NSString.h>

@interface NSString (rot13)

NSString+rot13.m

// // rot13.m // iROT13 // // Created by David Giffin on 11/9/04. // Copyright 2004 David Giffin http://www.davtri.com. All rights reserved. //

#import “NSString+rot13.h”

@implementation NSString (rot13)

@end

I hope others find this of use… I have had to do this a few times over the years when some project called for ROT13, so I figured this way, others can get the use of this, and I can look it up here later in case I look the original (again).

[[DaveGiffin

This code will break with characters that don’t fit within a single byte, which is all unicode characters that are outside of the Latin1 charset. It will work fine for ASCII, but it will mangle general unicode text. Declaring theChar as a unichar and changing the append lines would fix it.

Thanks, I totally missed that. Still not used to messing with the unichar typedef… I just fixed this in the application and am updating the above posted code to reflect it. Again, thanks for the input. DaveGiffin

Great! I’m always keeping my eye out for things like that. I’m glad you were able to fix it so easily. It does make one wonder, what exactly is the proper way to rot13 a bunch of Chinese text? :-)

It’s probably like rot3000 or something…

By the way, you are leaking the local NSMutableString holder.

NSString *rval = [NSString stringWithString:holder]; [holder release]; return rval;

Also stylistically, and performance wise, you would be best to burn another local variable to cache [theText length] so you don’t recompute it every time through the loop.

NSUInteger len = [theText length]; for(i = 0; i < len; i++) {


Added pathToFSRef and pathFromFSRef.

Usage:

FSRef ref = {‘\0’}; if ( [@”/System” pathToFSRef:&ref] == noErr ) { NSString *path; path = [NSString pathFromFSRef:&ref]; NSLog(path); }

Category:CocoaDevUsersAdditions