Restrict user to only entering one word in UITextField - objective-c

Is there a way to only allow the user enter one word in the UITextField? If so, how?
Here's the current code that I'm using:
-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
_disallowedCharacters = [NSCharacterSet whitespaceCharacterSet];
for(int i = 0; i < [_searchBox.text length]; i++){
unichar c = [_searchBox.text characterAtIndex:i];
if (![_disallowedCharacters characterIsMember:c])
{
return NO;
}
}
return YES;
}

Use the UITextFieldDelegate protocol:
- (BOOL) textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)textEntered
{
for (int i = 0; i < [textEntered length]; i++)
{
unichar c = [textEntered characterAtIndex:i];
if ([disallowedCharacters characterIsMember:c])
{
return NO;
}
}
return YES;
}
where disallowedCharacters is an NSCharacterSet containing the characters that should not be accepted by the keyboard, i.e. a space, punctuation, numbers, etc:
self.disallowedCharacters = [NSCharacterSet characterSetWithCharactersInString:#" ,.123"];

For a character set (for Evan's answer) that checks against whitespace and newlines, you can use
self.disallowedCharacters = [NSCharacterSet whitespaceAndNewlineCharacterSet];
If you want to check against characters besides whitespace and newlines, create a mutableCopy and add whatever you'd like to it:
NSMutableCharacterSet *set = [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy];
[set formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
[set formUnionWithCharacterSet:[NSCharacterSet symbolCharacterSet];
[set addCharactersInString:#"whatever you want"];
...
self.disallowedCharacters = [[set copy] autorelease];
[set release];
The NSCharacterSet docs have a good overview of the character sets available to you.

Related

Restricting NSTextField input to alpha-numeric

I'm making a simple app in which there is an NSTextField and I want only alpha-numeric characters in it while typing.
Can anyone suggest an approach to this please?
There's a built-in support for that.
In Interface Builder check "Only Roman Characters" option for the text field.
OR
In your code set this property:
[myTextField.cell setAllowedInputSourceLocales: #[NSAllRomanInputSourcesLocaleIdentifier]];
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([self validCharecter:textField.text){
return YES;
}
else{
return NO:
}
}
-(BOOL)validCharecter :(NSString)textStr{
NSCharacterSet *alphaSet = [NSCharacterSet alphanumericCharacterSet];
BOOL validStr = [[textStr stringByTrimmingCharactersInSet:alphaSet] isEqualToString:#""];
return validStr;
}
Try with dis hope it will helps you!!
Take a look at below code sample.
I hope this will help you.
//#define CHARACTERS #" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
//#define CHARACTERS_NUMBERS [CHARACTERS stringByAppendingString:#"1234567890"]
///// Inside shouldChangeCharactersInRange
///////////>>>>>>>>>>>>>>>>>>
if(textField== txtFldAlpha)
{
//Alpha only
NSUInteger newLength = [textField.text length] + [string length] - range.length;
NSCharacterSet *unacceptedInput =
[[NSCharacterSet characterSetWithCharactersInString:CHARACTERS] invertedSet];
// Create array of strings from incoming string using the unacceptable
// characters as the trigger of where to split the string.
// If array has more than one entry, there was at least one unacceptable character
if ([[string componentsSeparatedByCharactersInSet:unacceptedInput] count] > 1)
return NO;
else
return YES&&(newLength < 26);
return YES;
}
///////////<<<<<<<<<<<<<<<<<<
///////////>>>>>>>>>>>>>>>>>>
if(textField==txtFldNumeric)
{
//Num only
NSUInteger newLength = [textField.text length] + [string length] - range.length;
NSCharacterSet *nonNumberSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
if ([[string componentsSeparatedByCharactersInSet:nonNumberSet] count] > 1)
return NO;
else
return YES&&(newLength < 6);
return YES;
}
///////////<<<<<<<<<<<<<<<<<<
///////////>>>>>>>>>>>>>>>>>>
if(textField==txtFieldNumAlphaSpecial)
{
//Num,Alpha,Special field
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 50) ? NO : YES;
}
///////////<<<<<<<<<<<<<<<<<<
#define ACCEPTABLE_CHARACTERS #" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_."
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [string isEqualToString:filtered];
}
OR
Implement
textField:shouldChangeCharactersInRange:replacementString:
in the delegate, check the replacement string for special characters, and disallow the replacement if you detect any.
The easiest way to check for non-alphanumerics is as follows:
if ([replacementString rangeOfCharacterFromSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]].location != NSNotFound) {
// There are non-alphanumeric characters in the replacement string
}
Hope this helps mate .. !

Anagram / partial anagram detection algorithm finds incorrect answers

I've written the following method to find out whether a long word contains a shorter word, and the order in which I pass the letters appears to effect the outcome.
I've noticed that if I feed it absconds and bassy it correctly reports NO, but if I alphabetize the letters and give it abcdnoss and abssy, it gives YES. I'm not too sure why this is – can anyone spot the issue?
- (BOOL) does: (NSString* ) longWord contain: (NSString *) shortWord {
while([longWord length] > 0 && [shortWord length] > 0) {
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString: [shortWord substringToIndex: 1]];
if ([longWord rangeOfCharacterFromSet: set].location == NSNotFound) {
return NO;
}
longWord = [longWord substringFromIndex: [longWord rangeOfCharacterFromSet: set].location+1];
shortWord = [shortWord substringFromIndex: 1];
}
return YES;
}
The problem with your algorithm is that this line doesn't work:
longWord = [longWord substringFromIndex: [longWord rangeOfCharacterFromSet: set].location+1];
If the first letter you search is at the end of the long word, then long word becomes an empty string, and you jump out of your loop to YES.
I would use a different algorithm, like this. I think it's easier to see what's going on, and so less prone to errors:
- (BOOL) does: (NSString* ) longWord contain: (NSString *) shortWord {
NSMutableString *longer = [longWord mutableCopy];
for (int i = 0; i<shortWord.length; i++) {
NSString *letter = [shortWord substringWithRange:NSMakeRange(i, 1)];
NSRange letterRange = [longer rangeOfString:letter];
if (letterRange.location != NSNotFound) {
[longer deleteCharactersInRange:letterRange];
}else{
return NO;
}
}
return YES;
}
- (BOOL) does: (NSString* ) longWord contain: (NSString *) shortWord
{
return ([longWord rangeOfString:shortWord].location != NSNotFound);
}

Algorithm to find anagrams Objective-C

I've got an algorithm to find anagrams within a group of eight-letter words. Effectively it's alphabetizing the letters in the longer word, doing the same with the shorter words one by one, and seeing if they exist in the longer word, like so:
tower = eortw
two = otw
rot = ort
The issue here is that if I look for ort in eortw (or rot in tower), it'll find it, no problem. Rot is found inside tower. However, otw is not inside eortw (or two in tower), because of the R in the middle. Ergo, it doesn't think two is found in tower.
Is there a better way I can do this? I'm trying to do it in Objective-C, and both the eight-letter words and regular words are stored in NSDictionaries (with their normal and alphabetized forms).
I've looked at various other posts re. anagrams on StackOverflow, but none seem to address this particular issue.
Here's what I have so far:
- (BOOL) doesEightLetterWord: (NSString* )haystack containWord: (NSString *)needle {
for (int i = 0; i < [needle length] + 1; i++) {
if (!needle) {
NSLog(#"DONE!");
}
NSString *currentCharacter = [needle substringWithRange:NSMakeRange(i, 1)];
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString: currentCharacter];
NSLog(#"Current character is %#", currentCharacter);
if ([haystack rangeOfCharacterFromSet:set].location == NSNotFound) {
NSLog(#"The letter %# isn't found in the word %#", currentCharacter, haystack);
return FALSE;
} else {
NSLog(#"The letter %# is found in the word %#", currentCharacter, haystack);
int currentLocation = [haystack rangeOfCharacterFromSet: set].location;
currentLocation++;
NSString *newHaystack = [haystack substringFromIndex: currentLocation];
NSString *newNeedle = [needle substringFromIndex: i + 1];
NSLog(#"newHaystack is %#", newHaystack);
NSLog(#"newNeedle is %#", newNeedle);
}
}
}
If you use only part of the letters it isn't a true anagram.
A good algorithm in your case would be to take the sorted strings and compare them letter by letter, skipping mis-matches in the longer word. If you reach the end of the shorter word then you have a match:
char *p1 = shorter_word;
char *p2 = longer_word;
int match = TRUE;
for (;*p1; p1++) {
while (*p2 && (*p2 != *p1)) {
p2++;
}
if (!*p2) {
/* Letters of shorter word are not contained in longer word */
match = FALSE;
}
}
This is one that approach I might take for finding out if one ordered word contained all of the letters of another ordered word. Note that it won't find true anagrams (That simply requires the two ordered strings to be the same) but this does what I think you're asking for:
+(BOOL) does: (NSString* )longWord contain: (NSString *)shortWord {
NSString *haystack = [longWord copy];
NSString *needle = [shortWord copy];
while([haystack length] > 0 && [needle length] > 0) {
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString: [needle substringToIndex:1]];
if ([haystack rangeOfCharacterFromSet:set].location == NSNotFound) {
return NO;
}
haystack = [haystack substringFromIndex: [haystack rangeOfCharacterFromSet: set].location+1];
needle = [needle substringFromIndex: 1];
}
return YES;
}
The simplest (but not most efficient) way might be to use NSCountedSet. We can do this because for counted sets, [a isSubsetOfSet:b] return YES if and only if [a countForObject:object] <= [b countForObject:object] for every object in a.
Let's add a category to NSString to do it:
#interface NSString (lukech_superset)
- (BOOL)lukech_isSupersetOfString:(NSString *)needle;
#end
#implementation NSString (lukech_superset)
- (NSCountedSet *)lukech_countedSetOfCharacters {
NSCountedSet *set = [NSCountedSet set];
[self enumerateSubstringsInRange:NSMakeRange(0, self.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[set addObject:substring];
}];
return set;
}
- (BOOL)lukech_isSupersetOfString:(NSString *)needle {
return [[needle lukech_countedSetOfCharacters] isSubsetOfSet:[self lukech_countedSetOfCharacters]];
}
#end

How to enter Numbers only in UITextField and limit maximum length?

In UITextField we Enter Numeric only and limit up to 3 numeric for this i used below code
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:NUMBERS_ONLY] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
while (newLength < CHARACTER_LIMIT) {
return [string isEqualToString:filtered];
}
/* Limits the no of characters to be enter in text field */
return (newLength > CHARACTER_LIMIT ) ? NO : YES;
}
When i press long press on textfield (like below image )and enter string between two numbers it's allowing all special characters and charterers also.
Not that I don't like the answer I wrote at this question, that was copy & pasted here also. I'll try to explain your error.
This answer is based on the assumption that your constants are defined something like this:
#define NUMBERS_ONLY #"1234567890"
#define CHARACTER_LIMIT 3
The reason your logic is failing is that you never handle the event when newLength will be equal to the CHARACTER_LIMIT.
To illustrate suppose your textfield is empty and you request to paste the string #"ABC" to the textfield, your delegate method is called. You create the string filtered which correctly evaluates to an empty string, and you can't wait to execute the line return [string isEqualToString:filtered]; but you never actually evaluate that line because you don't meet the entry requirements for the while loop, because newLength is 3. so the simple return (newLength > CHARACTER_LIMIT ) ? NO : YES; decides the return value.
If your CHARACTER_LIMIT is actually 4 for some reason, just imagine #"ABCD" as the string the logic still applies.
Here is a simple example of your function corrected to work. Again I'm assuming that CHARACTER_LIMIT is equal to 3.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:NUMBERS_ONLY] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return (([string isEqualToString:filtered])&&(newLength <= CHARACTER_LIMIT));
}
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
// Check for non-numeric characters
NSUInteger lengthOfString = string.length;
for (NSInteger loopIndex = 0; loopIndex < lengthOfString; loopIndex++) {
unichar character = [string characterAtIndex:loopIndex];
if (character < 48) return NO; // 48 unichar for 0
if (character > 57) return NO; // 57 unichar for 9
}
// Check for total length
NSUInteger proposedNewLength = textField.text.length - range.length + string.length;
if (proposedNewLength > 3) return NO;
return YES;
}
Its working fine for me u can use this code
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *s = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"^\\d{0,3}$" options:0 error:nil];
NSTextCheckingResult *match = [regex firstMatchInString:s options:0 range:NSMakeRange(0, [s length])];
return (match != nil);
}
Check the UITextFieldDelegate method
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
This method will be invoked each time after you type/tap a character or press cut/paste and before that action changes the characters displayed. Here you can very well to your check for maxLength and numbers-only text input(by using RegularExpression patter as given below) and return YES or NO basd on that. If you return YES it will do the change otherwise it will not. Hope this clears your doubt.
I prefer using an NSNumberFormatter to validate the text can be parsed into a number. NSNumberFormatter returns nil if the string cannot be converted to a number. This lets you react to the input (i.e. make text red, throw up a alert)
NSNumber* value = nil;
NSNumberFormatter* format = [[NSNumberFormatter alloc] init];
value = [format numberFromString:someValueString];//returns and
if (value == nil){
//do something useful i.e. show alert
}

Objective-C: Numbers only text field? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Iphone UITextField only integer
I want to place a text field that only accepts numbers (0-9, doesn't even need decimals), but even using the "Number Pad" entry option I still get a keyboard with various symbols on it. Is there a better control for this, is there a better control for what I'm doing, or do I just have to validate input manually?
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
/* for backspace */
if([string length]==0){
return YES;
}
/* limit to only numeric characters */
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
for (int i = 0; i < [string length]; i++) {
unichar c = [string characterAtIndex:i];
if ([myCharSet characterIsMember:c]) {
return YES;
}
}
return NO;
}
The code is somehow incorrect, should be
/* limit to only numeric characters */
NSCharacterSet* numberCharSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
for (int i = 0; i < [string length]; ++i)
{
unichar c = [string characterAtIndex:i];
if (![numberCharSet characterIsMember:c])
{
return NO;
}
}
return YES;
The following code will allow you to only input numbers as well as limit the amount of characters that can be used.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
/* limit to only numeric characters */
NSCharacterSet *myCharSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
for (int i = 0; i < [string length]; i++) {
unichar c = [string characterAtIndex:i];
if ([myCharSet characterIsMember:c]) {
return YES;
}
}
/* limit the users input to only 9 characters */
NSUInteger newLength = [customTextField.text length] + [string length] - range.length;
return (newLength > 9) ? NO : YES;
}