如何用Swift RegexBuilder提取HTML嵌套<ul>标签中的内容?
用Swift RegexBuilder提取嵌套
- 列表的正确实现
你遇到的核心问题是正则默认的贪婪匹配会让外层<ul>提前匹配到内层的</ul>,要解决嵌套标签的匹配,需要通过递归正则结构识别嵌套的<ul>块,确保每个<ul>都匹配到对应的闭合标签。
测试用HTML示例
<ul> <li>Item 1</li> <li>Item 2 <ul> <li>Subitem 2.1</li> <li>Subitem 2.2</li> </ul> </li> <li>Item 3</li> </ul>
完整实现代码
import Foundation func extractULBlocks(from html: String) -> (outerBlock: String?, innerBlock: String?) { // 定义支持嵌套的<ul>匹配正则 let ulRegex = Regex { let nestedUL = Reference(Regex<Substring>.self) "<ul>" ZeroOrMore(.whitespaceAndNewline) // 捕获<ul>内部的内容(不含标签本身) Capture { OneOrMore { ChoiceOf { // 非贪婪匹配非<ul>/</ul>的内容,避免提前终止 OneOrMore(.any, .reluctant) // 递归匹配嵌套的<ul>结构 nestedUL } } } ZeroOrMore(.whitespaceAndNewline) "</ul>" } // 提取外层<ul>内部内容 guard let outerMatch = html.firstMatch(of: ulRegex) else { return (nil, nil) } let outerBlock = String(outerMatch.output.1) // 从外层内容中提取内层<ul>内部内容 guard let innerMatch = outerBlock.firstMatch(of: ulRegex) else { return (outerBlock, nil) } let innerBlock = String(innerMatch.output.1) return (outerBlock, innerBlock) } // 调用示例 let testHTML = """ <ul> <li>Item 1</li> <li>Item 2 <ul> <li>Subitem 2.1</li> <li>Subitem 2.2</li> </ul> </li> <li>Item 3</li> </ul> """ let result = extractULBlocks(from: testHTML) print("外层列表内容:\n\(result.outerBlock ?? "未找到")") print("\n内层列表内容:\n\(result.innerBlock ?? "未找到")")
关键逻辑说明
- 递归正则片段:用
Reference定义nestedUL,实现对嵌套<ul>结构的递归匹配,确保外层<ul>只会匹配到自己对应的</ul>。 - 非贪婪匹配:
OneOrMore(.any, .reluctant)采用非贪婪模式,避免提前吃掉后续的<ul>或</ul>标签。 - 结构适配:针对你提到的「结构简单规范」的HTML,无需处理标签属性、注释等复杂场景,该正则足够覆盖需求。
如果需要提取包含<ul>和</ul>标签的完整块,只需调整Capture的范围,将整个<ul>...</ul>包裹进去即可。
内容的提问来源于stack exchange,提问作者Patrick Bauers
相关产品推荐
相关产品推荐

