How to find the number of gaps between words in an NSString? - objective-c

Given an NSString containing a sentence I would like to determine the number of gaps between the words.
I could use something like [[theString componentsSeparatedByString:#" "].
But that would only work if each gap is a single space character, there could be multiple.

You can use NSRegularExpression, like:
NSString *test = #"The quick brown fox jumped over the lazy dog";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\\s+" options:0 error:NULL];
NSUInteger num = [regex numberOfMatchesInString:test options:0 range:NSMakeRange(0, test.length)];
NSLog(#"num: %lu", num);
The regular expression "\s+" matches one or more whitespace characters (it's written here with an extra "\" because we need a literal backslash in the NSString). numberOfMatchesInString:options:range: counts each run of one or more whitespace characters as a match, which is exactly what you want.

You can do it via componentsSeparatedByString - if you filter afterwards to ignore the empty strings:
NSString *theString = #"HI this is a test";
NSArray *arr = [theString componentsSeparatedByString:#" "];
arr = [arr filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *b) {
return [(NSString*)evaluatedObject length] > 0;
}]];
NSLog(#"number of words: %lu", arr.count);
NSLog(#"number of gaps: %lu", arr.count - 1);

Regex is the 'coolest' way, but this might be the fastest and cleanest
NSArray *components= [theString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSLog(#"gaps: %f", components.count - 1);

Related

Looping through the value in Textfield for Particular Text

I have a TextField which has values as shown below.
#"Testing<Car>Testing<Car2>Working<Car3 /Car 4> on the code"
Here I have to loop through the text field and check for the text present within Angle brackets(< >).
There can be space or any special characters within the Angle Brackets.
I tried using NSPredicate and also componentsSeparatedByString, but I was not able to get the exact text within.
Is there any way to get the exact text along with Angle Brackets. Like in the above mentioned example want only
#"<Car>,<Car2> , <Car3 /Car 4>"
Thanks for the help in Advance.
A possible solution is Regular Expression. The pattern checks for < followed by one or more non-> characters and one >.
enumerateMatchesInString extracts the substrings and append them to an array. Finally the array is flattened to a single string.
NSString *string = #"Testing<Car>Testing<Car2>Working<Car3 /Car 4> on the code";
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:#"<[^>]+>" options:0 error:nil];
__block NSMutableArray<NSString *> *matches = [NSMutableArray array];
[regex enumerateMatchesInString:string options:0 range:NSMakeRange(0, string.length) usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) {
if (result) [matches addObject:[string substringWithRange:result.range]];
}];
NSLog(#"%#", [matches componentsJoinedByString:#", "]);
We can solve it in different ways. Now I am showing one of the way. You can place textFiled.text in place of str.
NSString *str = #"This is just Added < For testing %# ___ & >";
NSRange r1 = [str rangeOfString:#"<" options: NSBackwardsSearch];
NSRange r2 = [str rangeOfString:#">" options: NSBackwardsSearch];
NSRange rSub = NSMakeRange(r1.location + r1.length, r2.location - r1.location - r1.length);
NSString *sub = [str substringWithRange:rSub];

Take all numbers separated by spaces from a string and place in an array

I have a NSString formatted like this:
"Hello world 12 looking for some 56"
I want to find all instances of numbers separated by whitespace and place them in an NSArray. I dont want to remove the numbers though.
Whats the best way of achieving this?
This is a solution using regular expression as suggested in the comment.
NSString *string = #"Hello world 12 looking for some 56";
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:#"\\b\\d+" options:nil error:nil];
NSArray *matches = [expression matchesInString:string options:nil range:(NSMakeRange(0, string.length))];
NSMutableArray *result = [[NSMutableArray alloc] init];
for (NSTextCheckingResult *match in matches) {
[result addObject:[string substringWithRange:match.range]];
}
NSLog(#"%#", result);
First make an array using NSString's componentsSeparatedByString method and take reference to this SO question. Then iterate the array and refer to this SO question to check if an array element is number: Checking if NSString is Integer.
I don't know where you are looking to do perform this action because it may not be fast (such as if it's being called in a table cell it may be choppy) based upon the string size.
Code:
+ (NSArray *)getNumbersFromString:(NSString *)str {
NSMutableArray *retVal = [NSMutableArray array];
NSCharacterSet *numericSet = [NSCharacterSet decimalDigitCharacterSet];
NSString *placeholder = #"";
unichar currentChar;
for (int i = [str length] - 1; i >= 0; i--) {
currentChar = [str characterAtIndex:i];
if ([numericSet characterIsMember:currentChar]) {
placeholder = [placeholder stringByAppendingString:
[NSString stringWithCharacters:&currentChar
length:[placeholder length]+1];
} else {
if ([placeholder length] > 0) [retVal addObject:[placeholder intValue]];
else placeholder = #"";
return [retVal copy];
}
To explain what is happening above, essentially I am,
going through every character until I find a number
adding that number including any numbers after to a string
once it finds a number it adds it to an array
Hope this helps please ask for clarification if needed

Objective C - Split string into array

How would I do this? I'm new to Objective-C but I can't find anything that would help me do this.
NSArray *splitLine = [currentLine componentsSeparatedByString:#":%#",notNumber];
Where notNumber is a string that represents anything that isn't a number. So I want to separate a string where there are colons separated by strings that aren't numbers. (I want to avoid splitting at times i.e. 3:00pm, but split at iCal parameters like DESCRIPTION: and LOCATION:.)
You can do this in several steps, like this. I have not compiled this code, but it should at least give you an idea of what to do.
1) Create a regex object to match your separators:
NSString *regexString = #"DESCRIPTION:\s|LOCATION:\s"; // or whatever makes sense for your scenario
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:regexString
options:NSRegularExpressionCaseInsensitive
error:nil];
2) Replace all the different separators matching your regex with just one separator:
NSRange range = NSMakeRange(0, string.length);
NSString *string2 = [regex stringByReplacingMatchesInString:string
options:0
range:range
withTemplate:#"SEPARATOR"];
3) Split the string!
NSArray *elements = [string2 componentsSeparatedByString:#"SEPARATOR"];
Shortest solution for splitting string.
NSString *str = #"Please split me to form array of words";
NSArray *wordsArray = [str componentsSeparatedByString:#" "];
You can use regular expressions!
Using the pattern (I believe this is the core of your question):
pattern = #"(?<=[^0-9]):(?=[^0-9])"
This pattern will only match ':' symbols not surrounded by numbers.
Then replace with a dummy value that won't show in your data
dummy = #"NEVERSEETHIS"
NSRegularExpressions *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
NSRange range = NSMakeRange(0, [string length])
NSString *modified= [regex replaceMatchesInString:yourString options:0 range:range withTemplate:dummy];
and finally, split
return [modified componentsSeparatedByString:dummy];

Split string into parts

I want to split NSString into array with fixed-length parts. How can i do this?
I searched about it, but i only find componentSeparatedByString method, but nothing more. It's also can be done manually, but is there a faster way to do this ?
Depends what you mean by "faster" - if it is processor performance you refer to, I'd guess that it is hard to beat substringWithRange:, but for robust, easy coding of a problem like this, regular expressions can actually come in quite handy.
Here's one that can be used to divide a string into 10-char chunks, allowing the last chunk to be of less than 10 chars:
NSString *pattern = #".{1,10}";
Unfortunately, the Cocoa implementation of the regex machinery is less elegant, but simple enough to use:
NSString *string = #"I want to split NSString into array with fixed-length parts. How can i do this?";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern: pattern options: 0 error: &error];
NSArray *matches = [regex matchesInString:string options:0 range:NSMakeRange(0, [string length])];
NSMutableArray *result = [NSMutableArray array];
for (NSTextCheckingResult *match in matches) {
[result addObject: [string substringWithRange: match.range]];
}
Break the string into a sequence of NSRanges and then try using NSString's substringWithRange: method.
You can split a string in different ways.
One way is to split by spaces(or any character):
NSString *string = #"Hello World Obj C is Awesome";
NSArray *words = [string componentsSeparatedByString:#" "];
You can also split at exact points in a string:
NSString *word = [string substringWithRange:NSMakeRange(startPoint, FIXED_LENGTH)];
Simply put it in a loop for a fixed length and save to Mutable Array:
NSMutableArray *words = [NSMutableArray array];
for (int i = 0; i < [string length]; i++) {
NSString *word = [string substringWithRange:NSMakeRange(i, FIXED_LENGTH)]; //you may want to make #define
[array addObject:word];
}
Hope this helps.

NSString category to calculate length combining some characters

I need to calculate word length of string for the certain known language, which has some letter sequence, to count it as 1 letter. Say letters "ao" is one letter. How can I achieve this?
One idea would be to replace each occurrence of the letter sequences by a single character and
count the length of the result:
NSString *string = #"Hello world";
NSMutableString *tmp = [string mutableCopy];
NSArray *sequences = #[#"ll", #"wo"];
for (NSString *seq in sequences) {
[tmp replaceOccurrencesOfString:seq
withString:#"."
options:NSCaseInsensitiveSearch
range:NSMakeRange(0, [tmp length])];
}
// tmp is "He.o .rld" now
NSUInteger length = [tmp length];
Remark: length does not count "composed characters" as a single character.
If that is an issue, you have to use enumerateSubstringsInRange:options:usingBlock:
with the NSStringEnumerationByComposedCharacterSequences option to count the
characters correctly. This applies for example to all "UTF-16" surrogate pairs (e.g. Emojis). It might apply to other characters such as Hangul characters as well,
I am not sure about that right now.
ADDED: The following method uses regular expressions and should work as well.
The advantage might be that no temporary strings are created. But one should
measure which method is really faster.
NSString *string = #"Hello world";
NSString *pattern = #"ll|wo|.";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern
options:NSRegularExpressionCaseInsensitive
error:NULL];
NSUInteger length = [regex numberOfMatchesInString:string
options:0
range:NSMakeRange(0, [string length])];
NSLog(#"length = %d", length);