Way to have UITextChecker suggest learned words? - ios

I would like to add words to the Apple Dictionary used by UITextChecker, and I am aware of the learnWords: method. It's documentation, and my experience with it, suggest that it only serves to ignore words that are learned. What I would like, and what seems obvious, would be to have learned words also provided as guesses and completions provided by the UITextChecker. Is that possible?
Here's the code I'm starting with:
NSString *newWord = [NSString stringWithFormat:#"%#", #"xyz"];
if ([UITextChecker hasLearnedWord:newWord]) {
NSLog(#"skipped %#", newWord);
} else {
[UITextChecker learnWord:newWord];
NSLog(#"learning %#", newWord);
}
A user might enter "xyj" into a search field, which would prompt this code to run:
// Fake User Input
NSString *word = #"xyj";
UITextChecker *checker = [[UITextChecker alloc] init];
NSRange range = NSMakeRange(0, word.length);
NSArray *guesses = [checker guessesForWordRange:range inString:word language:#"en_US"];
for (NSString *guess in guesses) {
if ([guess isEqualToString:#"xyz"]) {
NSLog(#"Success, iOS suggested xyz!");
}
}

Related

How to check if NSString has a URL with a specific address

I've been searching and trying different things, but come up short handed.
I am trying to take a URL that someone has copied i.e.: https://website/u/drksndrs and compare it with an if statement basically saying if copied string matches https://website/u/ prefix then go ahead with the program. Searching for different users based on their ID after u/. Here is the code I have right now.
NSString *latest = [UIPasteboard generalPasteboard].string;
NSString *prefix = #"https://www.website.com/u/";
NSRange textRange = [latest rangeOfString:prefix];
if (textRange.location != NSNotFound) {
NSLog(#"the prefix matches!");
[self performOperation];
} else {
NSLog(#"This doesn't match the https://www.website.com/u/ prefix.");
}
You should be checking if textRange.location == 0 to see if it is a prefix. Better yet, use the hasPrefix: method.
NSString *latest = [UIPasteboard generalPasteboard].string;
NSString *prefix = #"https://www.website.com/u/";
if ([latest hasPrefix:prefix]) {
NSLog(#"the prefix matches!");
[self performOperation];
} else {
NSLog(#"This doesn't match the https://www.website.com/u/ prefix.");
}

Ignore words beginning with a hashtag or mention

Please forgive me for my noobness but I am having trouble building a pattern to ignore words beginning with a hashtag # or a mention symbol #. I know that to select words beginning with hashtags I can do #(\w+) and to select words beginning with mentions I can do #(\w+).
I tried doing something like this (?!#(\w+)) to ignore the mentions and this (?!#(\w+)) to ignore hashtags but no luck. I'll keep trying and searching any help is appreciated.
I want to create a pattern that: !(hashtags) AND !(mentions)
Or a pattern that selects only words.
Try this:
NSMutableArray *words = [[text componentsSeparatedByString:#" "] mutableCopy];
for (NSString *word in words)
{
NSString *firstCharacter = [word substringToIndex:1];
if ([firstCharacter isEqual:#"#"] || [firstCharacter isEqual:#"#"])
{
// remove the word from the array here or whatever
[words removeObject:word];
}
}
Here is the solution that worked for me based on the answer provided by freshking
- (NSMutableArray *) checkForWords:(UITextField *)textField {
NSMutableArray *words = [[NSMutableArray alloc] initWithArray:[[textField.text componentsSeparatedByString:#" "] mutableCopy]];
NSMutableArray *matches = [[NSMutableArray alloc] init];
//NSLog(#"words: %#",words);
for (NSString *word in words) {
NSString *firstCharacter = [word substringToIndex:1];
if (![firstCharacter isEqual:#"#"] && ![firstCharacter isEqual:#"#"]) {
[matches addObject:word];
}
}
return matches;
}

How to filter search within a set of letters in search bar so that each letter typed will reduce the results in objective -c

i have implemented a search bar that searching trough an array of countries(presented in a picker view), the problem is that the user need to type the full country name that it will find it and i want him to be able to type even one letter and it will show the first country that starts with that letter and if types another than it sorts even further etc etc.
Anyone have any ideas??
for(int x = 0; x < countryTable.count; x++){
NSString *countryName = [[countryTable objectAtIndex:x]objectForKey:#"name"];
if([searchedStr isEqualToString:countryName.lowercaseString]){
[self.picker selectRow:i inComponent:0 animated:YES];
flag.image = [UIImage imageNamed:[[countryTable objectAtIndex:i]objectForKey:#"flag"]];
}
}
There's a method on NSArray called filteredArrayUsingPredicate: and a method on NSString called hasPrefix:. Together they do what you need...
NSString *userInput = //... user input as lowercase string. don't call this countryName, its confusing
NSPredicate *p = [NSPredicate predicateWithBlock:^BOOL(id element, NSDictionary *bind) {
NSString countryName = [[element objectForKey:#"name"] lowercaseString];
return [countryName hasPrefix:userInput];
}];
NSArray *filteredCountries = [countryTable filteredArrayUsingPredicate:p];
If you're on iOS 8 or OS X Yosemite, you can do:
NSString *country = countryName.lowercaseString; //"england"
NSString *needle = #"engl";
if (![country containsString:needle]) {
NSLog(#"Country string does not contain part (or whole) of searched country");
} else {
NSLog(#"Found the country!");
}
Else, if on versions below iOS 8:
NSString *country = countryName.lowercaseString; //"england"
NSString *needle = #"engl";
if ([country rangeOfString:needle].location == NSNotFound) {
NSLog(#"Country string does not contain part (or whole) of searched country");
} else {
NSLog(#"Found the country!");
}
Lastly, just iterate through all possible countries and apply this to them all. There might exist more robust solutions out there (like danh's solution with some smaller modifications), but this is by far the easiest to start with.

Search for any characters in an NSString

I have the following code to search an NSString:
for (NSDictionary *obj in data) {
NSString *objQuestion = [obj objectForKey:#"Question"];
NSRange dataRange = [objQuestion rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (dataRange.location != NSNotFound) {
[filteredData addObject:obj];
}
}
This works fine, but there is a problem. If objQuestion is: "Green Yellow Red" and I search for "Yellow Green Red", the object will not show up as my search is not in the correct order.
How would I change my code so that no matter what order I search the words in, the object will show?
You should be breaking your search text into words and search each word.
NSArray *wordArray= [searchText componentsSeparatedByString: #" "];
for (NSDictionary *obj in data) {
NSString *objQuestion = [obj objectForKey:#"Question"];
BOOL present = NO;
for (NSString *s in wordArray) {
if (s) {
NSRange dataRange = [objQuestion rangeOfString:s options:NSCaseInsensitiveSearch];
if (dataRange.location != NSNotFound) {
present = YES;
}
}
}
if (present) {
[filteredData addObject:obj];
}
}
So you want to basically do a keyword search? I would recommend doing a regular expression search. where the words can be in any order.
Something like this.
(your|test|data)? *(your|test|data)? *(your|test|data)?
Which you can use in a NSRegularExpressoin
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(your|test|data)? *(your|test|data)? *(your|test|data)?" options:NSRegularExpressionCaseInsensitive error:&error];
int numMatches = [regex numberOfMatchesInString:searchString options:0 range:NSMakeRange(0, [searchString length])];];
This will match any ordering in an efficient manner.
Not sure if regex is okay for Obj C, because I do not have a mac in front of me right now, but it should be okay.
You might want to consider that the search input string is not always as clean as you expect, and could contain punctuation, brackets, etc.
You'd also want to be lax with accents.
I like to use regular expressions for this sort of problem, and since you are looking for a solution that allows arbitrary ordering of the search terms, we'd need to re-work the search string. We can use regular expressions for that, too - so the pattern is constructed by a regex substitution, just out of principle. You may want to document it thoroughly.
So here is a code snippet that will do these things:
// Use the Posix locale as the lowest common denominator of locales to
// remove accents.
NSLocale *enLoc = [[NSLocale alloc] initWithLocaleIdentifier: #"en_US_POSIX"];
// Mixed bag of genres, but for testing purposes we get all the accents we need
NSString *orgString = #"Beyoncé Motörhead Händel";
// Clean string by removing accents and upper case letters in Posix encoding
NSString *string = [orgString stringByFoldingWithOptions: NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch
locale: enLoc ];
// What the user has typed in, with misplaced umlaut and all
NSString *orgSearchString = #"handel, mötorhead, beyonce";
// Clean the search string, too
NSString *searchString = [orgSearchString stringByFoldingWithOptions: NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch
locale: enLoc ];
// Turn the search string into a regex pattern.
// Create a pattern that looks like: "(?=.*handel)(?=.*motorhead)(?=.*beyonce)"
// This pattern uses positive lookahead to create an AND logic that will
// accept arbitrary ordering of the words in the pattern.
// The \b expression matches a word boundary, so gets rid of punctuation, etc.
// We use a regex to create the regex pattern.
NSString *regexifyPattern = #"(?w)(\\W*)(\\b.+?\\b)(\\W*)";
NSString *pattern = [searchString stringByReplacingOccurrencesOfString: regexifyPattern
withString: #"(?=.*$2)"
options: NSRegularExpressionSearch
range: NSMakeRange(0, searchString.length) ];
NSError *error;
NSRegularExpression *anyOrderRegEx = [NSRegularExpression regularExpressionWithPattern: pattern
options: 0
error: &error];
if ( !anyOrderRegEx ) {
// Regex patterns are tricky, programmatically constructed ones even more.
// So we check if it went well and do something intelligent if it didn't
// ...
}
// Match the constructed pattern with the string
NSUInteger numberOfMatches = [anyOrderRegEx numberOfMatchesInString: string
options: 0
range: NSMakeRange(0, string.length)];
BOOL found = (numberOfMatches > 0);
The use of the Posix locale identifier is discussed in this tech note from Apple.
In theory there is an edge case here if the user enters characters with a special meaning for regexes, but since the first regex removes non-word characters it should be solved that way. A bit of an un-planned positive side effect, so could be worth verifying.
Should you not be interested in a regex-based solution, the code folding may still be useful for "normal" NSString-based searching.

How to get user interests from the native iOS Facebook SDK?

I've been reading through the documentation, and I couldn't find anything. For other properties like name, id, etc, they're available in the FBGraphUser class. What I need though is the interest list for the user. I believe I have to use the FBGraphObject class, but I'm not really sure how to go about doing so. Any guidance would be very appreciated. Thanks!
me/interests is how you get the interests of the user. if you're looking for someone else, like the user's friend, then id/interests
This counts on the user being signed in
-(void)fbRequest{
[FBRequestConnection startWithGraphPath:#"me/interests" completionHandler:^(FBRequestConnection *connection,NSDictionary<FBGraphObject> *result,NSError *error){
if(!error){
NSArray *data = [result objectForKey:#"data"];
[self updateInterests:data];
}else{
}
}];
}
-(void)updateInterests:(NSArray*)interests
{
NSString *str = self.groupList.text;
for(FBGraphObject <FBGraphUser>*interest in interests) //Using FBGraphUser because it implements name though I'd love to use something else
{
str = [str stringByAppendingFormat:#"%#\n",interest.name ];
}
[self.groupList setText:str];
}
an alternative to the above method does not rely on the coincidence that graphuser has name, so here it is
-(void)updateInterests:(NSArray*)interests
{
NSString *str = self.groupList.text;
for(FBGraphObject *interest in interests) //Using FBGraphUser because it implements name though I'd love to use something else
{
str = [str stringByAppendingFormat:#"%#\n",[interest objectForKey:#"name"] ];
}
[self.groupList setText:str];
}

Resources