4

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.

  1. How can I extract strings between ranges and add it to an array using regEx in objective C?
  2. The initial string might contain more than 500 names, would it be a performance issue if I manipulate the string using regEx?
3
  • Doesn't first and last part contain @ character in front of name? Commented Jan 6, 2014 at 6:03
  • Just a quick question, in your string 2nd word starts with @ is it right ? don't you have uniform pattern ? Commented Jan 6, 2014 at 6:10
  • @KudoCC No, but the name will end with "!" sign. Only one name will start with @ sign. Commented Jan 6, 2014 at 6:55

4 Answers 4

5

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

Sign up to request clarification or add additional context in comments.

3 Comments

thanks for the answer. It works. As I mentioned in the question the names string might contain more than 500 names, would there be any performance issues in this approach?
just only small comment... the –addObject: method is not thread-safe and how you are using here is a potential crash-point, because you cannot be sure of the blocks are not called simultaneously.
From the documentation it says "This method executes synchronously." still you doubt please leave a proof, I will change accordingly.
5
NSMutableArray* nameArray = [[NSMutableArray alloc] init];
NSArray* youarArray = [yourString componentsSeparatedByString:@" "];
for(NSString * nString in youarArray) {
   NSArray* splitObj = [nString componentsSeparatedByString:@"!"];
   [nameArray addObject:[splitObj[0]]];
}    
NSLog(@"%@", nameArray);

8 Comments

+1 to providing solution, but you should always switch to latest approach available. In this case you can iterate using enumerateObjectsUsingBlock which gives you more flexibility against normal looping.
@JanakNirmal Thanks. do you find any performance difference between block vs fast Enumeration? Your solution is correct but i guess its doing more math processing for finding the range and then split? please correct me if i am assuming wrong.
In your case what if you want to break the loop in a certain condition? take a variable ? Which can be easily managed by code I have wrote, just assign stop to yes
Another advantage what if you want to access index, in your case take another variable ? simply available in the code I have wrote.
Sure but thats not a case here, just need a name array :) but definitely your answer very perfect way, Personally I will use this way if needed
|
4

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
)

Comments

4

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:

  1. "localhost" always comes between names

I know it ain't so optimized but it's one way to do this

3 Comments

thanks for the solution. But I am looking for a highly optimized solution because the solution should be able to handle 1000 of names without affecting the performance of the app.
@Clement : hm.. ok. lets find the most optimized solution then
@Clement : i was wondering how to make this even more simpler. updated answer... how does it look now?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.