Как написать регулярные выражения в Objective C (NSRegularExpression)? - PullRequest
47 голосов
/ 14 февраля 2012

У меня есть это регулярное выражение, когда я тестирую его в PHP, но оно не работает в Objective C:

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

Я пытался убежать от escape-символов, но это тоже не помогло. Должен ли я сбежать от любого другого персонажа?

Это мой код в Цели 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);
}

- ОБНОВЛЕНИЕ -

Это регулярное выражение возвращает (в PHP) массив со значениями "domain-name" и "tld.tld2", но в Цели C я получаю только одно значение: "domain-name.tld.tld2"

- ОБНОВЛЕНИЕ 2 -

Это регулярное выражение извлекает «доменное имя» и «TLD» из строки:

  • domain.com = (домен, com)
  • domain.co.uk = (домен, 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-.co.uk = (тестовый домен)

он принимает действительное имя домена (не начинающееся и не заканчивающееся на «-» и длиной от 2 до 63 символов) и до двух частей TLD, если эти части являются действительными (по крайней мере, два символа, содержащие только буквы и цифры)

Надеюсь, это объяснение поможет.

Ответы [ 2 ]

76 голосов
/ 14 февраля 2012

A NSTextCheckingResult имеет несколько элементов, полученных путем индексации в нем.

[match rangeAtIndex:0]; - полное совпадение.
[match rangeAtIndex:1]; (если оно существует) - первое совпадение группы захвата.
etc

Вы можете использовать что-то вроде этого:

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:

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

Проверьте правильность диапазонов соответствия.

Проще в этом случае:

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

вывод на печать:

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

В этом случае проще:

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

вывод на печать:

matchText1: имя-домена
matchText2: tld.tld2

14 голосов
/ 14 февраля 2012

Согласно документации Apple , эти символы должны быть заключены в кавычки (используя \), чтобы рассматриваться как литералы:

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

Было бы также полезно, если бы вы могли объяснить, чего вы пытаетесь достичь. У вас есть тестовые приборы?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...