regex - Swift 2 正则表达式意外行为

标签 regex swift swift2

我正在尝试从 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)被设置为 范围 20151003rangeAtIndex(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/

相关文章:

objective-c - 如何使用 ParseKit 的 ParserGenApp 语法指定字符范围 [a-zA-Z]

regex - 用尾随 9 舍入数值

c# - RegEx、StringBuilder 和大对象堆碎片

Python 从文档中剥离 XML 标签

ios - 使用 Swift 检查为表格 View 单元格中的文本字段选择的行?

swift - 使用 Kitura - Swift 保存数据

macos - NSArrayController 在插入后选择插入的索引未反射(reflect)在 NSTableView 中

ios - 在 AVPlayer 上添加 ActivityIndi​​cator 并删除 addObserver

swift - 弹跳并提高球的速度

swift - 实例化 UITableViewCell 以便在 TableView 方法之外使用