50

I have this regex working when I test it in PHP but it doesn't work in Objective C:

(?:www\.)?((?!-)[a-zA-Z0-9-]{2,63}(?<!-))\.?((?:[a-zA-Z0-9]{2,})?(?:\.[a-zA-Z0-9]{2,})?)

I tried escaping the escape characters but that doesn't help either. Should I escape any other character?

This is my code in Objective C:

NSMutableString *searchedString = [NSMutableString stringWithString:@"domain-name.tld.tld2"];
NSError* error = nil;

NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:@"(?:www\\.)?((?!-)[a-zA-Z0-9-]{2,63}(?<!-))\\.?((?:[a-zA-Z0-9]{2,})?(?:\\.[a-zA-Z0-9]{2,})?)" options:0 error:&error];
NSArray* matches = [regex matchesInString:searchedString options:0 range:NSMakeRange(0, [searchedString length])];
for ( NSTextCheckingResult* match in matches )
{
    NSString* matchText = [searchedString substringWithRange:[match range]];
    NSLog(@"match: %@", matchText);
}

-- UPDATE --

This regex returns (in PHP) the array with values "domain-name" and "tld.tld2" but in Objective C i get only one value: "domain-name.tld.tld2"

-- UPDATE 2 --

This regex extracts 'domain name' and 'TLD' from the string:

  • domain.com = (domain, com)
  • domain.co.uk = (domain, co.uk)
  • -test-domain.co.u = (test-domain, co)
  • -test-domain.co.uk- = (test-domain, co.uk)
  • -test-domain.co.u-k = (test-domain, co)
  • -test-domain.co-m = (test-domain)
  • -test-domain-.co.uk = (test-domain)

it takes the valid domain name (not starting or ending with '-' and between 2 and 63 characters long), and up to two parts of a TLD if the parts are valid (at least two characters long containing only letters and numbers)

Hope this explanation helps.

budiDino
  • 10,932
  • 8
  • 84
  • 83
  • maybe this helps? http://stackoverflow.com/questions/5478170/regular-expression-in-ios – dom Feb 14 '12 at 11:49
  • 2
    I think Dino is asking How to convert existing regex to ObjectiveC code. It doesn't matter what the regex does. – Edi Budimilic Feb 14 '12 at 11:56

2 Answers2

81

A NSTextCheckingResult has multiple items obtained by indexing into it.

[match rangeAtIndex:0]; is the full match.
[match rangeAtIndex:1]; (if it exists) is the first capture group match.
etc.

You can use something like this:

NSString *searchedString = @"domain-name.tld.tld2";
NSRange   searchedRange = NSMakeRange(0, [searchedString length]);
NSString *pattern = @"(?:www\\.)?((?!-)[a-zA-Z0-9-]{2,63}(?<!-))\\.?((?:[a-zA-Z0-9]{2,})?(?:\\.[a-zA-Z0-9]{2,})?)";
NSError  *error = nil;

NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern: pattern options:0 error:&error];
NSArray* matches = [regex matchesInString:searchedString options:0 range: searchedRange];
for (NSTextCheckingResult* match in matches) {
    NSString* matchText = [searchedString substringWithRange:[match range]];
    NSLog(@"match: %@", matchText);
    NSRange group1 = [match rangeAtIndex:1];
    NSRange group2 = [match rangeAtIndex:2];
    NSLog(@"group1: %@", [searchedString substringWithRange:group1]);
    NSLog(@"group2: %@", [searchedString substringWithRange:group2]);
}

NSLog output:

match: domain-name.tld.tld2
domain-name
tld.tld2

Do test that the match ranges are valid.

More simply in this case:

NSString *searchedString = @"domain-name.tld.tld2";
NSRange   searchedRange = NSMakeRange(0, [searchedString length]);
NSString *pattern = @"(?:www\\.)?((?!-)[a-zA-Z0-9-]{2,63}(?<!-))\\.?((?:[a-zA-Z0-9]{2,})?(?:\\.[a-zA-Z0-9]{2,})?)";
NSError  *error = nil;

NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:searchedString options:0 range: searchedRange];
NSLog(@"group1: %@", [searchedString substringWithRange:[match rangeAtIndex:1]]);
NSLog(@"group2: %@", [searchedString substringWithRange:[match rangeAtIndex:2]]);

Swift 3.0:

let searchedString = "domain-name.tld.tld2"
let nsSearchedString = searchedString as NSString
let searchedRange = NSMakeRange(0, searchedString.characters.count)
let pattern = "(?:www\\.)?((?!-)[a-zA-Z0-9-]{2,63}(?<!-))\\.?((?:[a-zA-Z0-9]{2,})?(?:\\.[a-zA-Z0-9]{2,})?)"

do {
    let regex = try NSRegularExpression(pattern:pattern, options: [])
    let matches = regex.matches(in:searchedString, options:[], range:searchedRange)
    for match in matches {
        let matchText = nsSearchedString.substring(with:match.range);
        print("match: \(matchText)");

        let group1 : NSRange = match.rangeAt(1)
        let matchText1 = nsSearchedString.substring(with: group1)
        print("matchText1: \(matchText1)")

        let group2 = match.rangeAt(2)
        let matchText2 = nsSearchedString.substring(with: group2)
        print("matchText2: \(matchText2)")
    }
} catch let error as NSError {
    print(error.localizedDescription)
}

print output:

match: domain-name.tld.tld2
matchText1: domain-name
matchText2: tld.tld2

More simply in this case:

do {
    let regex = try NSRegularExpression(pattern:pattern, options: [])
    let match = regex.firstMatch(in:searchedString, options:[], range:searchedRange)

    let matchText1 = nsSearchedString.substring(with: match!.rangeAt(1))
    print("matchText1: \(matchText1)")

    let matchText2 = nsSearchedString.substring(with: match!.rangeAt(2))
    print("matchText2: \(matchText2)")

} catch let error as NSError {
    print(error.localizedDescription)
}

print output:

matchText1: domain-name
matchText2: tld.tld2

zaph
  • 108,117
  • 19
  • 176
  • 215
  • my code above currently displays all of the matched results (full match, domain-name, TLDs) and that works when I test that regex online but it returns only the first value (full match) when tested in Objective C. – budiDino Feb 14 '12 at 12:35
  • Looks like I have a problem with the "NSMutableString stringWithString" part because the regex doesn't match the same things online VS Objective C – budiDino Feb 14 '12 at 12:36
  • 2
    I'm sorry, you were right. Looks like I didn't understand how to obtain the results correctly. I'm a web developer at my core and Objective C just makes everything I try to do at least 2 times harder than it is in PHP :) Thanks again. – budiDino Feb 14 '12 at 12:51
  • 2
    The whole `NSTextCheckingResult` is a world of hurt because it does to much and is over-kill for regex. It is not readily apparent that it contains the capture groups. – zaph Feb 14 '12 at 12:55
  • lol, I just saw my 2nd comment here. I was thinking about "NSRegularExpression regularExpressionWithPattern" but copy-pasted "NSMutableString stringWithString" :) Anyway, I love the community here! – budiDino Feb 15 '12 at 09:18
  • 1
    Very useful solution! It's save my time, and makes my day!) Thanks! – Nubaslon Feb 11 '16 at 14:52
16

According to Apple's documentation, these characters must be quoted (using \) to be treated as literals:

* ? + [ ( ) { } ^ $ | \ . /

It would also help if you could explain what you are trying to achieve. Do you have any test fixtures?

hwaxxer
  • 3,308
  • 1
  • 20
  • 37