NSString category to calculate length combining some characters - objective-c

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);

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];

How can I replace one pair of character with multiple occurrence in a string?

Original String is: This is a sentence with (noun) (verb) (adverb).
Original sentence has three occurrence of (). I need the last one intact but replace rest with #""
Required String: This is a sentence with (adverb).
I can do it with NSRange but I am looking for NSRegularExpression pattern.
Also which is more efficient, one with NSRange or the NSRegularExpression.
CODE
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\\(.*?\\)" options:NSRegularExpressionCaseInsensitive error:NULL];
NSString *newString = [regex stringByReplacingMatchesInString:modify options:0 range:NSMakeRange(0, [modify length]) withTemplate:#""];
Output:: This is a sentence with
You can obtain the match ranges themselves and do the replacement manually, ignoring the last one.
NSMutableString* newString = [modify mutableCopy];
NSArray<NSTextCheckingResult*>* matches = [regex matchesInString:newString options:0 range:NSMakeRange(0, newString.length)];
if (matches.count >= 2)
{
// Enumerate backwards so that each replacement doesn't invalidate the other ranges
for (NSInteger i = matches.count - 2; i >= 0; i--)
{
NSTextCheckingResult* result = matches[i];
[newString replaceCharactersInRange:result.range withString:#""];
}
}

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

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);

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.