NSString: Find parts of string in another string - objective-c

I know how to find a string in another string, that is easy. But in this case I want to find John Smith within the allProfessors string. So I figured I could just split the string and search for both parts, which works how I want:
NSString *fullName = #"John Smith";
NSArray *parts = [fullName componentsSeparatedByString:#" "];
NSString *allProfessors = #"Smith, John; Clinton, Bill; Johnson, John";
NSRange range = [[allProfessors lowercaseString] rangeOfString:[[parts objectAtIndex:0] lowercaseString]];
NSRange range2 = [[allProfessors lowercaseString] rangeOfString:[[parts objectAtIndex:1] lowercaseString]];
if(range.location != NSNotFound && range2.location != NSNotFound) {
NSLog(#"Found");
} else {
NSLog(#"Not Found");
}
What I want to know is, is this the BEST way to do this or is there a more preferred method to do what I want?
In addition to this, what if my fullName is longer than my allProfessors name, such as:
NSString *fullName = #"Gregory Smith";
NSString *allProfessors = #"Smith, Greg; Clinton, Bill; Johnson, John";
I still want there to be a match for Greg Smith and Gregory Smith.

You could use regular expressions, which I prefer to use. See RegexKitLite.
With RegexKitLite, you could use a regular expression like (untested):
NSString *regEx = #"(?i)Smith,\\s*\\w";
NSArray *matchingStrings = [allProfessors componentsMatchedByRegex:regEx];
if ([matchingStrings count] == 0) // not found!
{
[...]
}
else
{
[...]
}
Using RegexKitLite you could alternatively have used [NSString stringByMatching:(NSString*)].
You can really do a lot with regular expression. There are a ton of different functions available through Using RegexKitLite. The regular expression above should find people with the last name of Smith.
Regular Expression explained:
(?i) make this case insensitive
Smith matches last name of Smith. Obviously you could change this to anything
, match a comma
\\s* match any number of spaces (greedy)
\\w match a word
Also, you could use [NSString rangeOfString:options:] function like:
if ([myString rangeOfString:#"John" options:NSCaseInsensitiveSearch].location != NSNotFound &&
[myString rangeOfString:#"Smith" options:NSCaseInsensitiveSearch].location != NSNotFound)
{
NSLog(#"Found");
}
else
{
NSLog(#"Not Found");
}
Also see similar functions like [rangeOfString:options:range:locale:] so that you can do case insensitive searches and even specify a locale.

Related

How to extend search with SearchBar

I want to search through an array with strings in it. Therefore i use a searchbar.
Here's my code:
for(NSString *string in itemsArray)
{
NSRange nameRange = [string rangeOfString:text options:NSCaseInsensitiveSearch];
if (nameRange.location != NSNotFound)
{
[filteredItemsArray addObject:string];
}
}
It works great, but the problem is it just finds the string when I write it exactly the same way (except the case insensitivity).
But I would also like to find it even if the strings doesn't fit a 100%. For example when I search for 'Ralle Turner' it should also find the string with 'Ralle/Ralph Turner'.
Thanks for your help guys!
You need to split the search string into words, and then iterate through each word to find a match.
You can split the string using this code inside your loop
for(NSString *string in itemsArray)
{
NSArray *words = [text componentsSeparatedByString:#" "];
for (NSString *word in words)
{
NSRange nameRange = [string rangeOfString:word options:NSCaseInsensitiveSearch];
if (nameRange.location != NSNotFound)
{
[filteredItemsArray addObject:string];
break;
}
}
}
You can compute the levenshtein distance of two string to see if there is a potential match.
You can easily find some implementation on the web, for instance:
-via NSString Category
-via a single method
Or use one the others approximate string matching algorithms

Find one string in another with case insensitive in Objective-C

My question is similar to How do I check if a string contains another string in Objective-C?
How can I check if a string (NSString) contains another smaller string but with ignoring case?
NSString *string = #"hello bla bla";
I was hoping for something like:
NSLog(#"%d",[string containsSubstring:#"BLA"]);
Anyway is there any way to find if a string contains another string with ignore case ? But please do not convert both strings to UpperCase or to LowerCase.
As similar to the answer provided in the link, but use options.
See - (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask in Apple doc
NSString *string = #"hello bla bla";
if ([string rangeOfString:#"BLA" options:NSCaseInsensitiveSearch].location == NSNotFound)
{
NSLog(#"string does not contain bla");
}
else
{
NSLog(#"string contains bla!");
}
From iOS 8 you can add the containsString: or localizedCaseInsensitiveContainsString method to NSString.
if ([string localizedCaseInsensitiveContainsString:#"BlA"]) {
NSLog(#"string contains Case Insensitive bla!");
} else {
NSLog(#"string does not contain bla");
}
NSString *string = #"hello BLA";
if ([string rangeOfString:#"bla" options:NSCaseInsensitiveSearch].location == NSNotFound) {
NSLog(#"string does not contain bla");
} else {
NSLog(#"string contains bla!");
}
The method
[string rangeOfString:#"bla" options:NSCaseInsensitiveSearch];
should help you.
You can use -(NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask; to get a range for a substring, the mask parameter is used to specify case insensitive match.
Example :
NSRange r = [str rangeOfString:#"BLA"
options:NSCaseInsensitiveSearch];
As stated in the documentation, the method returns a range like {NSNotFound, 0} when the substring isn't found.
BOOL b = r.location == NSNotFound;
Important this method raises an exception if the string is nil.
For Swift 4:
extension String {
func containsCaseInsensitive(string : String) -> Bool {
return self.localizedCaseInsensitiveContains(string)
}
}
Usage:
print("Hello".containsCaseInsensitive(string: "LLO"))
Output:
true

Check whether an NSString contains a special character and a digit

I need to check whether a string contains one uppercase letter, one lower case letter, one integer and one special character. How do I check?
Without any additional frameworks:
NSCharacterSet * set = [[NSCharacterSet characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"] invertedSet];
if ([aString rangeOfCharacterFromSet:set].location != NSNotFound) {
NSLog(#"This string contains illegal characters.");
}
You could also use a regex (this syntax is from RegexKitLite: http://regexkit.sourceforge.net):
if ([aString isMatchedByRegex:#"[^a-zA-Z0-9]"]) {
NSLog(#"This string contains illegal characters.");
}
Found a slightly better implementation. Improvement on Ameesh's answer
- (BOOL)isValidString:(NSString *)string
{
return [string rangeOfCharacterFromSet:[NSCharacterSet uppercaseLetterCharacterSet]].location != NSNotFound &&
[string rangeOfCharacterFromSet:[NSCharacterSet lowercaseLetterCharacterSet]].location != NSNotFound &&
[string rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location != NSNotFound;
}
Maulik's answer is incorrect. That will check for anything OTHER than any alphanumeric character, but doesn't enforce that there be one uppercase letter, one lowercase letter, and one integer. You do in fact have to do 3 checks to verify each constraint.
NSCharacterSet *lowerCaseChars = [NSCharacterSet characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyz"];
NSCharacterSet *upperCaseChars = [NSCharacterSet characterSetWithCharactersInString:#"ABCDEFGHIJKLKMNOPQRSTUVWXYZ"];
NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
if ([aString rangeOfCharacterFromSet:lowerCaseChars].location == NSNotFound || [aString rangeOfCharacterFromSet:upperCaseChars].location = NSNotFound || [aString rangeOfCharacterFromSet:numbers].location == NSNotFound) {
NSLog(#"This string contains illegal characters");
}
For Arabic/English
NSString *regEx = #"^([a-zA-Z0-9\u0600-\u06ff](\\-|\\_|\\.|\\ )?)+$";
NSPredicate *regExPredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",regEx];
BOOL myStringMatchesRegEx = [regExPredicate evaluateWithObject: self.text];
if (!myStringMatchesRegEx)
return NO;
Here is what I would do. Create Regular expressions for every condition you need to check if corresponding value present or not.
i.e. Regular Expression to check if it has one uppercase letter, one lower case letter , one integer and one special character, and so on.
and then use the same string to check against every regular expression if all of them return true you have winner if not then string doesn't match to your criteria.
// Example for the Validating UpperCaseLetter do same for all others with matching regular expression.
-(BOOL) validateOneUpperCaseLetter:(NSString *)string {
if ((string == nil) || ([string isEqualToString: #""])) {
return NO;
}
// Change this regEx to one you needed. // this one validates for the "name".
NSString *regEx = #"^[a-zA-Z]+(([\\'\\,\\.\\ -][a-zA-Z])?[a-zA-Z]\\s*)*$";
NSPredicate *regExPredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",regEx];
BOOL myStringMatchesRegEx = [regExPredicate evaluateWithObject: string];
if (!myStringMatchesRegEx) {
return NO;
}
return YES;}

String comparison in Objective-C

I've currently got a webserver set up which I communicate over SOAP with my iPhone app. I am returning a NSString containing a GUID and when I attempt to compare this with another NSString I get some strange results.
Why would this not fire? Surely the two strings are a match?
NSString *myString = #"hello world";
if (myString == #"hello world")
return;
Use the -isEqualToString: method to compare the value of two strings. Using the C == operator will simply compare the addresses of the objects.
if ([category isEqualToString:#"Some String"])
{
// Do stuff...
}
You can use case-sensitive or case-insensitive comparison, depending what you need.
Case-sensitive is like this:
if ([category isEqualToString:#"Some String"])
{
// Both strings are equal without respect to their case.
}
Case-insensitive is like this:
if ([category compare:#"Some String" options:NSCaseInsensitiveSearch] == NSOrderedSame)
{
// Both strings are equal with respect to their case.
}
You can compare string with below functions.
NSString *first = #"abc";
NSString *second = #"abc";
NSString *third = [[NSString alloc] initWithString:#"abc"];
NSLog(#"%d", (second == third))
NSLog(#"%d", (first == second));
NSLog(#"%d", [first isEqualToString:second]);
NSLog(#"%d", [first isEqualToString:third]);
Output will be :-
0
1
1
1

How to capitalize the first word of the sentence in Objective-C?

I've already found how to capitalize all words of the sentence, but not the first word only.
NSString *txt =#"hi my friends!"
[txt capitalizedString];
I don't want to change to lower case and capitalize the first char. I'd like to capitalize the first word only without change the others.
Here is another go at it:
NSString *txt = #"hi my friends!";
txt = [txt stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[txt substringToIndex:1] uppercaseString]];
For Swift language:
txt.replaceRange(txt.startIndex...txt.startIndex, with: String(txt[txt.startIndex]).capitalizedString)
The accepted answer is wrong. First, it is not correct to treat the units of NSString as "characters" in the sense that a user expects. There are surrogate pairs. There are combining sequences. Splitting those will produce incorrect results. Second, it is not necessarily the case that uppercasing the first character produces the same result as capitalizing a word containing that character. Languages can be context-sensitive.
The correct way to do this is to get the frameworks to identify words (and possibly sentences) in the locale-appropriate manner. And also to capitalize in the locale-appropriate manner.
[aMutableString enumerateSubstringsInRange:NSMakeRange(0, [aMutableString length])
options:NSStringEnumerationByWords | NSStringEnumerationLocalized
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[aMutableString replaceCharactersInRange:substringRange
withString:[substring capitalizedStringWithLocale:[NSLocale currentLocale]]];
*stop = YES;
}];
It's possible that the first word of a string is not the same as the first word of the first sentence of a string. To identify the first (or each) sentence of the string and then capitalize the first word of that (or those), then surround the above in an outer invocation of -enumerateSubstringsInRange:options:usingBlock: using NSStringEnumerationBySentences | NSStringEnumerationLocalized. In the inner invocation, pass the substringRange provided by the outer invocation as the range argument.
Use
- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator
and capitalize the first object in the array and then use
- (NSString *)componentsJoinedByString:(NSString *)separator
to join them back
pString = [pString
stringByReplacingCharactersInRange:NSMakeRange(0,1)
withString:[[pString substringToIndex:1] capitalizedString]];
you can user with regular expression i have done it's works for me simple you can paste below code
+(NSString*)CaptializeFirstCharacterOfSentence:(NSString*)sentence{
NSMutableString *firstCharacter = [sentence mutableCopy];
NSString *pattern = #"(^|\\.|\\?|\\!)\\s*(\\p{Letter})";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:NULL];
[regex enumerateMatchesInString:sentence options:0 range:NSMakeRange(0, [sentence length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
//NSLog(#"%#", result);
NSRange r = [result rangeAtIndex:2];
[firstCharacter replaceCharactersInRange:r withString:[[sentence substringWithRange:r] uppercaseString]];
}];
NSLog(#"%#", firstCharacter);
return firstCharacter;
}
//Call this method
NsString *resultSentence = [UserClass CaptializeFirstCharacterOfSentence:yourTexthere];
An alternative solution in Swift:
var str = "hello"
if count(str) > 0 {
str.splice(String(str.removeAtIndex(str.startIndex)).uppercaseString, atIndex: str.startIndex)
}
For the sake of having options, I'd suggest:
NSString *myString = [NSString stringWithFormat:#"this is a string..."];
char *tmpStr = calloc([myString length] + 1,sizeof(char));
[myString getCString:tmpStr maxLength:[myString length] + 1 encoding:NSUTF8StringEncoding];
int sIndex = 0;
/* skip non-alpha characters at beginning of string */
while (!isalpha(tmpStr[sIndex])) {
sIndex++;
}
toupper(tmpStr[sIndex]);
myString = [NSString stringWithCString:tmpStr encoding:NSUTF8StringEncoding];
I'm at work and don't have my Mac to test this on, but if I remember correctly, you couldn't use [myString cStringUsingEncoding:NSUTF8StringEncoding] because it returns a const char *.
In swift you can do it as followed by using this extension:
extension String {
func ucfirst() -> String {
return (self as NSString).stringByReplacingCharactersInRange(NSMakeRange(0, 1), withString: (self as NSString).substringToIndex(1).uppercaseString)
}
}
calling your string like this:
var ucfirstString:String = "test".ucfirst()
I know the question asks specifically for an Objective C answer, however here is a solution for Swift 2.0:
let txt = "hi my friends!"
var sentencecaseString = ""
for (index, character) in txt.characters.enumerate() {
if 0 == index {
sentencecaseString += String(character).uppercaseString
} else {
sentencecaseString.append(character)
}
}
Or as an extension:
func sentencecaseString() -> String {
var sentencecaseString = ""
for (index, character) in self.characters.enumerate() {
if 0 == index {
sentencecaseString += String(character).uppercaseString
} else {
sentencecaseString.append(character)
}
}
return sentencecaseString
}