0

I get an NSString containing different emails concatenated together like

def_ghi@hotmail.com_abc_1@me.com

Each email is separated by an underscore.The problem is if I try to separate the string using the underscore character it would also subdivide a single e-mail address as an underscore character can also come in within a single e-mail. What I've tried gives me this result

def

ghi@hotmail.com

abc

1@me.com

Here is my code

NSString *string = //The string I am receiving.
NSArray *chunks = [string componentsSeparatedByString: @"_"];

Please help me.

EDIT: I asked a senior and he told me that I should first search the string for "@" character.When I find this,then I search for an "_" and replace it if it exists.As the first underscore after "@" is the separator.I should then start from this location and again repeat the previous step.I do this till the string ends.Please somebody help me with this.

Monolo
  • 18,205
  • 17
  • 69
  • 103
Jpk
  • 21
  • 3
  • 2
    You can't do this. You either need a delimiter that can't be part of the values or you must escape the delimiter character if it appears in a value. Otherwise there is no way to know how to properly split the string. – rmaddy May 01 '13 at 04:56
  • I asked a senior and he told me that I should first search the string for "@" character.When I find this,then I search for an "_" and replace it if it exists.As the first underscore after "@" is the separator.I should then start from this location and again repeat the previous step.I do this till the string ends. – Jpk May 01 '13 at 05:01
  • 2
    OK but I don't get why this is being made harder than it should. It would make so much more sense for everyone if the delimiter was changed to a character that can't appear in a valid email address. – rmaddy May 01 '13 at 05:05

4 Answers4

3

Solution using regular expressions,

NSString *yourString = @"def_ghi@hotmail.com_abc_1@me.com";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
                              regularExpressionWithPattern:@"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
                              options:NSRegularExpressionCaseInsensitive
                              error:&error];
[regex enumerateMatchesInString:yourString options:0 range:NSMakeRange(0, [yourString length]) usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){

    // detect email addresses
    NSString *email = [yourString substringWithRange:match.range];

    //this part remove the '_' between email addresses
    if(match.range.location != 0){
        if([email characterAtIndex:0]=='_'){
            email = [email substringFromIndex:1];
        }
    }

    //print the email address
    NSLog(@"%@",email);

}];

EDIT: how to collect them,

declare a variable like this,

@property(nonatomic, strong) NSMutableArray *emailsArray;



 _emailsArray = [[NSMutableArray alloc] init];

NSString *yourString = @"def_ghi@hotmail.com_abc_1@me.com";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
                              regularExpressionWithPattern:@"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
                              options:NSRegularExpressionCaseInsensitive
                              error:&error];
[regex enumerateMatchesInString:yourString options:0 range:NSMakeRange(0, [yourString length]) usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){

    // detect email addresses
    NSString *email = [yourString substringWithRange:match.range];

    //this part remove the '_' between email addresses
    if(match.range.location != 0){
        if([email characterAtIndex:0]=='_'){
            email = [email substringFromIndex:1];
        }
    }

    //print the email address
    NSLog(@"%@",email);
    [self.emailsArray addObject:email];
}];


NSLog(@"%@",self.emailsArray);
Thilina Chamath Hewagama
  • 9,039
  • 3
  • 32
  • 45
  • @Thilina How do I add the check about the underscore in between the emails? Please edit your code .I don't understand regular expressions. – Jpk May 01 '13 at 05:20
  • @Jimmy Johnny, I changed the code and I added that part as well. Just copy the code and run it. cheers – Thilina Chamath Hewagama May 01 '13 at 05:21
  • @ThilinaHewagama That's not good advice. It is important that the OP understands the answer, not just blindly copies and uses it. – rmaddy May 01 '13 at 05:23
  • 1
    @rmaddy, i just ask him to run it and see the result first. then he knows that works. then I'm going to explain that. wait and see – Thilina Chamath Hewagama May 01 '13 at 05:24
  • @ThilinaHewagama Chose you as best answer.There is one last thing.How do I assign this email to my own NSString which I am returning? When I try to assign it,it says "variable is not assignable,missing block type specifier – Jpk May 01 '13 at 05:27
  • @ThilinaHewagama Fair enough. BTW - your regular expression may not be sufficient. The part before the `@` sign is supposed to be case sensitive and the part after isn't. Also, the part before the `@` sign is officially allowed to have many more characters than you have in your regular expression. – rmaddy May 01 '13 at 05:30
  • @Jimmy, to collect them, I added a NSMutableArray *emailsArray, and then inside the code you can add those email addresses to the mutable array. I added that part to the answer. – Thilina Chamath Hewagama May 01 '13 at 05:34
  • My function is a static function.It is returning an NSString.I am returning after replacing the parameter with the updated value.Please help me with this as I don't understand about blocks. – Jpk May 01 '13 at 05:37
  • @Jimmy,ok what do you want to return from your static method ? – Thilina Chamath Hewagama May 01 '13 at 05:38
  • I want to return an NSString – Jpk May 01 '13 at 05:49
  • 1
    This won't work. http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address – maroux May 01 '13 at 05:53
  • String of what ? do you want to return the first email address, or 2nd email address or number of email addresses or what ? – Thilina Chamath Hewagama May 01 '13 at 05:54
