Regex in objective C - ios

I want to extract only the names from the following string
bob!33#localhost #clement!17#localhost jack!03#localhost
and create an array [#"bob", #"clement", #"jack"].
I have tried NSString's componentsseparatedbystring: but it didn't work as expected. So I am planning to go for regEx.
How can I extract strings between ranges and add it to an array
using regEx in objective C?
The initial string might contain more than 500 names, would it be a
performance issue if I manipulate the string using regEx?

You can do it without regex as below (Assuming ! sign have uniform pattern in your all words),
NSString *names = #"bob!33#localhost #clement!17#localhost jack!03#localhost";
NSArray *namesarray = [names componentsSeparatedByString:#" "];
NSMutableArray *desiredArray = [[NSMutableArray alloc] initWithCapacity:0];
[namesarray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSRange rangeofsign = [(NSString*)obj rangeOfString:#"!"];
NSString *extractedName = [(NSString*)obj substringToIndex:rangeofsign.location];
[desiredArray addObject:extractedName];
}];
NSLog(#"%#",desiredArray);
output of above NSLog would be
(
bob,
"#clement",
jack
)
If you still want to get rid of # symbol in above string you can always replace special characters in any string, for that check this
If you need further help, you can always leave comment

NSMutableArray* nameArray = [[NSMutableArray alloc] init];
NSArray* youarArray = [yourString componentsSeparatedByString:#" "];
for(NSString * nString in youarArray) {
NSArray* splitObj = [nString componentsSeparatedByString:#"!"];
[nameArray addObject:[splitObj[0]]];
}
NSLog(#"%#", nameArray);

I saw the other solutions and it seemed no one tried to use real regular expressions here, so I created a solution which uses it, maybe you or someone else can use it as a possible idea in the future:
NSString *_names = #"bob!33#localhost #clement!17#localhost jack!03#localhost";
NSError *_error;
NSRegularExpression *_regExp = [NSRegularExpression regularExpressionWithPattern:#" ?#?(.*?)!\\d{2}#localhost" options:NSRegularExpressionCaseInsensitive error:&_error];
NSMutableArray *_namesOnly = [NSMutableArray array];
if (!_error) {
NSLock *_lock = [[NSLock alloc] init];
[_regExp enumerateMatchesInString:_names options:NSMatchingReportProgress range:NSMakeRange(0, _names.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
if (result.numberOfRanges > 1) {
if ([_lock tryLock]) [_namesOnly addObject:[_names substringWithRange:[result rangeAtIndex:1]]], [_lock unlock];
}
}];
} else {
NSLog(#"error : %#", _error);
}
the result can be logged...
NSLog(#"_namesOnly : %#", _namesOnly);
...and that will be:
_namesOnly : (
bob,
clement,
jack
)

Or even something as simple as this will do the trick:
NSString *strNames = #"bob!33#localhost #clement!17#localhost jack!03#localhost";
strNames = [[strNames componentsSeparatedByCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]]
componentsJoinedByString:#""];
NSArray *arrNames = [strNames componentsSeparatedByString:#"localhost"];
NSLog(#"%#", arrNames);
Output:
(
bob,
clement,
jack,
""
)
NOTE: Ignore the last element index while iterating or whatever
Assumption:
"localhost" always comes between names
I know it ain't so optimized but it's one way to do this

Related

Understanding how to use NSRegularExpressions correctly

I am trying to write a function that has an NSString and parses it returning an array of tags.
The definition of a tag is any nsstring text that starts with # and contains only alphanumeric characters after the #.
Is this correct?
#.*?[A-Za-z0-9]
I want to use matchesInString:options:range: but need some help.
My function is:
- (void) getTags
{
NSString* str = #"This is my string and a couple of #tags for #you.";
// Range is 0 to 48 (full length of string)
// NSArray should contain #tags and #you only.
Thanks!
The patten "#.*?[A-Za-z0-9]" matches a # which is followed by zero or more
characters which are not in the set [A-Za-z0-9]. What you probably want is
NSString *pattern = #"#[A-Za-z0-9]+";
The you can create a regular expression using that pattern:
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
and enumerate all matches in the string:
NSString *string = #"abc #tag1 def #tag2.";
NSMutableArray *tags = [NSMutableArray array];
[regex enumerateMatchesInString:string options:0 range:NSMakeRange(0, string.length)
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange range = [result range];
NSString *tag = [string substringWithRange:range];
[tags addObject:tag];
}];
NSLog(#"%#", tags);
Output:
(
"#tag1",
"#tag2"
)

Ignore words beginning with a hashtag or mention

Please forgive me for my noobness but I am having trouble building a pattern to ignore words beginning with a hashtag # or a mention symbol #. I know that to select words beginning with hashtags I can do #(\w+) and to select words beginning with mentions I can do #(\w+).
I tried doing something like this (?!#(\w+)) to ignore the mentions and this (?!#(\w+)) to ignore hashtags but no luck. I'll keep trying and searching any help is appreciated.
I want to create a pattern that: !(hashtags) AND !(mentions)
Or a pattern that selects only words.
Try this:
NSMutableArray *words = [[text componentsSeparatedByString:#" "] mutableCopy];
for (NSString *word in words)
{
NSString *firstCharacter = [word substringToIndex:1];
if ([firstCharacter isEqual:#"#"] || [firstCharacter isEqual:#"#"])
{
// remove the word from the array here or whatever
[words removeObject:word];
}
}
Here is the solution that worked for me based on the answer provided by freshking
- (NSMutableArray *) checkForWords:(UITextField *)textField {
NSMutableArray *words = [[NSMutableArray alloc] initWithArray:[[textField.text componentsSeparatedByString:#" "] mutableCopy]];
NSMutableArray *matches = [[NSMutableArray alloc] init];
//NSLog(#"words: %#",words);
for (NSString *word in words) {
NSString *firstCharacter = [word substringToIndex:1];
if (![firstCharacter isEqual:#"#"] && ![firstCharacter isEqual:#"#"]) {
[matches addObject:word];
}
}
return matches;
}

What will be the best way to update my NSString with appropriate NSArray value

I am trying to update my NSString value with the following code.
NSString *string =[NSString stringWithFormat:#"array[0]%#",[array componentsJoinedByString:#"[0]"]];
This is the result I got.
array[0]1array[0]2array[0]3
However, I need this result, basically the number inside the brackets will be updated based on the number of objects in the NSMutablearray.
array[0]1array[1]2array[2]3
I tried using a for loop with [NSString stringWithFormat:#"[%i]", i], but it seem to not have worked.
Untested:
NSMutableString *finalString = [[NSMutableString alloc] init];
[array enumerateObjectsUsingBlock:^(NSString *str, NSUInteger idx, BOOL *stop) {
[finalString appendFormat:#"[%lu]%#", (unsigned long)idx, str];
}];
// do stuff with finalString

Print symbols that were met in the text, no duplicates

I have been struggling with this question for couple days now. Really need your help and opinion.
We have a string, that holds a text:
NSString *contentOfFile = [[NSString alloc] initWithString:#"This is string#1"];
Now I have to log symbols, that were met in this string without duplicates. Result should look like this:
whitespace symbol here
#
1
g
h
i
n
r
s
t
I know that this is solved very simple in C code using char set and iterators but I am looking for the same simple and elegant way of handling this operation in objective-c.
I was thinking of using NSCharacterSet on the string somehow but I have a lack of knowledge in objective-c so I need your help guys please. Thanks in advance to everyone who replies.
Take advantage of a trait of NSSet: Its members are distinct.
NSString *contentOfFile = #"This is string#1";
NSMutableSet *set = [NSMutableSet set];
NSUInteger length = [contentOfFile length];
for (NSUInteger index = 0; index < length; index++)
{
NSString *substring = [contentOfFile substringWithRange:NSMakeRange(index, 1)];
[set addObject:substring];
}
NSLog(#"%#", set);
However, there's one remaining problem, and that is the members of a set are also unordered. Fortunately, arrays are ordered. So if you change the last line:
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"self" ascending:YES];
NSArray *array = [set sortedArrayUsingDescriptors:#[sortDescriptor]];
NSLog(#"%#", array);
If case insensitivity is important to you, there unfortunately is no 'case-insensitive' option for NSSet. However, you could convert your source string to all lowercase, like this:
NSString *contentOfFile = [#"This is string#1" lowercaseString];
and this would give you results exactly matching your sample output.
// Create the string
NSString *contentOfFile = #"This is string#1";
// Remove all whitespaces
NSString *whitespaceRemoval = [contentOfFile stringByReplacingOccurrencesOfString:#" " withString:#""];
// Initialize an array to store the characters
NSMutableArray *components = [NSMutableArray array];
// Iterate through the characters and add them to the array
for (int i = 0; i < [whitespaceRemoval length]; i++) {
NSString *character = [NSString stringWithFormat:#"%c", [whitespaceRemoval characterAtIndex:i]];
if (![components containsObject:character]) {
[components addObject:character];
}
}

All elements of nsarray are present in nsstring or not

I want to scan NSString (case insensitive) to check whether all elements of an array contain in that String or not ?
Eg.
NSString *string1 = #"Java is pass by value : lets see how?";
NSString *string2 = #"Java is OOP Language";
NSArray *array = [[NSArray alloc] initWithObjects:#"Java",#"Pass",#"value", nil];
In this case string1 pass the test as it contain all keyword from array (i.e. Java,Pass,Value).
So, how can i achieve this functionality ?
I don't test it for speed, and it will fail on case-sensitive strings, but here's another solution (just in case)
NSArray *components = [string1 componentsSeparatedByString:#" "];
NSSet *textSet = [NSSet setWithArray:components];
NSSet *keywordsSet = [NSSet setWithArray:array];
BOOL result = [keywordsSet isSubsetOfSet:textSet];
Keep in mind that componentsSeparatedByString will tokenize very silly, like "how?" instead of "how" you need.
BOOL containsAll = YES;
for (NSString *test in array) {
if ([string1 rangeOfString:test].location == NSNotFound) {
containsAll = NO;
break;
}
}

Resources