Java正则解析HTML 跳过标签间文本提取信息存入嵌套Map
可直接落地的正则与匹配方案
正则设计逻辑
原有方案的问题本质是没有跟踪HTML块的所属状态,直接导致城市和线路的绑定关系错位。正则设计需要兼顾两个目标:
- 清晰划分城市块的边界,从物理上避免跨城市的内容错配
- 兼容标签间的任意空白、换行、无关文本,避免因严格的标签格式校验出现匹配失败
最终可用正则表达式
- 城市块匹配正则(用于分割每个城市对应的内容范围)
"<h3>\\s*(?<city>.*?)\\s*</h3>(?<blockContent>.*?)(?=<h3>|$)"- 命名分组
city:提取h3标签包裹的城市名 - 命名分组
blockContent:提取当前h3标签结束后,到下一个h3标签或文档末尾的所有内容,完成城市块的物理隔离 - 编译时需搭配
Pattern.DOTALL标志,让.可以匹配换行符,顺利跳过块内的任意无关文本
- 命名分组
- 线路条目匹配正则(在单个城市块内部运行)
"<strong>\\s*<a\\s+href=\\\"(?<lineUrl>.*?)\\\"\\s*>\\s*(?<lineId>.*?)\\s*</a>\\s*</strong>"- 命名分组
lineUrl:提取a标签的href属性值(线路URL) - 命名分组
lineId:提取a标签包裹的文本(线路编号) - 加入
\\s*兼容标签间的任意排版空格、换行,避免严格格式校验导致的匹配漏错
- 命名分组
正确的匹配处理流程
- 第一步:初始化目标存储结构,即外层
LinkedHashMap,键为城市名,值为存储「线路编号-线路URL」键值对的内层LinkedHashMap - 第二步:编译城市块正则,遍历整个HTML文档完成分块:每一次匹配提取当前块的城市名、块内内容,全程无跨块的状态干扰
- 第三步:对每一个独立的城市块内容,初始化当前城市对应的内层
LinkedHashMap,编译线路条目正则在块内逐次匹配所有线路条目,将提取到的线路编号、线路URL直接存入内层Map - 第四步:将当前城市名和对应的内层Map关联,存入外层总Map
原有问题的根因说明
- 两个独立全局Matcher的问题:两个遍历流程没有共享状态,线路匹配的全过程无法关联当前所属的城市块,会直接将所有提取到的线路绑定到第一次匹配到的城市上,甚至因Matcher的内部状态冲突出现遍历提前终止
- 合并正则失败的问题:未设置块边界的终止条件,匹配过程会跨块捕获后续h3标签的内容,导致分组取值错位、无关内容被错误捕获
- 不推荐尝试把所有匹配逻辑塞进单条超长正则,分块匹配的可靠性远高于全量单匹配,也更容易定位匹配失败的具体环节
内容的提问来源于stack exchange,提问作者Duck
相关产品推荐
相关产品推荐

