-4

Given a String taken from the internet, such as:

"A dusting of snow giving way to moderate rain (total 10mm) heaviest on Thu night. Freeze-thaw conditions (max 8°C on Fri morning, min -2°C on Wed night). Mainly strong winds."

Using Swift 3, I want to convert the temperatures to Fahrenheit. So I need to find any numbers that have °C after them (including negative numbers); convert them to Fahrenheit, and then replace the integer back into the string.

I was originally trying to use: components(separatedBy: String). I did get it to work with this method. Although I think there is probably a better way.

func convertStringToFahrenheit (_ message: String) -> String{
    var stringBuilder = String()
    let stringArray = message.components(separatedBy: "°C")
    for subString in stringArray {
        if subString != stringArray.last {
            if subString.contains("(max "){
                let subStringArray = subString.components(separatedBy: "(max ")
                stringBuilder.append(subStringArray[0])
                stringBuilder.append("(max ")
                if var tempInt = Int(subStringArray[1]){
                    tempInt = convertCelsiusToFahrenheit(tempInt)
                    stringBuilder.append(String(tempInt))
                    stringBuilder.append("°F")
                }
            }
            else if subString.contains(", min "){
                let subStringArray = subString.components(separatedBy: ", min ")
                stringBuilder.append(subStringArray[0])
                stringBuilder.append(", min ")
                if var tempInt = Int(subStringArray[1]){
                    tempInt = convertCelsiusToFahrenheit(tempInt)
                    stringBuilder.append(String(tempInt))
                    stringBuilder.append("°F")
                }
            }
        }
        else {
            stringBuilder.append(subString)
        }
    }
    return stringBuilder
}
Justin Lewis
  • 534
  • 1
  • 5
  • 22

1 Answers1

1

A job for regular expression.

The pattern "(-?\\d+)°C" searches for

  • an optional minus sign -?
  • followed by one or more digits \\d+
  • followed by °C

The group – within the parentheses – captures the degrees value.

var string = "A dusting of snow giving way to moderate rain (total 10mm) heaviest on Thu night. Freeze-thaw conditions (max 8°C on Fri morning, min -2°C on Wed night). Mainly strong winds."

let pattern = "(-?\\d+)°C"

do {
    let regex = try NSRegularExpression(pattern: pattern)
    let matches = regex.matches(in: string, range: NSRange(location: 0, length: string.utf16.count))
    for match in matches.reversed() { // reversed() is crucial to preserve the indexes.
        let celsius = (string as NSString).substring(with: match.rangeAt(1))
        let fahrenheit = Double(celsius)! * 1.8 + 32
        let range = match.range
        let start = string.index(string.startIndex, offsetBy: range.location)
        let end = string.index(start, offsetBy: range.length)
        string = string.replacingCharacters(in: start..<end, with: String(format: "%.0f°F", fahrenheit))
    }
} catch {
    print("Regex Error:", error)
}

print(string)

The most complicated part of the code is the conversion NSRange -> Range<String.Index>

vadian
  • 274,689
  • 30
  • 353
  • 361