Manny
Manny

Reputation: 309

How to convert a time pattern from a string to TimeInterval in Swift?

I have an array of strings that contains a time pattern (e.g '30 min'):

let arrayOfStrings: [String] = ["Episode 1 - 23 min", "Episode 2 - 42 min", "Episode 3 - 45 min"] 

func convertToTimeInterval(from string: String) -> TimeInterval {
    // logic here...
    return timeInterval // Double
}

So using such a method, I want from the results:

arrayOfStrings.forEach { string in 
   print(convertToTimeInterval(from: string))
}

// Prints
1380 // timeinterval from "23 min"
2520 // timeinterval from "42 min"
2700 // timeinterval from "45 min"

Thanks for your help!

Upvotes: 0

Views: 885

Answers (2)

vadian
vadian

Reputation: 285039

A rather underestimated but powerful API in Objective-C and Swift is (NS)Scanner.

Assuming there is always a hyphen and a whitespace character before the duration value just scanUpTo "- " then scan the pattern and then scan the numeric value as Double and multiply it with 60.

func convertToTimeInterval(from string: String) -> TimeInterval? {
    let scanner = Scanner(string: string)
    scanner.scanUpToString("- ")
    scanner.scanString("- ")
    guard let duration = scanner.scanDouble() else { return nil }
    return duration * 60.0
}

Or – a bit more elaborate – with NSRegularExpression. The pattern captures one or more digits after " - "

func convertToTimeInterval(from string: String) -> TimeInterval? {
    let regex = try! NSRegularExpression(pattern: #"\s-\s(\d+)"#)
    guard let firstMatch = regex.firstMatch(in: string, range: NSRange(string.startIndex..., in: string)) else { return nil }
    let durationRange = Range(firstMatch.range(at: 1), in: string)!
    return Double((string[durationRange]))! * 60.0
}

However it becomes more convenient with the new Regex API introduced in Swift 5.7

func convertToTimeInterval(from string: String) -> TimeInterval? {
    let regex = Regex {
        " - "
         Capture { OneOrMore(.digit) } transform: {
             Double($0)! * 60.0
         }
    }
    return string.firstMatch(of: regex)?.output.1
}

Upvotes: 2

you could try this approach, where each string in the array is split into sections, and the minutes extracted and returned as a Double/TimeInterval.

This should (not tested) cater for multiple languages that uses Western Arabic numerals

let arrayOfStrings: [String] = ["Episode 1 - 23 min", "Episode 2 - 42 min", "Episode 3 - 45 min"]

arrayOfStrings.forEach { string in
     let t = convertToTimeInterval(from: string)
     print("--> timeInterval: \(t) minutes or \(t * 60) seconds")
}

func convertToTimeInterval(from string: String) -> TimeInterval {
    if let last = string.split(separator: "-").last {
        let term2 = last.split(separator: " ")
        if let minutes = term2.first {
            if let result = Double(minutes.trimmingCharacters(in: .whitespacesAndNewlines)) {
                return result
            }
        }
    }
    return 0.0  // <-- adjust as desired
}

Upvotes: 0

Related Questions