Check NSString for special characters - cocoa

I want to check an NSString for special characters, i.e. anything except a-z, A-Z and 0-9.
I don't need to check how many special characters are present, or their positions, I just need to know whether a particular string contains any or not. If it does, then I want to be able to display "Error!", or something similar.
For example, jHfd9982 is OK but asdJh992# is not.
Also, letters with accents, diacritics, etc. should not be allowed.
How would I go about this?
Thanks!
Michael

NSCharacterSet * set = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
if ([aString rangeOfCharacterFromSet:set].location != NSNotFound) {
NSLog(#"This string contains illegal characters");
}
You could also use a regex (this syntax is from RegexKitLite: http://regexkit.sourceforge.net ):
if ([aString isMatchedByRegex:#"[^a-zA-Z0-9]"]) {
NSLog(#"This string contains illegal characters");
}

Here the code you can use it to check the string has any special character or not
NSString *string = <your string>;
NSString *specialCharacterString = #"!~`##$%^&*-+();:={}[],.<>?\\/\"\'";
NSCharacterSet *specialCharacterSet = [NSCharacterSet
characterSetWithCharactersInString:specialCharacterString];
if ([string.lowercaseString rangeOfCharacterFromSet:specialCharacterSet].length) {
NSLog(#"contains special characters");
}

You want to search NSString using a character set if it cant find any characters in the string then rangeOfCharacterFromSet: will return a range of {NSNotFound, 0}
The character set would be like [NSCharacterSet symbolCharacterSet] or your own set. Note you can also invert character sets so you could have a set of acceptable characters

If you want to remove special characters & numbers from any string (even textfield text), while you are editing, these lines below are quite handy:
#define ACCEPTABLE_CHARACTERS #"!~`##$%^&*-+();:=_{}[],.<>?\\/|\"\'0123456789"
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *cs = [NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return (![string isEqualToString:filtered]) ? NO : YES;
}

This code allows only numbers in UITextField input.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if ([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
return NO;
else
return YES;
}

Related

NSRegularExpressions - filtering out words within Xcode

I'm currently teaching myself NSRegularExpressions and how to filter certain things out of RSS feeds. Particularly, the RSS feed is in the format "some text :: (there can be a Re: here for a reply) some text :: some text". I would like to remove that Re: if it exists. I know that there should be a way to do this without creating another NSRegularExpression within the one I currently have. I don't have a grasp on all of the symbols. I was trying to use ?: to uninclude the Re: from capture, but I can't quite figure out how. Would someone mind looking at this for me and giving me a helping hand?
NSRegularExpression *reg = [[NSRegularExpression alloc] initWithPattern:#".* :: ?:Re: (.*) :: .*" options:0 error:nil]; //The () creates a capture group and an array of ranges for reg
//Loop through every title of the items in channel
for (RSSItem *i in items) {
NSString *itemTitle = [i title];
//find mittts
//Find matches in the title string. The range argument specifies how much of the title to search; in this case, all of it.
NSArray *matches = [reg matchesInString:itemTitle options:0 range:NSMakeRange(0, [itemTitle length])];
//If there was a match...
if ([matches count] > 0) {
//Print the location of the match in the string and the string
NSTextCheckingResult *result = [matches objectAtIndex:0];
NSRange r = [result range];
NSLog(#"\nMatch at {%d, %d} for %#!\n", r.location, r.length, itemTitle);
NSLog(#"Range : %d",[result numberOfRanges]);
//One capture group, so two ranges, let's verify
if ([result numberOfRanges] == 2) {
//Pull out the 2nd range, which will be the capture group
NSRange r = [result rangeAtIndex:1];
//Set the title of the item to the string within the capture group
[i setTitle:[itemTitle substringWithRange:r]];
NSLog(#"%#", [itemTitle substringWithRange:r]);
}
}
}
Never mind, found it. I needed (?:Re: )? to prevent capturing it.

osx: remove all characters from string that cannot be used for a filenames in osx

Is there some standard method to remove all characters from string that cannot be used for a filenames in osx? Does the characters you are allowed to use correspond to some commonly used category? (I know defining a list of allowed characters would be possible, but I want to be able to use filenames from several languages (chinese, among others), so this will be a bit of a pain.) A solution that works in ubuntu too, would be great.
I use the following code to convert a arbitrary string into a valid filename. It follows similar rules (if not the same) to those applied to creating a webloc file when dragging a URL to the Desktop.
// Returns a sting representing this filename transformed (if neccesary) to make
// a valid (Mac OS X) filename.
- (NSString *) stringByMakingFileNameValid:(NSString *)fileName
{
NSMutableString * validFileName = [NSMutableString stringWithString:fileName];
if (!validFileName || [validFileName isEqualToString:#""]) {
return #"untitled";
}
// remove initial period chars "."
if ([validFileName hasPrefix:#"."]) {
NSRange dotRange = [validFileName rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:#"."]];
[validFileName deleteCharactersInRange:dotRange];
}
// remove any colon chars ":" (same as webloc creation behaviour)
[validFileName replaceOccurrencesOfString:#":" withString:#"" options:0 range:NSMakeRange(0, [validFileName length])];
// this may lead to spaces at either end which need trimming
validFileName = [[[validFileName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] mutableCopy] autorelease];
// if there is nothing left return default value
if ([validFileName isEqualToString:#""]) {
return #"untitled";
}
// replace other disallowed Mac OS X characters
[validFileName replaceOccurrencesOfString:#"/" withString:#"-" options:0 range:NSMakeRange(0, [validFileName length])];
// if grater than 102 chars reduce to 101 and add elipses
if ([validFileName length] > 102) {
[validFileName deleteCharactersInRange:NSMakeRange(100, [validFileName length]-100)];
[validFileName appendString:#"…"];
}
return [[validFileName copy] autorelease];
}
At the Darwin level "/" characters are stored as ":" characters (and vice versa). They are removed here for cosmetic reasons.
Any unicode character except for the "/" is allowed. Because your question is AppleScript related as well I have to inform you that Macintosh Paths displays a "/" while the actual character is ":". So when you tell the Finder to make folder at path "Macintosh HD:Users:shortname:Desktop:images/movies" then in POSIX it will look like "/Users/shortname/Desktop/images:movies".

Check for String within a String

I'm trying to compare two strings
NSString strOne = #"Cat, Dog, Cow";
NSString strTwo = #"Cow";
How do I determine if strOne contains strTwo
Try using rangeOfString:
NSRange result = [strOne rangeOfString:strTwo];
From the documentation:
Returns an NSRange structure giving the location and length in the receiver of the first occurrence of aString. Returns {NSNotFound, 0} if aString is not found or is empty (#"").
For anyone needing the code to check is a string exists within a string, here's my code thanks to fbrereto. This example checks to see if any string contained in an array of strings (stringArray) can be found within a string (myString):
int count = [stringArray count];
for (NSUInteger x = 0; x < count; ++x) {
NSRange range = [self.myString rangeOfString:[stringArray objectAtIndex:x]];
if (range.length > 0) {
// A match has been found
NSLog(#"string match: %#",[stringArray objectAtIndex:x]);
}
}
I believe this is the correct syntax for checking if the range exists (correcting response from Kendall):
range.location != NSNotFound
Gradually straying off topic, but I always explode my strings, which would mean just exploding it using your search string as a key and you can use the array count to see how many instances you have.
Just incase anyone is coming from a code language that uses "explode" to blow a string up into an array like me, I found writing my own explode function tremendously helpful, those not using "explode" are missing out:
- (NSMutableArray *) explodeString : (NSString *)myString key:(NSString*) myKey
{
NSMutableArray *myArray = [[NSMutableArray alloc] init];
NSRange nextBreak = [myString rangeOfString:myKey];
while(nextBreak.location != NSNotFound)
{
[myArray addObject: [myString substringToIndex:nextBreak.location]];
myString = [myString substringFromIndex:nextBreak.location + nextBreak.length];
nextBreak = [myString rangeOfString:myKey];
}
if(myString.length > 0)
[myArray addObject:myString];
return myArray;
}
works like this:
[self explodeString: #"John Smith|Age: 37|Account Balance: $75.00" key:#"|"];
which will return this array:
[#"John Smith", #"Age: 37", #"Account Balance: $75.00"];
This lets you quickly pull out a specific value in a tight space, Like if you have a client and you want to know how much money he has:
[[self explodeString: clientData key: pipe] objectAtIndex: 1];
or if you wanted specifically the dollar amount as a float:
[[[self explodeString: [[self explodeString: clientData key: pipe] objectAtIndex: 1] key: #": "] objectAtIndex: 2] floatValue];
anyway I find arrays way easier to work with and more flexible, so this is very helpful to me. Additionally with a little effort you could make an "explodable string" data type for your private library that lets you treat it like a string or return an index value based on the key
ExplodableString *myExplodableString;
myExplodableString.string = #"This is an explodable|string";
NSString *secondValue = [myExplodableString useKey: #"|" toGetValue: index];

NSString isEqualToString: does not work. Why?

I create an NSString using,
NSString *myString = [[NSString alloc] initWithBytes:someBuffer length:sizeof(someBuffer) encoding:NSASCIIStringEncoding];
I used NSLog to output myString and it displays "Hello".
If this is the case, then why does this fail.
NSString *helloString = #"Hello"
BOOL check = [myString isEqualToString:helloString];
Your myString variable is actually an NSString with a length of 64; the additional characters are probably undefined. What you most likely want to do is this:
NSString *myString = [[NSString alloc] initWithBytes:someBuffer length:strlen(someBuffer) encoding:NSASCIIStringEncoding];
This assumes a null-terminated C-string exists in your buffer.
There are probably some trailing characters that you can't see when calling NSLog(). For example: whitespace, linefeeds or even '\0' characters.
Check [myString length] to see if it returns 5.

How to create an NSString with one random letter?

I need to create an NSString that has a single random uppercase letter.
I can get random int's fine, and I could construct a C string from it and then make the NSString, but I imagine there has to be a better and more cocoa-ish way.
Thanks!
You can just make an NSString containing what you consider to be letters and pull a random character from it. Here's an example category:
#implementation NSString(RandomLetter)
- (NSString *)randomLetter {
return [self substringWithRange:[self rangeOfComposedCharacterSequenceAtIndex:random()%[self length]]];
}
#end
(You'll need to srandom(time()) at some point, obviously. Maybe include an initialize method in your category.)
I think the best way is to use a c string so that you can use an explicit encoding. Here's an example of that:
NSInteger MyRandomIntegerBetween(NSInteger min, NSInteger max) {
return (random() % (max - min + 1)) + min;
}
NSString *MyStringWithRandomUppercaseLetter(void) {
char string[2] = {0, 0};
string[0] = MyRandomIntegerBetween(65, 90); /// 'A' -> 'Z' in ASCII.
return [[[NSString alloc] initWithCString:string encoding:NSASCIIStringEncoding] autorelease];
}
Here's an alternative, that's really pretty much the same thing, but avoids the C string.
NSString *MyStringWithRandomUppercaseLetter(void) {
unichar letter = MyRandomIntegerBetween(65, 90);
return [[[NSString alloc] initWithCharacters:&letter length:1] autorelease];
}
I prefer the explicit character encodings in the first approach, but they're both correct.

Resources