I need to match my string in this way: *myString*
where * mean any substring.
which method should I use?
can you help me, please?
If it's for iPhone OS 3.2 or later, use NSRegularExpressionSearch.
NSString *regEx = [NSString stringWithFormat:#".*%#.*", yourSearchString];
NSRange range = [stringToSearch rangeOfString:regEx options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
}
You can't do an actual search using a * (wildcard character), but you can usually do something that is equivalent:
Equivalent to searching for theTerm*:
if ([theString hasPrefix:#"theTerm"]) {
Equivalent to searching for *theTerm:
if ([theString hasSuffix:#"theTerm"]) {
Or, using the category on NSString shown below, the following is equivalent to searching for *theTerm*:
if ([theString containsString:#"theTerm"]) {
A category is simply a new method (like a function) that we add to class. I wrote the following one because it generally makes more sense to me to think of one string containing another rather than dealing with NSRanges.
// category on NSString
#interface NSString (MDSearchAdditions)
- (BOOL)containsString:(NSString *)aString;
#end
#implementation NSString (MDSearchAdditions)
- (BOOL)containsString:(NSString *)aString {
return [self rangeOfString:aString].location != NSNotFound;
}
#end
If you need something more evolved, try https://github.com/dblock/objc-ngram.
Related
I have NSString *string = #"Helo"; and NSString *editedString = #"Hello";. How find index for changed character or characters (for example here is #"l").
Start going through one string and compare each character with the character at the same index in the other string. The place where the comparison fails is the index of the changed character.
I've written a category on NSString that will do what you want. I've used my StackOverflow username as a postfix on the category method. This is to stop an unlikely potential future collision with a method of the same name. Feel free to change it.
First the interface definition NSString+Difference.h:
#import <Foundation/Foundation.h>
#interface NSString (Difference)
- (NSInteger)indexOfFirstDifferenceWithString_mttrb:(NSString *)string;
#end
and the implementation 'NSString+Difference.m`:
#import "NSString+Difference.h"
#implementation NSString (Difference)
- (NSInteger)indexOfFirstDifferenceWithString_mttrb:(NSString *)string; {
// Quickly check the strings aren't identical
if ([self isEqualToString:string])
return -1;
// If we access the characterAtIndex off the end of a string
// we'll generate an NSRangeException so we only want to iterate
// over the length of the shortest string
NSUInteger length = MIN([self length], [string length]);
// Iterate over the characters, starting with the first
// and return the index of the first occurence that is
// different
for(NSUInteger idx = 0; idx < length; idx++) {
if ([self characterAtIndex:idx] != [string characterAtIndex:idx]) {
return idx;
}
}
// We've got here so the beginning of the longer string matches
// the short string but the longer string will differ at the next
// character. We already know the strings aren't identical as we
// tested for equality above. Therefore, the difference is at the
// length of the shorter string.
return length;
}
#end
You would use the above as follows:
NSString *stringOne = #"Helo";
NSString *stringTwo = #"Hello";
NSLog(#"%ld", [stringOne indexOfFirstDifferenceWithString_mttrb:stringTwo]);
You can use -rangeOfString:. For example, [string rangeOfString:#"l"].location. There are several variants of that method, too.
How can I check to see if an NSString contains base64 data in an if statement? Because base64 encodes the data in a completely random way, I can't search for a phrase within the NSString so instead I will need to check to see if the contents of the string results in a data file.
Here's a category on NSString I created that should work:
#interface NSString (MDBase64Additions)
- (BOOL)isBase64Data;
#end
#implementation NSString (MDBase64Additions)
- (BOOL)isBase64Data {
if ([self length] % 4 == 0) {
static NSCharacterSet *invertedBase64CharacterSet = nil;
if (invertedBase64CharacterSet == nil) {
invertedBase64CharacterSet = [[[NSCharacterSet
characterSetWithCharactersInString:
#"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="]
invertedSet] retain];
}
return [self rangeOfCharacterFromSet:invertedBase64CharacterSet
options:NSLiteralSearch].location == NSNotFound;
}
return NO;
}
#end
If you expect newlines or blank spaces in the data, you could update this method to remove those first (likely NSCharacterSet's +whitespaceCharacterSet).
If there's primarily just one class where you'll be using this category method, you could put this code inside its .m file above that class's #implementation block. If you think you might want to use that category from more than one class, you could create a separate .h & .m pair to contain it (e.g. MDFoundationAdditions.h, MDFoundationAdditions.m), and then import it into those classes.
To use:
NSString *dataString = /* assume exists */;
if ([dataString isBase64Data]) {
}
How can I uppercase the fisrt letter of a NSString, and removing any accents ?
For instance, Àlter, Alter, alter should become Alter.
But, /lter, )lter, :lter should remains the same, as the first character is not a letter.
Please Do NOT use this method. Because one letter may have different count in different language. You can check dreamlax answer for that. But I'm sure that You would learn something from my answer.
NSString *capitalisedSentence = nil;
//Does the string live in memory and does it have at least one letter?
if (yourString && yourString.length > 0) {
// Yes, it does.
capitalisedSentence = [yourString stringByReplacingCharactersInRange:NSMakeRange(0,1)
withString:[[yourString substringToIndex:1] capitalizedString]];
} else {
// No, it doesn't.
}
Why should I care about the number of letters?
If you try to access (e.g NSMakeRange, substringToIndex etc)
the first character in an empty string like #"", then your app will crash. To avoid this you must verify that it exists before processing on it.
What if my string was nil?
Mr.Nil: I'm 'nil'. I can digest anything that you send to me. I won't allow your app to crash all by itself. ;)
nil will observe any method call you send to it.
So it will digest anything you try on it, nil is your friend.
You can use NSString's:
- (NSString *)capitalizedString
or (iOS 6.0 and above):
- (NSString *)capitalizedStringWithLocale:(NSLocale *)locale
Since you want to remove diacritic marks, you could use this method in combination with the common string manipulating methods, like this:
/* create a locale where diacritic marks are not considered important, e.g. US English */
NSLocale *locale = [[[NSLocale alloc] initWithLocaleIdentifier:#"en-US"] autorelease];
NSString *input = #"Àlter";
/* get first char */
NSString *firstChar = [input substringToIndex:1];
/* remove any diacritic mark */
NSString *folded = [firstChar stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:locale];
/* create the new string */
NSString *result = [[folded uppercaseString] stringByAppendingString:[input substringFromIndex:1]];
Gonna drop a list of steps which I think you can use to get this done. Hope you can follow through without a prob! :)
Use decomposedStringWithCanonicalMappingto decompose any accents (Important to make sure accented characters aren't just removed unnecessarily)
Use characterAtIndex: to extract the first letter (index 0), use upperCaseString to turn it into capitol lettering and use stringByReplacingCharactersInRange to replace the first letter back into the original string.
In this step, BEFORE turning it into uppercase, you can check whether the first letter is one of the characters you do not want to replace, e.g. ":" or ";", and if it is, do not follow through with the rest of the procedure.
Do a [theString stringByReplacingOccurrencesOfString:#"" withString:#""]` sort of call to remove any accents left over.
This all should both capitalize your first letter AND remove any accents :)
Since iOS 9.0 there is a method to capitalize string using current locale:
#property(readonly, copy) NSString *localizedCapitalizedString;
I'm using this method for similar situations but I'm not sure if question asked to make other letters lowercase.
- (NSString *)capitalizedOnlyFirstLetter {
if (self.length < 1) {
return #"";
}
else if (self.length == 1) {
return [self capitalizedString];
}
else {
NSString *firstChar = [self substringToIndex:1];
NSString *otherChars = [self substringWithRange:NSMakeRange(1, self.length - 1)];
return [NSString stringWithFormat:#"%#%#", [firstChar uppercaseString], [otherChars lowercaseString]];
}
}
Just for adding some options, I use this category to capitalize the first letter of a NSString.
#interface NSString (CapitalizeFirst)
- (NSString *)capitalizeFirst;
- (NSString *)removeDiacritic;
#end
#implementation NSString (CapitalizeFirst)
- (NSString *)capitalizeFirst {
if ( self.length <= 1 ) {
return [self uppercaseString];
}
else {
return [[[[self substringToIndex:1] removeDiacritic] uppercaseString] stringByAppendingString:[[self substringFromIndex:1] removeDiacritic]];
// Or: return [NSString stringWithFormat:#"%#%#", [[[self substringToIndex:1] removeDiacritic] uppercaseString], [[self substringFromIndex:1] removeDiacritic]];
}
}
- (NSString *)removeDiacritic { // Taken from: http://stackoverflow.com/a/10932536/1986221
NSData *data = [NSData dataUsingEncoding:NSASCIIStringEncoding
allowsLossyConversion:YES];
return [[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding];
}
#end
And then you can simply call:
NSString *helloWorld = #"hello world";
NSString *capitalized = [helloWorld capitalizeFirst];
NSLog(#"%# - %#", helloWorld, capitalized);
I've been trying to use UITextChecker to see if a word inside a string is, in fact, actually a word. I've pieced the code together using examples I've found online, but I don't really understand it, and it's a bit above my level. Can anyone help me figure out how to check if a word in a string is really a word? I'm still learning all of this so thanks a ton!
-(IBAction)pushButton:(id)sender{
label.text = textField.text;
NSString * currentWord;
currentWord = label.text;
NSRange range = NSMakeRange(0, 0);
range = [textChecker rangeOfMisspelledWordInString:[currentWord lowercaseString]
range:NSMakeRange(0, [currentWord length])
startingAt:0
wrap:NO
language:#"en_US"];
if (range.location == NSNotFound) {
NSLog(#"Word found");
}
else {
NSLog(#"Word not found");
}
}
UPDATE: I'm still having trouble with this, as my log is showing "Word not found" no matter what I put in the textfield. I wanted to post my .h file as well to see if something is incorrect. Also here is a link to where I received the original code, in case that helps. Thanks again.
#import <UIKit/UIKit.h>
#import <UIKit/UITextChecker.h>
#interface CheckIfWordViewController : UIViewController {
IBOutlet UILabel * label;
IBOutlet UITextField * textField;
IBOutlet UIButton * button;
UITextChecker * textChecker;
}
#property (retain, nonatomic) UITextChecker * textChecker;
#property (retain, nonatomic) UIButton * button;
#property (retain, nonatomic) UILabel * label;
#property (retain, nonatomic) UITextField * textField;
-(IBAction)pushButton:(id)sender;
#end
I got caught out by UITextChecker always returning NSNotFound even for misspelled words because I was feeding it CAPs only words. A slight problem for rookies solved by submitting [currentWord lowercaseString]. I also discovered from researching this that words over 25 characters will also return NSNotFound irrespective of incorrect spelling.
Your code looks like it is passing one word to rangeOfMisspelledWordInString - I think you want to use the whole string and use the returned NSRange to identify which word in particular UITextChecker thinks is misspelled. So instead of currentWord, pass the whole string. If nothing is misspelled you get range.location == NSNotFound as you worked out.
A word check is only as good as the dictionary you check against. I believe it was Don Knuth who devised this method for checking words:
Get dictionary
Create copy of dictionary with all entries sorted so that sorted word index matches unsorted word index
Sort candidate word
Find sorted candidate word in sorted dictionary
Index (and there may be multiples) of match is your word.
In your case you only care if there are zero matches or otherwise. If there is at least one match you have a valid word.
I do not know exactly what dictionaries UITextChecker uses but nothing will annoy people more than rejecting a correct word... especially if they consider their word a bit obscure and themselves clever for using it. Using an all-encompassing dictionary like the official Scrabble reference will avoid that problem.
Your code looks correct, I guess from your question you want it explained?
label.text = textField.text;
This line takes the text entered in textField (which is presumably a UITextField) and assigns it to the text property of label (which is presumably a UILabel). It has nothing to do with the spell checking per se.
NSString * currentWord;
currentWord = label.text;
This copies the text string back out of the label's text property.
NSRange range = NSMakeRange(0, 0);
This declares an NSRange struct, and initializes it to an empty value. Not really necessary, since the next line will change it anyway.
range = [textChecker rangeOfMisspelledWordInString:[currentWord lowercaseString]
range:NSMakeRange(0, [currentWord length])
startingAt:0
wrap:NO
language:#"en_US"];
This is the line that actually does the work.
You're searching for misspelled words in the text string from earlier. It lowercases it for good measure, I don't know if that's strictly necessary.
range:NSMakeRange(0, [currentWord length]) specifies that the entire string (from character 0 to the length of the string) should be searched.
startingAt:0 specifies that it should start from the beginning of the range. The use of this would be in a loop, after finding the first misspelled word you'd tell it to start after the end of the word to find another.
wrap:NO tells it not to start over from the beginning of the range if a misspelled word. Not that that matters here.
`language:#"en_US" tells it to use the built-in US English dictionary.
There doesn't seem to be any way to specify a custom dictionary, BTW.
if (range.location == NSNotFound) {
NSLog(#"Word found");
}
else {
NSLog(#"Word not found");
}
This just checks the result. If a misspelled word were found, range.location would be the start of the word and range.length would be the length. If all the words are spelled correctly, range.location will be NSNotFound and range.length will be 0.
Where are you allocating the UITextChecker? In the controller's init method, I assume? Just checking, because the solution works for me, with one alteration: instead of passing #"en_us" into the rangeOfMisspelledWords... method I do the following:
UITextChecker* checker = [[UITextChecker alloc] init];
NSString* preferredLang = [[UITextChecker availableLanguages] objectAtIndex:0];
NSRange range;
range = [checker rangeOfMisspelledWordInString:currentWord
range:NSMakeRange(0, [currentWord length])
startingAt:0
wrap:NO
language:preferredLang];
Followed by the same if-statement you use. The solution works, and will also work for users of other languages without change, should you decide to localize your app.
Perhaps for whatever reason the #"en_US" you're using is not the correct string to pass? It seems right though.
Probably you have forgotten ALLOC/INIT for UITextChecker
Works in this way:
- (IBAction)CheckWord:(id)sender
{
UITextChecker *Checker = [[UITextChecker alloc] init];
NSRange range = [Checker rangeOfMisspelledWordInString:[_Word.text lowercaseString]
range:NSMakeRange(0, [_Word.text length])
startingAt:0 wrap:NO
language:#"it_IT"];
if ( range.location == NSNotFound ) {
_Esito.text = #"Word found";
}
else {
_Esito.text = #"Word not found";
}
[Checker release];
}
For languages, use
NSLog(#"%#", [UITextChecker availableLanguages]);
hope this helps.
I just started Objective-C recently, and this has once again gotten me to the point of asking SO for help. I need to rewrite this method so that I can call it using [self URLEncodedString];
This is what the method currently looks like -
- (NSString *)URLEncodedString {
NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR("!*'();:#&=+$,/?%#[]"), kCFStringEncodingUTF8);
[result autorelease];
return result;
}
But I can't call it like [self URLEncodedString]; How can I rewrite it so that it would work for me to be able to call it using [self URLEncodedString];?
P.S. Calling it via [strValue URLEncodedString]; doesn't work, hence the reason I'm making this post.
Thanks for any help!
I think what you're asking for is to create an NSString category which will encode your string.
You need to create a new set of files, name them something that makes sense (NSString+URLEncoding).
In the .h file, you'll need something like this:
#interface NSString (URLEncoding)
- (NSString*)URLEncodedString;
#end
Then in your .m file:
#implementation NSString (URLEncoding)
- (NSString *)URLEncodedString {
NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR("!*'();:#&=+$,/?%#[]"), kCFStringEncodingUTF8);
[result autorelease];
return result;
}
#end
When you want to use this method, you'll need to make sure you import "NSString+URLEncoding.h".
You can then do something like this:
NSString * firstString = #"Some string to be encoded %&^(&(!#£$%^&*";
NSString * encodedString = [firstString URLEncodedString];
Hope that helps.
Why not just use the NSString instance method stringByAddingPercentEscapesUsingEncoding?