我正在尝试从 HTML 字符串中提取信息,但得到了意外的结果。我使用的代码如下:
let html: NSString? = "<tbody><tr><td sortkey=\"20151003\">03 Oct 2015</td><td>8,852.61</td><td>1,383.68</td><td>Text</td></tr><tr><td sortkey=\"20151004\">04 Oct 2015</td><td>2,577.14</td><td>282.49</td><td>Text</td></tr></tbody>"
let rowPattern = "<tr>\\s*<td s.*?<\\/tr>"
let rowRegex = try! NSRegularExpression(pattern: rowPattern, options: [])
let rowMatches = rowRegex.matchesInString(String(html), options: [], range: NSMakeRange(0, html!.length))
for rowMatch in rowMatches {
let rowString: NSString = html!.substringWithRange(rowMatch.resultByAdjustingRangesWithOffset(-9).range)
print(rowString)
let valPattern = "<td>(.*?)<\\/td>|<td.*?\"(.*?)\">.*?<\\/td>"
let valRegex = try! NSRegularExpression(pattern: valPattern, options: [])
let valMatches = valRegex.matchesInString(String(rowString), options: [], range: NSMakeRange(0, rowString.length))
for valMatch in valMatches {
print(valMatch.rangeAtIndex(1))
// let value = rowString.substringWithRange(valMatch.rangeAtIndex(1))
// print(value)
}
}
输出是:
<tr><td sortkey="20151003">03 Oct 2015</td><td>8,852.61</td><td>1,383.68</td><td>Text</td></tr>
(9223372036854775807,0)
(47,8)
(64,8)
(81,4)
首先,请注意,我需要将 rowMatch 的范围偏移 -9 才能获得正确的结果。我不知道为什么会这样。
其次,第一个匹配项返回的范围是 (9223372036854775807,0),这显然不正确并引发错误。再说一遍,我不明白这里出了什么问题,但我怀疑这可能是我的正则表达式模式的问题。其他范围都是正确的。
仅供引用,print(value)
的预期输出为:
20151003
8,852.61
1,383.68
Text
编辑:
经过进一步的实验,我发现了以下内容:
valMatches[0].rangeAtIndex(2)
给出第一个匹配的正确范围,但其余匹配则需要 valMatches[0].rangeAtIndex(1)
。我不确定这是否是正确的行为,或者是否是 @t4nhpt 在下面的答案中建议的错误。不管怎样,如果有人能解释一下发生了什么,那就太好了。
最佳答案
第一个问题是 let html: NSString? = "..."
是一个可选,
因此String(html)
评估为
Optional(...)
神秘的偏移量9
是“Optional(”:)的长度
要解决这个问题,您可以解开 String(html!)
或声明html
作为非可选项。无论哪种情况,resultByAdjustingRangesWithOffset(-9)
没有必要。
第二个问题是您的捕获组中有两个捕获组 图案:
let valPattern = "<td>(.*?)<\\/td>|<td.*?\"(.*?)\">.*?<\\/td>"
<td>8,852.61</td>
与第一个选项匹配,因此
第一个捕获组匹配 8,852.61
, 以便
rangeAtIndex(1)
设置为该字符串的范围,并且
rangeAtIndex(2)
设置为(NSNotFound, 0)
.
<td sortkey="20151003">03 Oct 2015</td>
匹配第二个
替代方案,因此rangeAtIndex(2)
被设置为
范围 20151003
和rangeAtIndex(1)
是 (NSNotFound, 0)
.
NSNotFound
定义为Int.max
那就是2^63 - 1 = 9223372036854775807
在 64 位平台上。
把它们放在一起,这给出了预期的结果:
let html: NSString = "<tbody><tr><td sortkey=\"20151003\">03 Oct 2015</td><td>8,852.61</td><td>1,383.68</td><td>Text</td></tr><tr><td sortkey=\"20151004\">04 Oct 2015</td><td>2,577.14</td><td>282.49</td><td>Text</td></tr></tbody>"
let rowPattern = "<tr>\\s*<td s.*?<\\/tr>"
let rowRegex = try! NSRegularExpression(pattern: rowPattern, options: [])
let rowMatches = rowRegex.matchesInString(String(html), options: [], range: NSMakeRange(0, html.length))
for rowMatch in rowMatches {
let rowString: NSString = html.substringWithRange(rowMatch.range)
print("rowString=\(rowString)")
let valPattern = "<td>(.*?)<\\/td>|<td.*?\"(.*?)\">.*?<\\/td>"
let valRegex = try! NSRegularExpression(pattern: valPattern, options: [])
let valMatches = valRegex.matchesInString(String(rowString), options: [], range: NSMakeRange(0, rowString.length))
for valMatch in valMatches {
if valMatch.rangeAtIndex(1).location != NSNotFound {
let value = rowString.substringWithRange(valMatch.rangeAtIndex(1))
print(value)
}
if valMatch.rangeAtIndex(2).location != NSNotFound {
let value = rowString.substringWithRange(valMatch.rangeAtIndex(2))
print(value)
}
}
}
输出:
rowString=<tr><td sortkey="20151003">03 Oct 2015</td><td>8,852.61</td><td>1,383.68</td><td>Text</td></tr>
20151003
8,852.61
1,383.68
Text
rowString=<tr><td sortkey="20151004">04 Oct 2015</td><td>2,577.14</td><td>282.49</td><td>Text</td></tr>
20151004
2,577.14
282.49
Text
关于regex - Swift 2 正则表达式意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33114751/