【问题标题】:Regular expression, specifying optional capture groups?正则表达式,指定可选的捕获组?
【发布时间】:2012-02-10 00:39:23
【问题描述】:

有没有办法编写一个正则表达式模式,该模式将根据输入文本创建一个或两个组。 (即)

// ONE
NSString *pattern = @""; ([0-9]+).([0-9]+)
NSString *inputText = @"ThisIs MyTest72.56String";
// OUTPUT match = 72.56, group1 = 72, group2 = 56

我想要得到的是:

// TWO
NSString *pattern = @""; ([0-9]+).([0-9]+)
NSString *inputText = @"ThisIs MyTest72String";
// OUTPUT match = 72, group1 = 72, group2 = Empty

我想我可以使用 (?:) 但这只会删除组

我追求的是:

Text = "ThisIs MyTest72String"
Match = 72
Group1 = 72
Group2 = Empty

Text = "ThisIs MyTest72.56String"
Match = 72.56
Group1 = 72
Group2 = 56

编辑:

这样的作品,虽然我想在最初的比赛中去掉“S”。

Pattern = ([0-9]+).([0-9]*)
Text = "ThisIs MyTest72String"
Match = 72S
Group1 = 72    //RangeAtIndex:1 {13,2}
Group2 = Empty //RangeAtIndex:2 {16,0}

Text = "ThisIs MyTest72.56String"
Match = 72.56
Group1 = 72
Group2 = 56

这很接近,但在“空”(Group2)的情况下,我期望 rangeAtIndex:2 等于 NSNotFound。文档说“如果其中一个捕获组未参加此特定比赛,则返回范围 {NSNotFound, 0}” 空组是否算作“未参加”?

【问题讨论】:

    标签: objective-c regex


    【解决方案1】:

    这能满足你的需求吗?

    ([0-9]+)(?:\.([0-9]+))?
    

    我已经转义了小数位(您没有转义,不确定您的目标语言是否需要)并将小数点及其后面的所有内容分组为可选的非捕获组。

    应该只是检查是否存在第二组。

    【讨论】:

    • 谢谢 rrrr,我是正则表达式的新手,但我知道什么是王不。最后一个问题是尾随的“?”似乎允许第一组自己匹配,你能解释一下它到底是做什么的吗?
    • 它是一个量词,使正则表达式中的前一项(在这种情况下是整个未捕获的组)是可选的,以便它可以出现 0 次或 1 次。
    【解决方案2】:

    这个怎么样:

    NSString *inputText = @"ThisIs MyTest72.56String";
    // Setup an NSError object to catch any failures
    NSError *error = NULL;  
    // create the NSRegularExpression object and initialize it with a pattern
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\d+.\\d+" options:NSRegularExpressionCaseInsensitive error:&error];
    // create an NSRange object using our regex object for the first match in the string httpline
    NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString:inputText options:0 range:NSMakeRange(0, [inputText length])];
    // check that our NSRange object is not equal to range of NSNotFound
    if (!NSEqualRanges(rangeOfFirstMatch, NSMakeRange(NSNotFound, 0))) {
        // Since we know that we found a match, get the substring from the parent string by using our NSRange object
        NSString *substringForFirstMatch = [inputText substringWithRange:rangeOfFirstMatch];
        NSLog(@"Extracted string: %@",substringForFirstMatch); // Extracted string: 72.56
    
    regex = [NSRegularExpression regularExpressionWithPattern:@"\\d+" options:NSRegularExpressionCaseInsensitive error:&error];
    NSArray *matches = [regex matchesInString:substringForFirstMatch options:0 range:NSMakeRange(0, [substringForFirstMatch length])];
    for (NSTextCheckingResult *match in matches) {
        NSString *matchString = [substringForFirstMatch substringWithRange:[match range]];
        NSLog(@"match string: %@", matchString);
        // match string: 72
        // match string: 56
    }
    
    }
    

    【讨论】:

    • 这失败了:"ThisIs MyTest72String""
    【解决方案3】:

    使用这种模式:

    pattern = @"([0-9]+)\.([0-9]+)?";
    

    然后在NSTextCheckingResult 中检查组范围位置是否为NSNotFound

    示例代码:

    NSString *pattern = @"([0-9]+).([0-9]+)?";
    NSString *string = @"ThisIs MyTest72.56String";
    //NSString *string = @"ThisIs MyTest72.XXString";
    
    NSRegularExpression *regex = [NSRegularExpression
                                  regularExpressionWithPattern:pattern
                                  options:NSRegularExpressionCaseInsensitive
                                  error:nil];
    
    NSTextCheckingResult *match = [regex firstMatchInString:string options:0 range:NSMakeRange(0, string.length)];
    
    for (int groupNumber=1; groupNumber<match.numberOfRanges; groupNumber+=1) {
        NSRange groupRange = [match rangeAtIndex:groupNumber];
        if (groupRange.location != NSNotFound)
            NSLog(@"match %d: '%@'", groupNumber, [string substringWithRange:groupRange]);
        else
            NSLog(@"match %d: '%@'", groupNumber, @"");
    }
    

    NSLog 输出:

    匹配 1:'72'
    比赛 2:'56'
    使用第二个模式“match 2: ''”。

    【讨论】:

    • 非常感谢,在“ThisIs MyTest73String”上使用您的模式时,有没有办法停止包括“S”在内的初始匹配?
    • 我的回答已经考虑到了这一点,你的问题是小数实际上匹配任何字符,因为它应该在正则表达式中。
    • 啊,我错过了,所以 (\.) 创建了一个包含“.”的新组。并且 (?:\.) 从匹配中删除该组。非常感谢...
    • 根据我的回答,小数点和第二组都需要作为同一组的一部分是可选的。
    • 感谢 CocoaFu 和 rrrr,您在解释这一点方面提供了很大帮助,非常感谢您的时间和精力。
    猜你喜欢
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-15
    相关资源
    最近更新 更多