正则表达式re.sub()常见问题及解决(换行匹配+标签清洗)

本文围绕Python的re.sub()方法展开。在网页数据爬取与清洗时,使用该方法去除标签遇到诸多问题,如引号匹配错误、换行符影响匹配、正则表达式贪婪特性导致匹配异常等,通过将外层引号改为三引号、解决换行问题、使用非贪婪匹配等方法最终解决问题。

首先大家都知道re.sub()简单用法:

#re.sub()会替换满足条件的所有式子,返回被替换后的文本

text = "阅读量 9999, 点赞量 7788"
ret_sub = re.sub(r'\d+', '8800', text)

结果:
阅读量 8800, 点赞量 8800

 

 

但是有陷阱:这个例子之所以匹配全部成功是因为它所检查的是'\d',也就是数字格式,遇到不是数字的就停止了

现在做另一个例子,我们找了一个网页准备爬它的数据:

 

 

 

今天这个例子先直接复制下来,可以看到数据很乱,嵌套着很多标签,我们接下来要清洗这些数据,那就是把这些标签去掉,只留文字,在说sub方法之前还有一个问题:我第一次粘贴文本给test赋值时,代码为:

text = "<div class="job-detail"><p>1.通过爬虫技术,实现PMS系统与多个销售平台(airbnb、途家、美团榛果等)的订单房态同步、自动发房、价格调整工作;</p>
<p>工作职责:</p><p>2.完成智能定价所需要的数据爬取及数据分析等工作;</p>
<p>3.完成IM针对房源咨询的自动回复的开发工作。</p>
<p><br></p>
<p>任职资格:</p>
<p>1、Python基础良好,2-4年相关岗位工作经验;</p>
<p>2、大学全日本制本科及以上学历;</p>
<p>3、掌握网络爬虫基本类库使用,了解爬虫架构且熟练使用至少一种爬虫框架(Scrapy、PySpider等)进行开发,了解反爬虫、反反爬机制;</p>
<p>4、熟悉WebDriver、Selenium、PhantomJS等常用工具;</p>
<p>5、具有一定前端基础,拥有分析结构化和非结构化数据能力;</p>
<p>6、掌握正则表达式、搜索策略、算法、数据聚类以及重组并可以独立完成对抓取数据进行信息提取、去重和清洗;</p>
<p>7、熟练使用<a class="jd-ad" href="https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1&amp;sid=3-MySQL-1557236458934" target="_blank" rel="nofollow" data-ad="3" data-lg-tj-id="1kcw" data-lg-tj-no="idnull" data-lg-tj-cid="31557236458934" data-lg-tj-content="MySQL">MySQL</a><a class="jd-ad" href="https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1&amp;sid=3-%E6%95%B0%E6%8D%AE%E5%BA%93-1557236458934" target="_blank" rel="nofollow" data-ad="3" data-lg-tj-id="1kcw" data-lg-tj-no="idnull" data-lg-tj-cid="31557236458934" data-lg-tj-content="数据库">数据库</a>,了解非关系型数据库(<a class="jd-ad" href="https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1&amp;sid=3-Redis-1557236458934" target="_blank" rel="nofollow" data-ad="3" data-lg-tj-id="1kcw" data-lg-tj-no="idnull" data-lg-tj-cid="31557236458934" data-lg-tj-content="Redis">Redis</a>、MongoDB等);</p>
<p>8、了解Scrapy+Redis<a class="jd-ad" href="https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1&amp;sid=3-%E5%88%86%E5%B8%83%E5%BC%8F-1557236458934" target="_blank" rel="nofollow" data-ad="3" data-lg-tj-id="1kcw" data-lg-tj-no="idnull" data-lg-tj-cid="31557236458934" data-lg-tj-content="分布式">分布式</a>策略为加分项。</p>
</div>"

结果疯狂报错,我????怎么粘贴个文本还有错了,百度无果,突然想到引号匹配的问题:test字符串用双引号包裹,div标签里也有双引号,直接配对,导致错误,解决方法就是要么把文本里的双引号转义,要么改外面包裹的双引号,标签很多,可想有多麻烦,直接把外层双引号改为三引号,问题解决!接下来说正题:

要去掉标签,可以想到那就用re.sub()方法,用空字符串去替代每个标签,初始想法:

text = re.sub(r'<.*>', "", text)

这样做了之后可以发现结果是全空,接下来又加了

text = re.sub(r"^<.*>", "", text)

发现结果是只过滤掉了第一个标签,接下来的数据全没有动,百度了一下,发现原来是换行出了问题,匹配到第一个<h后,‘.’对'\n'没辙,所以就直接停止了。得,先解决换行问题:

text = re.sub(r'\n+', '', text)

接下来的数据就没有换行了,但是结果还不正确,又出现了全空,百度了也没有结果,突然想到以前做爬虫常用的正则是:*后面跟?,继续百度,找到了问题所在:

