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

时间:2015-05-18 14:43:04

标签: objective-c regex swift cocoa 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所问,我在这里添加了一些例子。

  • String" 1"应该被解析并存储为month == "1"expiryYear == ""
  • String" 12"应该被解析并存储为month == "12"expiryYear == ""
  • String" 12/45"应该被解析并存储为month == "12"expiryYear == "45"

当我解析字符串" 1"代码match.numberOfRanges以上为3且match.rangeAtindex(2)为(9223372036854775807,0)

3 个答案:

答案 0 :(得分:1)

对于输入字符串"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) } } 会 匹配零次。所以你必须检查这种情况:

with data as 
(
  ...
),
temp as 
(
  select     d.id 
            ,d.AddedOn
            ,dprev.AddedOn as PrevAddedOn
            ,dnext.AddedOn as NextAddedOn
  FROM      data d
            left JOIN
            data dprev on   dprev.id = d.id
                       and  dprev.AddedOn = dateadd(d, -1, d.AddedOn)
            left JOIN
            data dnext on   dnext.id = d.id
                       and  dnext.AddedOn = dateadd(d,  1, d.AddedOn)
),
starts AS
(
  select     id
            ,AddedOn 
  from      temp 
  where     PrevAddedOn is NULL
),
ends as
(
  select     id
            ,AddedOn
  from      temp
  where     NextAddedon is NULL
)
SELECT   s.id as id
        ,s.AddedOn as StartDate
        ,(select min(e.AddedOn) from ends e where e.id = s.id and e.AddedOn >= s.AddedOn) as EndDate
from    starts s

答案 1 :(得分:1)

对于这样一个简单的字符串和模式,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
}

答案 2 :(得分:1)

因此,如果你决定拆分你的字符串,你可以按照以下步骤进行:

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! : ""