Isuru Isuru - 4 months ago 17
Swift Question

Convert Range<Int> to Range<String.Index>

The below function given a

NSString
, removes the HTML tags from that string and returns the result also as a
NSString
.

private func removeHTMLTags(source: NSString) -> NSString {
var range = NSMakeRange(0, 0)
let HTMLTags = "<[^>]*>"
var sourceString = source

while sourceString.rangeOfString(HTMLTags, options: NSStringCompareOptions.RegularExpressionSearch).location != NSNotFound {
range = sourceString.rangeOfString(HTMLTags, options: NSStringCompareOptions.RegularExpressionSearch)
sourceString = sourceString.stringByReplacingCharactersInRange(range, withString: "")
}
return sourceString;
}


I'm trying to rewrite this in pure Swift. I'm facing a issue with the
Range
type in Swift.

In the original code function,
range
variable is declared of type
NSRange
. In my version I cannot do that because the line
sourceString.rangeOfString(HTMLTags, options: NSStringCompareOptions.RegularExpressionSearch)
inside the while loop returns the type
Range<String.Index>
and it would give me the error Cannot convert the expression's type '()' to type 'NSRange'.

So I declared the variable like this
var range = Range(start: 0, end: 0)
but now I get a couple of new errors.

Cannot convert the expression's type '()' to type 'Range' error at the line

range = sourceString.rangeOfString(HTMLTags, options: NSStringCompareOptions.RegularExpressionSearch)


And 'Int' is not identical to 'String.Index' at the line

sourceString = sourceString.stringByReplacingCharactersInRange(range, withString: "")


I searched for a solution to this and came across this post. Then I changed the
range
variable declaration to this.

var range = Range<String.Index>(start: 0, end: 0)


But I get this new error now! Extra argument 'end' in call

I can't figure out a way to resolve this. Can anyone help please?

Thank you.

Answer

The Swift String method rangeOfString() returns an optional Range? which does not have a location property but can be checked with conditional binding (if let).

And if you replace the NSString method stringByReplacingCharactersInRange() by the Swift String method replaceRange() (or in this case simply by removeRange()) then you can work purely with Range<Swift.Index> without converting it to NSRange or Range<Int>.

func removeHTMLTags(source : String) -> String {

    var sourceString = source
    let HTMLTags = "<[^>]*>"

    while let range = sourceString.rangeOfString(HTMLTags, options: .RegularExpressionSearch) {
        sourceString.removeRange(range)
    }

    return sourceString;
}
Comments