Search code examples
iosswiftnsdateisnumeric

Detect numeric year from string using Swift


I am looking for a way to detect years e.g. 2019. The requirements I think would be that the numbers are in a row, have four digits and are not adjacent to letters or special characters. So I'd like to get the method to return "2019" in each of the following cases:

"2019"
"in 2019
"Before 2019, all IOS apps were written in one of 2 ways"

But exclude it from:

"1234z20191234

There are a lot of ways to detect the numbers in a string as seen here such as

let newString = origString
    .components(separatedBy:CharacterSet.decimalDigits.inverted)
    .joined(separator: "")

But they don't pull out each series of numbers to test for length and adjacency.

Data detector can try to pull out a date but going from the possible date to the year that might have been in the starting text seems error prone e.g. working with something like:

“2018-08-31 04:00:00 +0000”, “America/Los_Angeles”, 18000.0

Can anyone suggest a reliable way to retrieve a numerical year from a string?


Solution

  • You might use regular expression, searching for four digits ([0-9]{4}) between word boundaries (\b), e.g.

    let strings = [
        "2019",
        "in 2019",
        "Before 2019, all IOS apps were written in one of 2 ways",
        "1234z20191234"
    ]
    
    for string in strings {
        if let range = string.range(of: #"\b[0-9]{4}\b"#, options: .regularExpression) {
            let year = String(string[range])
            print(year)
        } else {
            print("No year found")
        }
    }
    

    Producing:

    2019
    2019
    2019
    No year found

    Note, the above uses Swift 5’s Extended String Delimiters, #" and "#. If doing this in earlier Swift versions, you’ll want to just escape the backslashes with yet another backslash:

    if let range = string.range(of: "\\b[0-9]{4}\\b", options: .regularExpression) {
        ...
    }
    

    Clearly if you want to narrow the range of four digit numbers recognized as years, you’d have to tweak the regular expression or supplement it with some logic. But your question doesn’t identify what criteria you want to use to detect years.