I am trying to create an app in which random words are generated, however I want abbreviations to be ignored when they are created. To do this i randomly generate an array of letters, (Weighting them with the same weighting as scrabble ;P) and then run through the array checking for correct words using UITextChecker like so:
for (int i = 0; i < 14; i++) {
[word setString:#""];
for (int j = i; j < 14 ;j++) {
[word appendString:[letterArray objectAtIndex:j]];
NSRange misspelledWord = [checkText rangeOfMisspelledWordInString:word range:NSMakeRange(0, word.length) startingAt:0 wrap:NO language:#"en_GB"];
if (misspelledWord.location == NSNotFound && word.length > 2) {
NSRange misspelledWordSecondRun = [checkText rangeOfMisspelledWordInString:word range:NSMakeRange(0, word.length) startingAt:0 wrap:NO language:#"en_US"];
if (misspelledWordSecondRun.location == NSNotFound) {
NSLog(#"You generated the word: %#",word);
}
}
else {
}
}
}
The only problem is that this lets a ridiculous amount of abbreviations and acronyms through... is there any way I can reduce this number? There must be a language that I can send checkText which is an abbreviation free version of the english dictionary? Or some way of telling it to flag acronyms as misspelled words? As you can see I have tried to reduce the number by filtering the words a second time using us english rather than uk english, however this doesn't reduce the number of acronyms being let through at all :/
Implemented this using an array of words that I didn't want to include, each time a word is generated it checks to see if it's in this array. If it is it doesn't register it as a word, if it isn't it doesn't.
Related
I have a game that renders the player's nickname.
Normally, I use a nice, styled, bitmap font to render the nickname. However, I only have bitmaps for "normal" characters - A,B,C,...,1,2,3,...!##$%^,.... There are no bitmaps for Chinese, Japanese or whatever other "fancy" characters in any other language.
Trying to render such text with a bitmap will crash because I don't supply such bitmaps. Therefore I decided to detect whether the given string was a "fancy" string, and if that was the case, render the nickname using some generated system font.
How can I detect if a string has fancy characters? My current solution is something like
-(BOOL)isNormalText:(NSString *)text {
char accepted[] = {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!##$%^&*()_+{}/\\\"\'?.,"};
for (int i = 0; i < [text length]; ++i) {
char character = [text characterAtIndex:i];
BOOL found = NO;
for (int j = 0; j < 84 && !found; ++j) {
char acceptedChar = accepted[j];
if (character == acceptedChar) {
found = YES;
}
}
if (!found) {
return NO;
}
}
return YES;
}
Which does NOT work, I think. Because a fancy character is not one character - it is a sequence like "\u123".
I have seen a question, in Java, about something similar here: How to check if the word is Japanese or English?
They check if the character value is within the 255 range. But when I do this check in Objective-C, it tells me it is redundant because a char will always be within such range - which makes sense as I imagine the fancy characters to be actually a sequence like "\u123"...
Use an NSCharacterSet, fill it with the characters that you have bitmaps for, then invert the set so that it represents all characters that you don't have. Then use -[NSString rangeOfCharacterFromSet:]. If it returns NSNotFound then the string contains only valid characters.
Just as an example to illustrate what I mean:
- (BOOL) isNormalText:(NSString *) str
{
if (str == nil)
return NO;
NSCharacterSet *allowedChars = [NSCharacterSet characterSetWithCharactersInString:#"ABCDEFG"];
NSCharacterSet *notAllowedChars = [allowedChars invertedSet];
return [str rangeOfCharacterFromSet:notAllowedChars].location == NSNotFound;
}
Use regular expression checking
-(BOOL)isNormalText:(NSString *)text {
NSString * regex = #"(^[A-Za-z0-9]*$)";
NSPredicate * pred = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
BOOL isMatch = [pred evaluateWithObject:text];
return isMatch;
}
I am trying to make a simple calculator app. Currently, the app works perfectly. One problem: It's smart enough to change results into formatted numbers (800000 = 800,000), but not full expressions (200*600/21000 = 200*600/21,000).
I would like to be able to have a method that I could feed a string and get back a string of properly formatted numbers with operations still inside the string.
Example:
I feed the method 30000/80^2. Method gives back 30,000/80^2.
EDIT: People seem to be misunderstanding the question (Or it's possible I am misunderstanding the answers!) I want to be able to separate the numbers - 60000/200000 would separate into 60000 & 200000. I can do it from there.
Well, what's the problem? You obviously can parse the whole expression (you say calculator works), you can format single numbers (you say you can format results).
The only thing you need is to parse the expression, format all the numbers and recompose the expression...
EDIT: There is a simpler solution. For formatting, you don't need to parse the expression into a tree. You just have to find the numbers.
I suggest to create character set of all operators
NSCharacterSet* operators = [NSCharacterSet characterSetWithCharactersInString:#"+*-/^()"];
NSCharacterSet* whitespaces = [NSCharacterSet whitespaceCharacterSet];
Then split the expression using this set:
NSString* expression = [...];
NSMutableString* formattedExpression = [NSMutableString string];
NSRange numberRange = NSMakeRange(0, 0);
for (NSUInteger i = 0; i < expression.length; i++) {
unichar character = [expression characterAtIndex:i];
if ([whitespaces characterIsMember:character] || [operators characterIsMember:character]) {
if (numberRange.length > 0) {
NSString* number = [expression substringWithRange:numberRange];
NSString* formattedNumber = [self formatNumber:number];
[formattedExpression appendString:number];
numberRange.length = 0;
}
}
else if (numberRange.length == 0) {
numberRange.location = i;
numberRange.length = 1;
}
else {
numberRange.length++;
}
if ([operators characterIsMember:character]) {
[formattedExpression appendFormat:#"%C", character];
}
}
if (numberRange.length > 0) {
NSString* number = [expression substringWithRange:numberRange];
NSString* formattedNumber = [self formatNumber:number];
[formattedExpression appendString:number];
}
Note that this should work even for numbers prefixed by a sign. I am ignoring all whitespaces because if you want to have a pretty expression, you probably want to handle whitespaces differently (e.g. no space after (, space before +/-, space after - only if it's not a number sign...). In general, for handling spaces, parsing the expression into a tree would simplify matters. Also note that infix expressions are not unambiguous - that means that you should sometimes add parenthesis. However, that can't be done without parsing into a tree.
Look up NSNumberFormatter. Not only will that handle formatting of numbers, it will do so based on the user's locale.
I am searching for an algorithm where I can compare two strings and read out the failers.
I know the normal code to compare two strings but this isn't enough.
Example:
NSString *userinput = #"xaplseiPhonr";// (Input from the user)
NSString *correct =#"apple iphone";
In the next step i would check this strings and put out the failers for this example: x,l,s, ,r = 5 failers
I tested many things, saved the two strings in an array with two for-loops and compared it but something is wrong, the hardest thing is if the word has 2 letters that are the same. Or if you have no dynamic index search then are the whole letters after the "l" or the missing space in the userinput false, and so on.
So, It would be nice if anyone has fine code for me
edit: code to compare, but this doesn't work if you missed a letter or space.
for (int i = 0; i < [originalWordLetters count]; i++)
{
NSString *originalLetter = [originalWordLetters objectAtIndex:i];
//NSLog(#"%i: %#", d, originalLetter);
BOOL letterFound = FALSE;
while (letterFound == FALSE && d < [userWordLetters count])
{
if ([originalLetter caseInsensitiveCompare:[userWordLetters objectAtIndex:d]] == NSOrderedSame)
{
//NSLog(#"letter %i correct", d+1);
letterFound = TRUE;
}
else
{
//NSLog(#"letter %i false", d+1);
failedLetters++;
}
d++;
}
}
I have a working algorithm where you can compare two strings. And put out the mistakes
I've uploaded the sample project to GitHub:
NSString compareTwoStrings: algorithm outputs the mistakes
What you want to do is compute the Damerau-Levenshtein distance between two strings. Here is an open source implementation for NSString: GitHub JanX2/NSString-DamerauLevenshtein
You can use NSScanner to do this.
I'm writing a Mac app that goes through an NSString, and adds all its word to an NSArray (by separating them based on whitespace). Now, I've got the whole system down, but I'm still having one little problem: names (first + last), are added as two different words, and that's bothersome to me.
I thought of a couple solutions to fix this. My best idea was to, before actually adding the words to the array, join two words in a row that are capitalized. Then, through an if statement, determine if a word has two capitals in it, and then split the word and add it as one word. However, I can't find a way to find 2 words in a row with capitals.
Should I be using RegexKitLite (which I'm not familiar with), for example, to find two capitalized words in a row? I've seen this question: Regexp to pull capitalized words not at the beginning of sentence and two adjacent words
which seems somehow related, but due to my lack of understand of regular expressions, I don't really know if this is exactly what I need.
I've also seen this: Separating NSString into NSArray, but allowing quotes to group words
which is also similar, yet not exactly adapted to my needs.
So, to conclude, does anyone know how to either join capitalized words in an NSString, or even better, how to find two capitalized words in a row in an NSString ?
If you're targeting iOS 4.0 or greater OR OS 10.7 you can use NSRegularExpression
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"[A-Z]\\w*\\s[A-Z]\\w*"
options:nil
error:&error];
NSString *inputString = #"One two Three Four five six Seven Eight";
NSArray *stringsWithTwoCapitalizedWordsInARow = [regex
matchesInString:inputString
options:0
range:NSMakeRange(0, [string length])];
You'll get something like this
["Three Four", "Seven Eigth"]
You could just do a second pass on the resulting array after it has been loaded to append entries together that need to be joined.
Names are notoriously difficult to match with regular expressions alone, as it is not unheard of for names (first or last) to contain spaces themselves.
NSMutableArray* words = ...;
NSMutableArray* joinedWords = [NSMutableArray array];
for (int i=0; i < [words length]; i++)
{
NSString* currentLine = [words objectAtIndex:i];
bool capitalized = false;
bool capitalizedNext = false;
capitalized = isCap(currentLine); // Up to your discretion here
NSString* nextLine = nil;
// for the last entry
if (i+1 < [words length])
{
nextLine = [words objectAtIndex:i+1];
capitalizedNext = isCap(nextLine);
}
// Check if first letter is uppercase
if (capitalized == true && capitalizedNext == true)
{
[words replaceObjectAtIndex:i withObject:[NSString stringWithFormat:#"%# %#", currentLine, nextLine];
[words removeObjectAtIndex:i+1];
// Run test again on new version of the line
i--;
}
else
{
[joinedWords addObject:currentLine];
}
}
[A-Z][A-Za-z]* [A-Z][A-Za-z]*|[\S]*
http://rubular.com/r/DrOabOAfBr
I've written a regular expression for you. This regex will try to match a name first, then fall back to a word, so your job is as simple as feeding this into NSRegularExpression, and take all the matches as your words, or names joined.
I'm writing a simple shift cipher iPhone app as a pet project, and one piece of functionality I'm currently designing is a "universal" decryption of an NSString, that returns an NSArray, all of NSStrings:
- (NSArray*) decryptString: (NSString*)ciphertext{
NSMutableArray* theDecryptions = [NSMutableArray arrayWithCapacity:ALPHABET];
for (int i = 0; i < ALPHABET; ++i) {
NSString* theNewPlainText = [self decryptString:ciphertext ForShift:i];
[theDecryptions insertObject:theNewPlainText
atIndex:i];
}
return theDecryptions;
}
I'd really like to pass this NSArray into another method that attempts to spell check each individual string within the array, and builds a new array that puts the strings with the fewest typo'd words at lower indicies, so they're displayed first. I'd like to use the system's dictionary like a text field would, so I can match against words that have been trained into the phone by its user.
My current guess is to split a given string up into words, then spell check each with NSSpellChecker's -checkSpellingOfString:StartingAt: and using the number of correct words to sort the Array. Is there an existing library method or well-accepted pattern that would help return such a value for a given string?
Well, I found a solution that works using UIKit/UITextChecker. It correctly finds the user's most preferred language dictionary, but I'm not sure if it includes learned words in the actual rangeOfMisspelledWords... method. If it doesn't, calling [UITextChecker hasLearnedWord] on currentWord inside the bottom if statement should be enough to find user-taught words.
As noted in the comments, it may be prudent to call rangeOfMisspelledWords with each of the top few languages in [UITextChecker availableLanguages], to help multilingual users.
-(void) checkForDefinedWords {
NSArray* words = [message componentsSeparatedByString:#" "];
NSInteger wordsFound = 0;
UITextChecker* checker = [[UITextChecker alloc] init];
//get the first language in the checker's memory- this is the user's
//preferred language.
//TODO: May want to search with every language (or top few) in the array
NSString* preferredLang = [[UITextChecker availableLanguages] objectAtIndex:0];
//for each word in the array, determine whether it is a valid word
for(NSString* currentWord in words){
NSRange range;
range = [checker rangeOfMisspelledWordInString:currentWord
range:NSMakeRange(0, [currentWord length])
startingAt:0
wrap:NO
language:preferredLang];
//if it is valid (no errors found), increment wordsFound
if (range.location == NSNotFound) {
//NSLog(#"%# %#", #"Valid Word found:", currentWord);
wordsFound++;
}
else {
//NSLog(#"%# %#", #"Invalid Word found:", currentWord);
}
}
//After all "words" have been searched, save wordsFound to validWordCount
[self setValidWordCount:wordsFound];
[checker release];
}