Reputation:
I'm having a problem with understand how I can work with substrings in Swift. Basically, I'm getting a JSON value that has a string with the following format:
<a href="#">Something</a>
I'm trying to get rid of the HTML anchor tag with Swift so I'm left with Something
. My thought was to find the index of every <
and >
in the string so then I could just do a substringWithRange and advance up to the right index.
My problem is that I can't figure out how to find the index. I've read that Swift doesn't support the index (unless you extend it.)
I don't want to add CPU cycles unnecessarily. So my question is, how do I find the indexes in a way that is not inefficient? Or, is there a better way of filtering out the tags?
Edit: Converted Andrew's first code sample to a function:
func formatTwitterSource(rawStr: String) -> String {
let unParsedString = rawStr
var midParseString = ""
var parsedString = ""
if let firstEndIndex = find(unParsedString, ">") {
midParseString = unParsedString[Range<String.Index>(start: firstEndIndex.successor(), end: unParsedString.endIndex)]
if let secondStartIndex = find(midParseString, "<") {
parsedString = midParseString[Range<String.Index>(start: midParseString.startIndex, end: secondStartIndex)]
}
}
return parsedString
}
Nothing too complicated. It takes in a String that has the tags in it. Then it uses Andrew's magic to parse everything out. I renamed the variables and made them clearer so you can see which variable does what in the process. Then in the end, it returns the parsed string.
Upvotes: 0
Views: 459
Reputation: 11555
Even though this question has been already answered, I am adding solution based on regex.
let pattern = "<.*>(.*)<.*>"
let src = "<a href=\"#\">Something</a>"
var error: NSError? = nil
var regex = NSRegularExpression(pattern: pattern, options: .DotMatchesLineSeparators, error: &error)
if let regex = regex {
var result = regex.stringByReplacingMatchesInString(src, options: nil, range: NSRange(location:0,
length:countElements(src)), withTemplate: "$1")
println(result)
}
Upvotes: 0
Reputation: 1794
You could do something like this, but it isn't pretty really. Obviously you would want to factor this into a function and possibly allow for various start/end tokens.
let testText = "<a href=\"#\">Something</a>"
if let firstEndIndex = find(testText, ">") {
let testText2 = testText[Range<String.Index>(start: firstEndIndex.successor(), end: testText.endIndex)]
if let secondStartIndex = find(testText2, "<") {
let testText3 = testText2[Range<String.Index>(start: testText2.startIndex, end: secondStartIndex)]
}
}
Working on this a little further and came up with something a little more idiomatic?
let startSplits = split(testText, { $0 == "<" })
let strippedValues = map(startSplits) { (s) -> String? in
if let endIndex = find(s, ">") {
return s[Range<String.Index>(start: endIndex.successor(), end: s.endIndex)]
}
return nil
}
let strings = map(filter(strippedValues, { $0 != "" })) { $0! }
It uses a little more functional style there at the end. Not sure I much enjoy the Swift style of map/filter compared to Haskell. But anyhow, the one potentially dangerous part is that forced unwrapping in the final map
. If you can live with a result of [String?]
then it isn't necessary.
Upvotes: 1