.*具有贪婪的性质,首先匹配到不能匹配为止,根据后面的正则表达式,会进行回溯。.*?则相反,一个匹配以后,就往下进行,所以不会进行回溯,具有最小匹配的性质。

我们虽然没有换行符了,但是.*条件一直满足,一直贪婪下去,则一直匹配到了末尾 ,而?则成为非贪婪,匹配到了一个就停止继续下一个匹配。那么改了之后的代码:

text = '''<div class="job-detail"><p>1.通过爬虫技术,实现PMS系统与多个销售平台(airbnb、途家、美团榛果等)的订单房态同步、自动发房、价格调整工作;</p>
<p>工作职责:</p><p>2.完成智能定价所需要的数据爬取及数据分析等工作;</p>
<p>3.完成IM针对房源咨询的自动回复的开发工作。</p>
<p><br></p>
<p>任职资格:</p>
<p>1、Python基础良好,2-4年相关岗位工作经验;</p>
<p>2、大学全日本制本科及以上学历;</p>
<p>3、掌握网络爬虫基本类库使用,了解爬虫架构且熟练使用至少一种爬虫框架(Scrapy、PySpider等)进行开发,了解反爬虫、反反爬机制;</p>
<p>4、熟悉WebDriver、Selenium、PhantomJS等常用工具;</p>
<p>5、具有一定前端基础,拥有分析结构化和非结构化数据能力;</p>
<p>6、掌握正则表达式、搜索策略、算法、数据聚类以及重组并可以独立完成对抓取数据进行信息提取、去重和清洗;</p>
<p>7、熟练使用<a class="jd-ad" href="https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1&amp;sid=3-MySQL-1557236458934" target="_blank" rel="nofollow" data-ad="3" data-lg-tj-id="1kcw" data-lg-tj-no="idnull" data-lg-tj-cid="31557236458934" data-lg-tj-content="MySQL">MySQL</a><a class="jd-ad" href="https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1&amp;sid=3-%E6%95%B0%E6%8D%AE%E5%BA%93-1557236458934" target="_blank" rel="nofollow" data-ad="3" data-lg-tj-id="1kcw" data-lg-tj-no="idnull" data-lg-tj-cid="31557236458934" data-lg-tj-content="数据库">数据库</a>,了解非关系型数据库(<a class="jd-ad" href="https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1&amp;sid=3-Redis-1557236458934" target="_blank" rel="nofollow" data-ad="3" data-lg-tj-id="1kcw" data-lg-tj-no="idnull" data-lg-tj-cid="31557236458934" data-lg-tj-content="Redis">Redis</a>、MongoDB等);</p>
<p>8、了解Scrapy+Redis<a class="jd-ad" href="https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1&amp;sid=3-%E5%88%86%E5%B8%83%E5%BC%8F-1557236458934" target="_blank" rel="nofollow" data-ad="3" data-lg-tj-id="1kcw" data-lg-tj-no="idnull" data-lg-tj-cid="31557236458934" data-lg-tj-content="分布式">分布式</a>策略为加分项。</p>
</div>'''

text = re.sub(r'\n+', '', text)
print(text + '\n')
ret = re.sub(r"<.*?>", "", text)
print(ret)

运行结果:

问题解决!赏心悦目! 

