Shades Shades - 3 months ago 12
Swift Question

Return results from pattern matching

I have a string (HTML in this example case) which contains the same pattern for displaying the results of sports games. So, the HTML tags are known, but the values for each game are not.


In Perl, we can do this:

if ( $content =~ /\<\/a\>\<br\>(\d+)\<\/span\>\<br\>(\d+)\-(\d+).+\<\/a\>\<br\>(\d+)\<\/span\>\<br\>(\d+)\-(\d+)/) {
$visitingTeamScore = $1; // $1 is the 1st matched digit
$visitingTeamWins = $2; // $2 is the 2nd matched digit
$visitingTeamLosses = $3; // Etc
$homeTeamScore = $4;
$homeTeamWins = $5;
$homeTeamLosses = $6;
}


which returns the digits inside the parentheses, in this case 6 total integers of varying digit lengths. We can then assign those matches to variables.





From an answer in this question: Swift Get string between 2 strings in a string, I have the following Swift code:

extension String {
func sliceFrom(start: String, to: String) -> String? {
return (rangeOfString(start)?.endIndex).flatMap { sInd in
(rangeOfString(to, range: sInd..<endIndex)?.startIndex).map { eInd in
substringWithRange(sInd..<eInd)
}
}
}
}

let firstMatch = content?.sliceFrom("</a><br>", to: "</span>") // The first integer in the string


The problem comes in when getting the 4th integer which is also between
</a\><br>
and
</span>
so the resulting match will be the first digit again.

I can manually count the characters (which itself isn't a perfect science because the digits in each integer can differ) to do something ugly like:

let newRawHTML = content![content!.startIndex.advancedBy(15)...content!.startIndex.advancedBy(5)]


Another possibility is to remove anything matched already from the string, making it shorter for each subsequent search (which I'm not sure how to implement.) What's the way to do this? Is there any way in Swift to "pluck out" the matches?

Answer

The code you have shown as a Perl example, uses regular expression. And in case the pattern is getting a little bit complex, you'd better use NSRegularExpression directly.

let pattern = "</a><br>(\\d+)</span><br>(\\d+)-(\\d+).+</a><br>(\\d+)</span><br>(\\d+)-(\\d+)"
let regex = try! NSRegularExpression(pattern: pattern, options: [])
if let match = regex.firstMatchInString(content, options: [], range: NSRange(0..<content.utf16.count)) {
    let visitingTeamScore = (content as NSString).substringWithRange(match.rangeAtIndex(1))
    let visitingTeamWins = (content as NSString).substringWithRange(match.rangeAtIndex(2))
    let visitingTeamLosses = (content as NSString).substringWithRange(match.rangeAtIndex(3))
    let homeTeamScore = (content as NSString).substringWithRange(match.rangeAtIndex(4))
    let homeTeamWins = (content as NSString).substringWithRange(match.rangeAtIndex(5))
    let homeTeamLosses = (content as NSString).substringWithRange(match.rangeAtIndex(6))
    //...use the values
}
Comments