使用 NSRegularExpression 解析日期时出现问题
Problems while parsing date with NSRegularExpression
我正在尝试解析日期格式为 MM/YY 的字符串并存储月份和年份变量。
我写了这段代码,当我传递像“1”这样的字符串时,我不明白为什么:
match.numberOfRanges
== 3
match.rangeAtindex(2)
== (9223372036854775807,0)
这是我的代码(正则表达式只有两组,所以我不明白范围的数量在理论上什至可以超过 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”应该被解析并存储为
month == "1"
和 expiryYear == ""
- 字符串“12”应该被解析并存储为
month == "12"
和 expiryYear == ""
- 字符串“12/45”应该被解析并存储为
month == "12"
和 expiryYear == "45"
当我用上面的代码解析字符串“1”时,match.numberOfRanges
是 3,match.rangeAtindex(2)
是 (9223372036854775807,0)
对于输入字符串"1"
,匹配到第二个捕获组(\d{1,2})?
零次。在这种情况下
match.rangeAtIndex(2).location
是 NSNotFound
(恰好是
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! : ""
我正在尝试解析日期格式为 MM/YY 的字符串并存储月份和年份变量。
我写了这段代码,当我传递像“1”这样的字符串时,我不明白为什么:
match.numberOfRanges
== 3match.rangeAtindex(2)
== (9223372036854775807,0)
这是我的代码(正则表达式只有两组,所以我不明白范围的数量在理论上什至可以超过 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”应该被解析并存储为
month == "1"
和expiryYear == ""
- 字符串“12”应该被解析并存储为
month == "12"
和expiryYear == ""
- 字符串“12/45”应该被解析并存储为
month == "12"
和expiryYear == "45"
当我用上面的代码解析字符串“1”时,match.numberOfRanges
是 3,match.rangeAtindex(2)
是 (9223372036854775807,0)
对于输入字符串"1"
,匹配到第二个捕获组(\d{1,2})?
零次。在这种情况下
match.rangeAtIndex(2).location
是 NSNotFound
(恰好是
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! : ""