I am trying to write a function that returns boolean value if given string is in valid fractional format or not.
e. g. fraction numbers are as follows
2/3,
1 2/3,
6/5,
80/20,
60 1/4,
etc.
-(BOOL)validateFraction:(NSString *)string
{
if(string is valid fraction)
return YES;
else
return NO;
}
You can use regular expressions for that:
-(BOOL)validateFraction:(NSString *)string{
NSString *fractionRegex = #"\\d+(/\\d+)?";
NSPredicate *fractionTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", fractionRegex];
return [fractionTest evaluateWithObject:string];
}
P.S. not also, that that function does not validate against division by zero and does not allow fraction to have sign (+ or -) at front
I found a solution which accepts numbers such as 1/210 2/35 6/8etc.
-(BOOL)validateFraction:(NSString *)string{
NSString *fractionRegex = #"[1-9]?[ ]?[0-9]+/[1-9]+";
NSPredicate *fractionTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", fractionRegex];
return [fractionTest evaluateWithObject:string];
}
You can do something like this:
-(BOOL)validateFraction:(NSString *)string
{
if ([string rangeOfString:#"/"].location == NSNotFound) {
return NO;
}
return YES;
}
This code will only see if the string #"/" appears as substring in the given string.
As you can see, this is a very simple solution, and may work if you know that the strings that you want to test are all numerical valid ones. If you want something more robust, that tests for "invalid" strings, just use regular expressions, like in #Vladimir's answer
Related
my requirement for validation is to validate username which allows to enter small a-z,and 0-9, and only two symbol _ and .(dot)
but symbol do not repeat.
and symbol not allowed at the starting of the name.
can any one help me ?? how to do this validation?
i have tried this code but it works fine but it repeats symbol how can i avoid to repeat?
- (BOOL)validateString:(NSString*)stringToSearch
{
NSString *emailRegex = #"[a-z0-9._]{5,15}";
NSPredicate *regex = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegex];
return [regex evaluateWithObject:stringToSearch];
}
Use the following regex to check if the characters are correct:
^([a-z0-9]+[._])*[a-z0-9]+$
Debuggex Demo
Additionally and separately check the string length. (or use lookaheads)
Edit: it seems like I misread some of the requirements. The above regex disallows symbol at the end of the name as well. If you want to allow symbols there, change the regex to
^([a-z0-9]+[._]?)*$
If you use predicates you can omit the leading ^ and trailing $.
Pure regex approach, used lookahead for count, might have other simplified solution
"(?=[a-z0-9._]{5,15})([a-z0-9][._]?)+"
EDIT
Regarding the additional question: What to avoid the user enter rejected characters
Technically you can achieve that by implementing the UITextViewDelegate method textView(_:shouldChangeTextInRange:replacementText:). But it might give the user impression that the keyboard is not responding correctly.
So it might be a better user experience that implementing textViewShouldEndEditing(_:) method with some kind of alert showing the alert.
define Validation #"abcdefghijklmnopqrstuvwxyz0123456789_."
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSCharacterSet *unacceptedInput = nil;
unacceptedInput = [[NSCharacterSet characterSetWithCharactersInString:ALPHA] invertedSet];
if ([[string componentsSeparatedByCharactersInSet:unacceptedInput] count] <= 1) {
int newLength = (int)textField.text.length + (int)string.length - (int)range.length;
if (newLength > 50) {
return false;
} else {
return true;
}
} else {
return false;
}
}
here I had to also put validation for text length not exceed 50 characters in my project so you can remove that condition
I've been facing some issue with to valid string with following condition. The respective conditions are as follows:
String should contain MAX length(which is 7) and should not less Than 6
First character must be from A-Z (should consider aUppercase only)
remaining character must contain only digit (0 to 9).
Here is an example of String I want to valid A12342 (desire output with validation)
Thanks in advance ,Any help will be appreciated.If any one need more information about my query please let me know .
-(BOOL)CheckConditionForValidation
{ if([textfield.text isequalToString:#""]){
return FALSE
}
//else if (//validation for my specific number)
//{
//want to implement logic here
//}
}
Try this rejex pattern [A-Z][0-9]{5,6}
check it online with the link Online rejex check
and if it work than use like this
- (BOOL)checkValidation:(UITextField *)textField
{
NSString *rejex = #"<your pattern>";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", rejex];
//if rejex fullfil than it will return true else false.
return [emailTest evaluateWithObject:textField.text];
}
I've a certain regex pattern to check against.
Valid result is is only Hebrew language, letters, marks etc.
//////////Regex//////////
static NSString *const HEBREW_NUMBERS_NON_NUMERIC_CHAR = #"([\u0590-\u05FF]*|[0-9]*|[\\s]*|[.-:;,?!/&*()+=_'\"]*)+";
+ (BOOL)hasValidOpenLine:(NSString *)openLine
{
if (openLine.length >= MIN_NUMBER_OF_CHARACTERS_IN_OPEN_LINE || openLine.length <= MAX_NUMBER_OF_CHARACTERS_IN_OPEN_LINE) {
NSError *errorRegex;
NSRegularExpression *regexOpenLine = [[NSRegularExpression alloc] initWithPattern:HEBREW_NUMBERS_NON_NUMERIC_CHAR
options:0
error:&errorRegex];
NSRange range = NSMakeRange(0, openLine.length);
if ([regexOpenLine numberOfMatchesInString:openLine options:0 range:range] > 0) {
return YES;
}
}
return NO;
}
But no matter what I type, it always return me YES even for only English string.
There may be two things going wrong here, depending on your test string. First off, the stars in your regex allow for empty matches against strings which would otherwise not match, which is why your regex might match English strings — matching your regex on #"Hello, world!" returns {0, 0}, a range whose location is not NSNotFound, but whose length is zero.
The other issue is that you're not anchoring your search. This will allow the regex to match against singular characters in strings that would otherwise not match (e.g. the , in #"Hello, world!"). What you need to do is anchor the regex so that the whole string has to match, or else the regex rejects it.
Your modified code can look something like this:
static NSString *const HEBREW_NUMBERS_NON_NUMERIC_CHAR = #"([\u0590-\u05FF]|[0-9]|[\\s]|[.-:;,?!/&*()+=_'\"])+";
+ (BOOL)hasValidOpenLine:(NSString *)openLine
{
if (openLine.length >= MIN_NUMBER_OF_CHARACTERS_IN_OPEN_LINE || openLine.length <= MAX_NUMBER_OF_CHARACTERS_IN_OPEN_LINE) {
NSError *errorRegex;
NSRegularExpression *regexOpenLine = [[NSRegularExpression alloc] initWithPattern:HEBREW_NUMBERS_NON_NUMERIC_CHAR
options:0
error:&errorRegex];
if ([regexOpenLine numberOfMatchesInString:openLine options:NSMatchingAnchored range:NSMakeRange(0, openLine.length)] > 0) {
return YES;
}
}
return NO;
}
This will now match against strings like #"שלום!", and not strings like #"Hello, world!" or #"Hello: היי", which is what I assume you're going for.
In the future, if you're looking to debug regexes, use -[NSRegularExpression rangeOfFirstMatchInString:options:range:] or -[NSRegularExpression enumerateMatchesInString:options:range:usingBlock:]; they can help you find matches that may cause your regex to accept unnecessarily.
I would like to limit user input in a UITextField to 1-105. I have set the delegate and have successfully limited the actual number of characters via the following code, found elsewhere on Stackoverflow. Is there something that I can add in order to force the user to input any integer between 1 and 105?
#define MAXLENGTH 2
- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger oldLength = [_startLevel.text length];
NSUInteger replacementLength = [string length];
NSUInteger rangeLength = range.length;
NSUInteger newLength = oldLength - rangeLength + replacementLength;
BOOL returnKey = [string rangeOfString: #"\n"].location != NSNotFound;
return newLength <= MAXLENGTH || returnKey;
}
I am using the number keypad, so the user is already limited to entering numbers. I just need to find something that will make them input something in the range.
Thanks in advance.
First convert the string to a number. In order of ease of use and lack of control, the ways you do that are -[NSString integerValue]*, NSNumberFormatter, and NSScanner. The formatter will give you an NSNumber from which you can then get the integerValue*; the other two get you primitives directly.
Once you have that, compare the number to the endpoints of your range, creating a boolean. Combine that boolean with the other two -- for length and lack of newline -- you already have, and return the result.
*For floating point, either floatValue or doubleValue.
In didEndEditing, get the text, convert it to an integer, and check the value. If it's out of range, display an error message. You might also reset the text to it's previous value, assuming it starts out in-range.
I've used a regular expression to validate inputs to the right format. I found some documentation on line on RegEx that I was able to use to build my expression. You might create a regular expression that requires the input to be 1, 2, or 3 digits. I'm no expert, but the string #"^[0-9]{1,3}$" should require 1 to 3 digits between 0 and 9 (the 0-9 defines the legal characters, and the {1,3} means that the user can enter 1 through 3 of them. The ^ at the beginning anchors the expression to the beginning of the string, and the "$" at the end anchors the expression to the end of the string.)
You can use the code below
NSString *numberRegex = #"[1-9]||[0-9][1-9]||[0-1]0[0-5]";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", numberRegex];
BOOL b = [emailTest evaluateWithObject:numberField.text];
if (b)
{
//Code when number is in the range 1-105
}
else
{
//Code when number is not in the range 1-105
}
Hope this helps you
When searching the text Çınaraltı Café for the text Ci using the code
NSStringCompareOptions options =
NSCaseInsensitiveSearch |
NSDiacriticInsensitiveSearch |
NSWidthInsensitiveSearch;
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"tr"];
NSRange range = [haystack rangeOfString:needle
options:options
range:NSMakeRange(o, haystack.length)
locale:locale];
I get range.location equals NSNotFound.
It's not to do with the diacritic on the initial Ç because I get the same result searching for alti where the only odd character is the ı. I also get a valid match searching for Cafe which contains a diacritic (the é).
The apple docs mention this situation as notes on the locale parameter and I think I'm following them. Though I guess I'm not because it's not working.
How can I get a search for 'i' to match both 'i' and 'ı'?
I don't know whether this helps as an answer, but perhaps explains why it's happening.
I should point out I'm not an expert in this matter, but I've been looking into this for my own purposes and been doing some research.
Looking at the Unicode collation chart for latin, the equivalent characters to ASCII "i" (\u0069) do not include "ı" (\u0131), whereas all the other letters in your example string are as you expect, i.e.:
"c" (\u0063) does include "Ç" (\u00c7)
"e" (\u0065) does include "é" (\u00e9)
The ı character is listed separately as being of primary difference to i. That might not make sense to a Turkish speaker (I'm not one) but it's what Unicode have to say about it, and it does fit the logic of the problem you describe.
In Chrome you can see this in action with an in-page search. Searching in the page for ASCII i highlights all the characters in its block and does not match ı. Searching for ı does the opposite.
By contrast, MySQL's utf8_general_ci collation table maps uppercase ASCII I to ı as you want.
So, without knowing anything about iOS, I'm assuming it's using the Unicode standard and normalising all characters to latin by this table.
As to how you match Çınaraltı with Ci - if you can't override the collation table then perhaps you can just replace i in your search strings with a regular expression, so you search on Ç[iı] instead.
I wrote a simple extension in Swift 3 for Turkish string search.
let turkishSentence = "Türkçe ya da Türk dili, batıda Balkanlar’dan başlayıp doğuda Hazar Denizi sahasına kadar konuşulan Altay dillerinden biridir."
let turkishWannabe = "basLayip"
let shouldBeTrue = turkishSentence.contains(turkishString: turkishWannabe, caseSensitive: false)
let shouldBeFalse = turkishSentence.contains(turkishString: turkishWannabe, caseSensitive: true)
You can check it out from https://github.com/alpkeser/swift_turkish_string_search/blob/master/TurkishTextSearch.playground/Contents.swift
I did this and seems to work well for me.. hope it helps!
NSString *cleanedHaystack = [haystack stringByReplacingOccurrencesOfString:#"ı"
withString:#"i"];
cleanedHaystack = [cleanedHaystack stringByReplacingOccurrencesOfString:#"İ"
withString:#"I"];
NSString *cleanedNeedle = [needle stringByReplacingOccurrencesOfString:#"ı"
withString:#"i"];
cleanedNeedle = [cleanedNeedle stringByReplacingOccurrencesOfString:#"İ"
withString:#"I"];
NSUInteger options = (NSDiacriticInsensitiveSearch |
NSCaseInsensitiveSearch |
NSWidthInsensitiveSearch);
NSRange range = [cleanedHaystack rangeOfString:cleanedNeedle
options:options];
As Tim mentions, we can use regular expression to match text containing i or ı. I also didn't want to add a new field or change the source data as the search looks up huge amounts of string. So I ended up a solution using regular expressions and NSPredicate.
Create NSString category and copy this method. It returns basic or matching pattern. You can use it with any method that accepts regular expression pattern.
- (NSString *)zst_regexForTurkishLettersWithCaseSensitive:(BOOL)caseSensitive
{
NSMutableString *filterWordRegex = [NSMutableString string];
for (NSUInteger i = 0; i < self.length; i++) {
NSString *letter = [self substringWithRange:NSMakeRange(i, 1)];
if (caseSensitive) {
if ([letter isEqualToString:#"ı"] || [letter isEqualToString:#"i"]) {
letter = #"[ıi]";
} else if ([letter isEqualToString:#"I"] || [letter isEqualToString:#"İ"]) {
letter = #"[Iİ]";
}
} else {
if ([letter isEqualToString:#"ı"] || [letter isEqualToString:#"i"] ||
[letter isEqualToString:#"I"] || [letter isEqualToString:#"İ"]) {
letter = #"[ıiIİ]";
}
}
[filterWordRegex appendString:letter];
}
return filterWordRegex;
}
So if the search word is Şırnak, it creates Ş[ıi]rnak for case sensitive and Ş[ıiIİ]rnak for case insensitive search.
And here are the possible usages.
NSString *testString = #"Şırnak";
// First create your search regular expression.
NSString *searchWord = #"şır";
NSString *searchPattern = [searchWord zst_regexForTurkishLettersWithCaseSensitive:NO];
// Then create your matching pattern.
NSString *pattern = searchPattern; // Direct match
// NSString *pattern = [NSString stringWithFormat:#".*%#.*", searchPattern]; // Contains
// NSString *pattern = [NSString stringWithFormat:#"\\b%#.*", searchPattern]; // Begins with
// NSPredicate
// c for case insensitive, d for diacritic insensitive
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self matches[cd] %#", pattern];
if ([predicate evaluateWithObject:testString]) {
// Matches
}
// If you want to filter an array of objects
NSArray *matchedCities = [allAirports filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:#"city matches[cd] %#", pattern]];
You can also use NSRegularExpression but I think using case and diacritic insensitive search with NSPredicate is much more simpler.