4

I was trying to translate the code from swift 2 to swift 4 and came across this error

Errors thrown from here are not handled

So I did this but now it tells me to return a string. Any idea how to do this?

func formatSentence(sentence:String) -> String
{
    do {
        let regex = try NSRegularExpression(pattern: "\\W+", options: .caseInsensitive)
        let modifiedString = regex.stringByReplacingMatches(in: sentence, options: [], range: NSRange(location: 0,length: sentence.count), withTemplate: "")

    } catch {
        print(error)
    }

    //I tried adding it here the return modifiedString but gives me error
}

This is what the original function looks like

func formatSentence(sentence:String) -> String
{
    let regex = NSRegularExpression(pattern: "\\W+", options: .caseInsensitive)//NSRegularExpression(pattern:"\\W+", options: .CaseInsensitive, error: nil)
    let modifiedString = regex.stringByReplacingMatches(in: sentence, options: [], range: NSRange(location: 0,length: sentence.count), withTemplate: "")

    return modifiedString
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044

2 Answers2

9

It depends upon how you want to handle the error condition. There are a few options:

  1. You could make it return String?, where nil means there was an error:

    func formatSentence(_ sentence: String) -> String? {
        do {
            let regex = try NSRegularExpression(pattern: "\\W+", options: .caseInsensitive)
            let range = NSRange(sentence.startIndex..., in: sentence)
            return regex.stringByReplacingMatches(in: sentence, range: range, withTemplate: "")
        } catch {
            print(error)
            return nil
        }
    }
    

    And then you'd do something like:

    guard let sentence = formatSentence(string) else { 
        // handle error here
        return
    }
    
    // use `sentence` here
    
  2. You could define your function as one that throws the error if it encounters one:

    func formatSentence(_ sentence: String) throws -> String {
        let regex = try NSRegularExpression(pattern: "\\W+", options: .caseInsensitive)
        let range = NSRange(sentence.startIndex..., in: sentence)
        return regex.stringByReplacingMatches(in: sentence, range: range, withTemplate: "")
    }
    

    And then you'd catch errors at the calling point:

    do {
        let sentence = try formatSentence(string)
    
        // use `sentence` here
    } catch {
        // handle error here
        print(error)
    }
    
  3. Or, given that you know your pattern is valid, you could use try! knowing that it cannot fail:

    func formatSentence(_ sentence: String) -> String {
        let regex = try! NSRegularExpression(pattern: "\\W+", options: .caseInsensitive)
        let range = NSRange(sentence.startIndex..., in: sentence)
        return regex.stringByReplacingMatches(in: sentence, range: range, withTemplate: "")
    }
    

    And then you can just do:

    let sentence = formatSentence(string)
    

    You only use this last pattern if you know, with 100% confidence, that NSRegularExpression cannot fail given your regex pattern (such as in this situation).


As an aside, you might cut the Gordian knot and just use replacingOccurrences with .regularExpression option:

func formatSentence(_ sentence: String) -> String {
    return sentence.replacingOccurrences(of: "\\W+", with: "", options: .regularExpression)
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • When creating a `NSRange` you pass the `String` utf16 count `NSRange(location: 0,length: sentence.utf16.count)` or cast the `String` to `NSString` and pass its `length` – Leo Dabus Jan 18 '18 at 06:19
  • Another option is to use the new Swift 4 initializer `init(_ region: R, in target: S) where R : RangeExpression, S : StringProtocol, R.Bound == String.Index, S.Index == String.Index` to convert from `Range` to `NSRange`: `NSRange(sentence.startIndex.. – Leo Dabus Jan 18 '18 at 06:30
  • 1
    I was focused on the throwing `NSRegularExpression` and the returning of a string, but you are correct. I've updated my examples accordingly. Like I said at the end of my answer, he really should just use `replacingOccurrences(of:with:options:)`, and eliminate all of that silliness altogether. – Rob Jan 18 '18 at 07:32
-1

Set default values at the beginning of the function like so:

func formatSentence(sentence:String) -> String {
   var regex = ""
   var modifiedString = "" 

   do {
       regex = try NSRegularExpression(pattern: "\\W+", options: .caseInsensitive)
       modifiedString = regex.stringByReplacingMatches(in: sentence, options: [], range: NSRange(location: 0,length: sentence.count), withTemplate: "")

   } catch {
       print(error)
   }
   return modifiedString
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
Xcoder
  • 1,433
  • 3
  • 17
  • 37
  • The comment I posted at Rob’s answer applies here as well – Leo Dabus Jan 18 '18 at 06:25
  • Like the post below, this is a bad idea. Returning something valid from an error means that on the other end, you have to check if `modifiedString` is something other than empty and that gets unnecessarily complex – kakubei Jan 14 '19 at 15:22