<think>好的,用户想了解Pythonre模块的正则表达式相关内容。我需要根据之前的回答和提供的引用信息来组织内容。首先,用户之前的问题是关于如何在Python中使用正则表达式,现在他们想要更详细的内容,特别是re模块的功能和元字符。 先回顾用户提供的引用,引用[1]提到了re模块的四个主要功能:查找匹配项、查找所有匹配项、替换匹配项、分割字符串,还提到了元字符。引用[2]则详细说明了findall在不同括号情况下的返回值差异。之前的回答已经覆盖了match、findall、sub和分组,但可能需要更深入。 用户现在需要详细内容,可能需要包括re模块的核心方法、元字符、分组机制、性能优化等。同时,用户之前的回答中提到了相关问题,比如何时使用正则表达式、性能优化、设计高效正则表达式,这些可能需要进一步扩展。 需要注意的是,用户提到引用的内容可能来自《跟老吕学Python编程》,所以在总结时可以引用相关内容。同时,要确保结构清晰,分点讲解,比如核心功能、元字符、分组、注意事项等。 可能还需要补充一些之前未提到的内容,如split方法、编译正则表达式、贪婪与非贪婪模式,以及使用re.VERBOSE等标志提高可读性。此外,引用[2]中的例子展示了不同括号情况下的结果,需要详细解释分组对结果的影响。 需要检查是否有遗漏的重要功能或常见问题,比如匹配模式(如忽略大小写、多行模式)、错误处理、特殊字符转义等。还要确保示例代码正确,并且符合用户提供的引用中的案例,比如findall的不同输出。 最后,生成的相关问题需要基于当前内容,可能涉及元字符的使用、分组应用、性能优化、常见错误等。确保问题有针对性,帮助用户进一步学习。</think>#### Python `re`模块正则表达式详解 以下内容整合自《跟老吕学Python编程》核心知识点及实践技巧[^1][^2],通过功能分类、语法演示和案例对比进行系统说明。 --- ### 一、`re`模块核心功能 | 方法名 | 作用描述 | 典型应用场景 | 返回值类型 | |----------------|----------------------------------|-----------------------|-------------------| | `re.match()` | **从字符串起始位置**匹配模式 | 验证输入格式(如邮箱) | `Match`对象/`None` | | `re.search()` | **扫描整个字符串**寻找首个匹配项 | 提取首个有效数据片段 | `Match`对象/`None` | | `re.findall()` | 返回所有**非重叠匹配项**的列表 | 批量提取符合条件的数据 | 列表 | | `re.sub()` | 替换所有匹配模式的子串 | 数据清洗/格式转换 | 修改后的字符串 | | `re.split()` | 根据模式分割字符串 | 结构化文本解析 | 列表 | --- ### 二、正则表达式元字符速查表 以下为常用元字符的数学表达式描述及作用: 1. **定位符** - `^`:匹配字符串开头,等价于$字符串起始位置$ - `$`:匹配字符串结尾,等价于$字符串终止位置$ - `\b`:匹配单词边界,如`\bword\b`匹配独立的"word" 2. **量词符** - `*`:匹配前导字符$0$次或多次,对应集合$\{0,+\infty\}$ - `+`:匹配前导字符$1$次或多次,对应集合$\{1,+\infty\}$ - `?`:匹配前导字符$0$或$1$次,对应集合$\{0,1\}$ - `{n,m}`:匹配前导字符$n$到$m$次,如`a{2,4}`可匹配"aa"、"aaa"或"aaaa" 3. **字符类** - `\d`:匹配数字,等价于$[0-9]$ - `\w`:匹配字母/数字/下划线,等价于$[a-zA-Z0-9_]$ - `\s`:匹配空白符(空格、制表符等) - `.`:匹配换行符外的任意字符 4. **逻辑控制** - `|`:或运算符,如`cat|dog`匹配"cat"或"dog" - `()`:定义捕获组,影响`findall()`返回值结构[^2] --- ### 三、分组机制深度解析 通过括号实现**数据捕获**与**逻辑分组**,直接影响匹配结果的呈现形式(参考引用[2]案例): #### 1. 无分组匹配 ```python text = "2023年5月15日" pattern = r'\d+年|\d+月|\d+日' print(re.findall(pattern, text)) # ['2023年', '5月', '15日'] ``` #### 2. 单分组匹配 ```python pattern = r'(\d+)(年|月|日)' print(re.findall(pattern, text)) # [('2023', '年'), ('5', '月'), ('15', '日')] ``` #### 3. 多分组匹配 ```python pattern = r'(\d+)(\d+)(\d+)' text = "开始时间:2023年5月15日" match = re.search(pattern, text) if match: print(match.groups()) # ('2023年', '5月', '15日') ``` --- ### 四、关键注意事项 1. **贪婪模式陷阱** 默认量词符采用贪婪匹配,可通过`?`改为非贪婪模式: ```python # 贪婪模式 re.findall(r'<div>.*</div>', "<div>内容1</div><div>内容2</div>") # 匹配整个字符串 # 非贪婪模式 re.findall(r'<div>.*?</div>', "<div>内容1</div><div>内容2</div>") # 匹配两个独立div ``` 2. **预编译优化** 高频使用的正则表达式建议预编译: ```python pattern = re.compile(r'\d{4}-\d{2}-\d{2}') dates = pattern.findall("日期:2023-05-20, 2023-06-01") ``` 3. **模式修饰符应用** - `re.IGNORECASE`:忽略大小写匹配 - `re.MULTILINE`:多行模式(影响`^`和`$`) - `re.VERBOSE`:允许正则表达式换行添加注释 --- ### 五、实战案例:提取日志关键信息 ```python log = """ [ERROR] 2023-05-20 14:30:22 | 用户ID:U1001 | 错误代码:500 [INFO] 2023-05-20 14:31:15 | 用户ID:U1002 | 操作:登录成功 """ # 提取错误日志详情 pattern = r'\[ERROR\] (\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}).*?用户ID:(\w+).*?错误代码:(\d+)' errors = re.findall(pattern, log) # 输出:[('2023-05-20', '14:30:22', 'U1001', '500')] ``` --- ### 六、进阶学习建议 1. 使用`re.DEBUG`标志查看正则表达式解析树 2. 通过`regex101.com`在线工具实时调试表达式 3. 学习正则表达式引擎原理(DFA/NFA差异)
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值