1

There are many good answers here on how to re-construct the original list of mail addresses from that somewhat messy string you found yourself with.

I would propose an NSScanner based solution, it seems to be well suited:

NSString *messyString = @"def_ghi@hotmail.com_abc_1@me.com";

NSScanner *mailScanner = [NSScanner scannerWithString:messyString];

NSMutableArray *mailAddresses = [NSMutableArray array];

while (YES) {

    NSString *recipientName;
    NSString *serverName;
    BOOL found = [mailScanner scanUpToString:@"@" intoString:&recipientName];
    found |= [mailScanner scanUpToString:@"_" intoString:&serverName];
    if ( !found ) break;

    [mailAddresses addObject:[recipientName stringByAppendingString:serverName]];

    // Consume the delimiting underscore
    found = [mailScanner scanString:@"_" intoString:nil];
    if ( !found ) break;
}
Monolo
  • 18,205
  • 17
  • 69
  • 103
  • I always forget about `NSScanner` for some reason. This is much simpler than my code. Two typos though - 1) It's `found |=`. 2) No need for the semicolon at the end of the `while` block. – rmaddy May 01 '13 at 05:36
  • Thanks for using cocoa-sheet in few questions :) – Anoop Vaidya May 01 '13 at 06:28
  • now I wonder `cocoa-sheet` is good name of `nswindow-sheet` or even `NSSheet` which actually doesn't exist. But I hear from many noobs. – Anoop Vaidya May 01 '13 at 06:34
0

Try

NSString *string = @"def_ghi@hotmail.com_abc_1@me.com";
NSArray *stringComponents = [string componentsSeparatedByString:@"_"];

NSMutableString *mutableString = [NSMutableString string];
NSMutableArray *emailIDs = [NSMutableArray array];
for (NSString *component in stringComponents) {
    if (!mutableString) {
        mutableString = [NSMutableString string];
    }
    [mutableString appendFormat:@"_%@",component];

    if ([component rangeOfString:@"@"].location != NSNotFound) {
        [emailIDs addObject:[mutableString substringFromIndex:1]];
        mutableString = nil;
    }
}

NSLog(@"%@",emailIDs);
Anupdas
  • 10,211
  • 2
  • 35
  • 60
0

Given your requirements then something like this should work for you:

NSString *string = @"def_ghi@hotmail.com_abc_1@me.com";
NSMutableArray *addresses = [NSMutableArray array];
NSUInteger currentIndex = 0; // start from beginning
// Stop when we are past the end of the string
while (currentIndex < string.length) {
    // Find the next @ symbol
    NSRange atRange = [string rangeOfString:@"@" options:0 range:NSMakeRange(currentIndex, string.length - currentIndex)];
    if (atRange.location != NSNotFound) {
        // We found another @, not look for the first underscore after the @
        NSRange underRange = [string rangeOfString:@"_" options:0 range:NSMakeRange(atRange.location, string.length - atRange.location)];
        if (underRange.location != NSNotFound) {
            // We found an underscore after the @, extract the email address
            NSString *address = [string substringWithRange:NSMakeRange(currentIndex, underRange.location - currentIndex)];
            [addresses addObject:address];
            currentIndex = underRange.location + 1;
        } else {
            // No underscore so this must be the last address in the string
            NSString *address = [string substringFromIndex:currentIndex];
            [addresses addObject:address];
            currentIndex = string.length;
        }
    } else {
        // no more @ symbols
        currentIndex = string.length;
    }
}

NSLog(@"Addresses: %@", addresses);
rmaddy
  • 314,917
  • 42
  • 532
  • 579