如何在Objective C(NSRegularExpression)中编写正则表达式?

Posted

技术标签:

【中文标题】如何在Objective C(NSRegularExpression)中编写正则表达式?【英文标题】:How to write regular expressions in Objective C (NSRegularExpression)? 【发布时间】:2012-03-05 18:47:42 【问题描述】:

当我在 php 中测试它时,我有这个正则表达式工作,但它在 Objective C 中不起作用:

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

我尝试转义转义字符,但这也无济于事。我应该转义任何其他角色吗?

这是我在 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);

-- 更新--

这个正则表达式返回(在 PHP 中)具有值“domain-name”和“tld.tld2”的数组,但在 Objective C 中我只得到一个值:“domain-name.tld.tld2”

-- 更新 2--

这个正则表达式从字符串中提取“域名”和“TLD”:

domain.com =(域,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)

它需要有效的域名(不以“-”开头或结尾,长度介于 2 到 63 个字符之间),如果部分有效,则最多包含两个部分 TLD(至少两个字符长,仅包含字母和数字)

希望这个解释有所帮助。

【问题讨论】:

也许这有帮助? ***.com/questions/5478170/regular-expression-in-ios 我认为 Dino 是在询问如何将现有的正则表达式转换为 ObjectiveC 代码。正则表达式的作用无关紧要。 【参考方案1】:

根据Apple's documentation,这些字符必须被引用(使用\)才能被视为文字:

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

如果您能解释您想要达到的目标,这也会有所帮助。你有测试夹具吗?

【讨论】:

在标准正则表达式意义上?还是被视为正则表达式运算符? 我一直在尝试 obj-c 中的正则表达式,但我无法让 \[ 工作。有什么想法吗? 您必须先转义反斜杠。 \\[ 我还要补充一点,如果您要搜索 #(作为文字),则 NSRegularExpression 初始化将失败。我用 \u0023(或者更确切地说是 \\u0023)替换了它并且有效。【参考方案2】:

NSTextCheckingResult 有多个通过索引获得的项目。

[match rangeAtIndex:0]; 是完整匹配。[match rangeAtIndex:1];(如果存在)是第一个捕获组匹配。 等等。

你可以这样使用:

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 输出:

匹配:域名.tld.tld2 域名 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]]);

斯威夫特 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)

打印输出:

匹配:域名.tld.tld2 matchText1:域名 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

【讨论】:

我上面的代码当前显示所有匹配的结果(完全匹配、域名、TLD),当我在线测试该正则表达式时有效,但在测试时它只返回第一个值(完全匹配)在目标 C 中。 看起来我的“NSMutableString stringWithString”部分有问题,因为正则表达式与在线 VS Objective C 的内容不匹配 对不起,你是对的。看起来我不明白如何正确获得结果。我的核心是 Web 开发人员,Objective C 使我尝试做的所有事情至少比 PHP 难 2 倍 :) 再次感谢。 整个NSTextCheckingResult 是一个充满伤害的世界,因为它做了很多事情并且对于正则表达式来说太过分了。它包含捕获组并不明显。 非常有用的解决方案!它节省了我的时间,让我开心!)谢谢!

以上是关于如何在Objective C(NSRegularExpression)中编写正则表达式?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Objective c中获取目录中文件的创建日期

如何在混合代码 Objective-C/C++ 文件(.mm 文件)中使用 PHPhotoLibrary?

如何在objective c框架中使用swift扩展

如何在 C / Objective-C 中将字符串文字拆分为多行?

如何在 Objective C 中对齐内存?

如何在Windows上编译Objective-C