使用 NSRegularExpression 解析日期时出现问题

Problems while parsing date with NSRegularExpression

我正在尝试解析日期格式为 MM/YY 的字符串并存储月份和年份变量。

我写了这段代码,当我传递像“1”这样的字符串时,我不明白为什么:

这是我的代码(正则表达式只有两组,所以我不明白范围的数量在理论上什至可以超过 2 个)。

let regex = NSRegularExpression(pattern: "^(\d{1,2})?[\s/]*(\d{1,2})?", options: NSRegularExpressionOptions.allZeros, error: nil)
// Expiry date string is "1"
let match = regex?.firstMatchInString(expiryDate, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, expiryDateNS.length))

if let match = match {
    let monthRange = match.rangeAtIndex(1)
    // next string works correct - month contains "1"
    var month = expiryDateNS.substringWithRange(monthRange)

    if match.numberOfRanges > 1 {  // match.numberOfRanges returns 3
        let yearRange = match.rangeAtIndex(2) // returns LONG_MAX as location, 0 as length
        // next line will crash
        expiryYear = expiryDateNS.substringWithRange(yearRange)
    }
}

更新 正如@matt 所问,我在这里添加了几个例子。

当我用上面的代码解析字符串“1”时,match.numberOfRanges 是 3,match.rangeAtindex(2) 是 (9223372036854775807,0)

对于输入字符串"1",匹配到第二个捕获组(\d{1,2})? 零次。在这种情况下 match.rangeAtIndex(2).locationNSNotFound(恰好是 Int.max = 9223372036854775807).

对于输入字符串 "/12",第一个捕获组 (\d{1,2})? 将 匹配零次。所以你必须检查这种情况:

var month = ""
var year = ""
if let match = match {
    let monthRange = match.rangeAtIndex(1)
    if monthRange.location != NSNotFound {
        month = expiryDateNS.substringWithRange(monthRange)
    }

    let yearRange = match.rangeAtIndex(2)
    if yearRange.location != NSNotFound {
        year = expiryDateNS.substringWithRange(yearRange)
    }
}

对于这么简单的字符串和模式,NSScanner更容易。此函数为您指定的输入提供您指定的输出:

func analyze(s:String) -> (String,String) {
    var result = ("","")
    let sc = NSScanner(string: s)
    var first:Int32 = 0
    let ok = sc.scanInt(&first)
    if ok {
        result.0 = String(first)
        let ok = sc.scanUpToCharactersFromSet(NSCharacterSet.decimalDigitCharacterSet(), intoString: nil)
        if !sc.atEnd {
            var second:Int32 = 0
            let ok = sc.scanInt(&second)
            if ok {
                result.1 = String(second)
            }
        }
    }
    return result
}

因此,如果您决定拆分您的字符串,您可以执行以下操作:

let date = "12 / 45".stringByReplacingOccurrencesOfString(" ", withString: "", options: .LiteralSearch, range: nil)

let components = date.componentsSeparatedByString("/")
let month =  components.count > 0 ? components.first! : ""
let expiryYear = components.count > 1 ? components.last! : ""