python中使用正则表达式将所有符合条件的字段全部提取出来

 更新时间:2020年08月24日 09:06:52   作者:前行的zhu  
这篇文章主要介绍了python中使用正则表达式将所有符合条件的字段全部提取出来,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

问题如标题,使用正则表达式匹配字段目前无非就三种,分别是:

re.match()
re.search()
re.findall()

简单介绍一下,re.match()与re.search()非常类似,主要区别就是前者是从目标字符串的开头匹配,而后者则要没有这个要求。而re.findall()则是可以返回匹配的所有结果。但是有时候re.findall()返回的结果和前面两个并不一样,我们来看下面一个例子:
对于句子:

起病以来,患者无腰背痛、颈痛,无咽痛、口腔溃疡,无光过敏、脱发,无口干、眼干,无肢端发作性青紫,无肢体乏力,无浮肿、泡沫尿,精神、食欲、睡眠欠佳,近1月大便干结,5-6天1次,无腹痛、黑便、便血,小便1-2小时1次,无尿痛、血尿。体重未见明显变化。

我想使用正则去匹配所有包含小便和尿相关的子句,目的就是将“无浮肿、泡沫尿”和“小便1-2小时1次,无尿痛、血尿。”识别出来并且将这些子句返回。
本来我想使用re.findall()去匹配:

import re
lines = [
 "起病以来,患者无腰背痛、颈痛,无咽痛、口腔溃疡,无光过敏、脱发,无口干、眼干,无肢端发作性青紫,无肢体乏力,无浮肿、泡沫尿,精神、食欲、睡眠欠佳,近1月大便干结,5-6天1次,无腹痛、黑便、便血,小便1-2小时1次,无尿痛、血尿。体重未见明显变化。",
 ]
for line in lines:
 pattern = "[,;.,;。]+[^,;.,;。]*((小便)|尿)+[^,;.,;。]*[,;.,;。]+"
 str = re.findall(pattern,line)
 print(str)

结果为:

[('尿', ''), ('小便', '小便')]

这里说明一下我使用的模式的意义,因为我是要匹配子句,所以一个子句的前后必然会有相应的符号,所以pattern前面和后面均添加了“[,;.,;。]+”;“+”表示至少匹配一个。而后面的“[,;.,;。]*”表示匹配0个或多个除标点符号“,;.,;。”的任意字符,这里分别添加了中英文的逗号、分号和句号,“*”表示匹配0个或1个及以上。需要说明的是,这里我之所以使用“[,;.,;。]”,是因为文本中可能包含很多其他的符号,像上例中出现的“-”;所以想要使用汉字、数字、特定符号来匹配的话可能会存在遗漏,而我的目的是只想要得到匹配的子句,所以使用“[^,;.,;。]”会更通用一些。接下来就是“((小便)|尿)”意思是匹配含有“小便”或者含有“尿”的子串。
但是使用re.findall()所得到的结果并不是我想要的,于是我稍微换了一下匹配规则,将“((小便)|尿)+”换成了“[(小便)|尿]+”;为了验证匹配的适用性,我又添加了两个样本。总体如下:

import re
lines = [
 "起病以来,患者无腰背痛、颈痛,无咽痛、口腔溃疡,无光过敏、脱发,无口干、眼干,无肢端发作性青紫,无肢体乏力,无浮肿、泡沫尿,精神、食欲、睡眠欠佳,近1月大便干结,5-6天1次,无腹痛、黑便、便血,小便1-2小时1次,无尿痛、血尿。体重未见明显变化。",
 "起病以来,睡眠、胃纳正常,小便正常,近4~5年来每天解大便3~4次,多为黄褐色成形软便,偶有解烂便,有排便不尽感,便血、解黑便,无消瘦。",
 "身材矮小,体重较同龄人轻。"
]
for line in lines:
 pattern = "[,;.,;。]+[^,;.,;。]*[(小便)尿]+[^,;.,;。]*[,;.,;。]+"
 str = re.findall(pattern,line)
 print(str)

结果为:

[',无浮肿、泡沫尿,', ',近1月大便干结,', ',无腹痛、黑便、便血,', ',无尿痛、血尿。']
[',小便正常,', ',多为黄褐色成形软便,', ',有排便不尽感,']
[]

倒是匹配出了子句,一则是“小便1-2小时1次,无尿痛、血尿”中的“小便1-2小时1次”没有匹配出来,二则是竟然连大便相关的“近1月大便干结”和“无腹痛、黑便、便血”都匹配出来了,看来“[(小便)尿]”的意思并不是匹配含有“小便”或者“尿”的子串;那“[(小便)尿]”的意思是不是匹配含有“小”、“便”、“尿”任意一个的子串呢?但是根据第三个含有“小”但是不含“便”与“尿”的样本可以看出,上述的想法依然不对。
再加上re.findall()没有匹配到的子串在原始文本中的开始和结束位置,所以我想要得到“小便1-2小时1次,无尿痛、血尿。”这种两个子句连在一起的情况也很难得到。
于是我转而使用另一个很常用的re.search()方法。

import re
lines = [
 "起病以来,患者无腰背痛、颈痛,无咽痛、口腔溃疡,无光过敏、脱发,无口干、眼干,无肢端发作性青紫,无肢体乏力,无浮肿、泡沫尿,精神、食欲、睡眠欠佳,近1月大便干结,5-6天1次,无腹痛、黑便、便血,小便1-2小时1次,无尿痛、血尿。体重未见明显变化。",
]
for line in lines:
 pattern = "[,;.,;。]+[^,;.,;。]*((小便)|尿)+[^,;.,;。]*[,;.,;。]+"
 str = re.search(pattern, line)
 print(str.group())

结果为:

,无浮肿、泡沫尿,

可见,re.search()只匹配遇到的第一个满足条件的子串。
而如果将pattern中的“((小便)|尿)”修改为“[(小便)|尿]”(或者“[(小便)尿]”,意思是完全一样的,也试过)
得到的结果为:

,无浮肿、泡沫尿,

可见修改前后并没有任何变化,但是如果我将原始文本中的“无浮肿、泡沫尿”中的“尿”删除,则修改前的结果为:

,小便1-2小时1次,

修改后的结果为:

,近1月大便干结,

也就是说对于

pattern = "[,;.,;。]+[^,;.,;。]*[(小便)尿]+[^,;.,;。]*[,;.,;。]+"

无论是re.findall()还是re.search(),都能匹配到大便相关的子串;
而对于:

pattern = "[,;.,;。]+[^,;.,;。]*((小便)|尿)+[^,;.,;。]*[,;.,;。]+"

re.findall()和re.search()匹配的子串就有所区别了,前置匹配的结果是含有元组的列表:[(‘尿', ‘'), (‘小便', ‘小便')];而后者匹配到了我想要的子串:,无浮肿、泡沫尿,
后来问了同事以及进一步了解了正则的运行机制后,发现小括号()除了提取匹配的字符串,还有一个作用是用来捕获分组的,也就是说小括号中的内容匹配后会被存储起来,在调用的时候便会返回相应的值。而使用re.findall()时会将存储分组的值全部返回。
再举个例子会更加明白些,将上述pattern中的“((小便)|尿)”改为“((小便)|(尿))”,如:

pattern = "[,;.,;。]+[^,;.,;。]*((小便)|(尿))+[^,;.,;。]*[,;.,;。]+"

使用re.findall()输出的结果为:

[('尿', '', '尿'), ('小便', '小便', '')]

由上可知,“((小便)|(尿))”使用了三个“()”,于是便产生了三个分组,在最外围的第一个分组用于捕获“小便”或“尿”,原文中“小便”和“尿”都能匹配到,所以第一个位置两者都有;第二个分组是用来捕获“(小便)”的,所以第二个分组只存储“小便”;同理第三个分组用来捕获“(尿)”的,所以结果只存储了“尿”。
而我使用re.search()来输出分组结果:

for line in lines:
    pattern = "[,;.,;。]+[^,;.,;。]*((小便)|(尿))+[^,;.,;。]*[,;.,;。]+"
    str = re.search(pattern, line)
    print(str.group(0))
    print(str.group(1))
    print(str.group(2))
    print(str.group(3))

结果为:

,无浮肿、泡沫尿,
尿
None
尿

group(1)、group(2)、group(3)分别与(‘尿', ‘', ‘尿')中对应的分组结果相同。但是这里的group(0)(或者说group(),两个意思完全一样)却不是“(‘尿', ‘', ‘尿')”;这里作者水平有限,不是很清楚原因,也就是说,当调用group(0)的时候,pattern中的()的意义并不再是捕获分组了,而是回到了原始的提取匹配字符串的意思上来了。
为了解决

pattern = "[,;.,;。]+[^,;.,;。]*[(小便)尿]+[^,;.,;。]*[,;.,;。]+"

会匹配到不想要的含有“大便”字符串的问题,通过使用非捕获分组(?:)便可以达到目的。

pattern = "[,;.,;。]?[^,;.,;。]*(?:小便|尿)[^,;.,;。]*[,;.,;。]"

此时便是匹配“小便”或者“尿”了;结果为:

[',无浮肿、泡沫尿,', ',小便1-2小时1次,', '无尿痛、血尿。']

注意上述结果,由于“,小便1-2小时1次,”和“无尿痛、血尿。”是紧接着的,而逗号已经被分配给了前者,所以后者便没有了逗号,这看起了有点像字符串的切片,被切走了就没了,所以这里在pattern中的第一个“[,;.,;。]”后面将“+”换成了“?”()意思的前面的字符出现0次或1次;当然更进一步可以优化为:

pattern = "[,;.,;。]?[^,;.,;。]*(?:小便|尿).*?[,;.,;。]"

可以看到,将pattern中第二个“[^,;.,;。]”变为“.?”
上述虽然将所有子句全部匹配并输出了,但是相邻的两个子句还是分开输出的,仍旧没有达到我们想要的预期。于是对上述代码进行了改进:

for line in lines:
 #pattern = "[,;.,;。]+[^,;.,;。]*[('小便')尿]+[^,;.,;。]*[,;.,;。]+"
 pattern = "[,;.,;。]?[^,;.,;。]*?(?:小便|尿).*?[,;.,;。]"
 #pattern = "[,;.,;。]?[^,;.,;。]*(?:小便|尿)[^,;.,;。]*[,;.,;。]"

 str = re.findall(pattern,line)
 ls = [',',';','.',',',';','。']
 for idx, text in enumerate(str):
  if text[0] not in ls:
   str[idx-1] += text
   str.remove(text)

 print(str)

结果为:

[',无浮肿、泡沫尿,', ',小便1-2小时1次,无尿痛、血尿。']

而如果使用re.search(),也是可以达到预期的,代码如下:

for line in lines:
 result = []
 num = -1
 while line:
  #pattern = re.compile(r"[,;.,;。]+[^,;.,;。]*((小便)|尿)+[^,;.,;。]*[,;.,;。]+")
  #str = pattern.search(line)
  pattern = r"[,;.,;。]+[^,;.,;。]*((小便)|尿)+[^,;.,;。]*[,;.,;。]+"
  str = re.search(pattern,line)
  if str == None:
   break
  tmp = str.group()
  if str.start() == 0:
   result[-1] += tmp[1:]
  else:
   result.append(tmp[1:])
  #print(tmp)
  num = str.end() - 1
  #print(num)
  line = line[num:]
 print(result)

结果为:

['无浮肿、泡沫尿,', '小便1-2小时1次,无尿痛、血尿。']

到此这篇关于python中使用正则表达式将所有符合条件的字段全部提取出来的文章就介绍到这了,更多相关python 正则表达式提取字段内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一篇文章了解正则表达式的替换技巧

    一篇文章了解正则表达式的替换技巧

    正则表达式非常有用,查找、匹配、处理字符串、替换和转换字符串,输入输出等,下面这篇文章主要给大家介绍了关于正则表达式替换技巧的相关资料,需要的朋友可以参考下
    2022-02-02
  • JS验证URL函数 正则

    JS验证URL函数 正则

    搜集一个JS验证URL函数,方便需要的朋友
    2012-10-10
  • Javascript校验密码复杂度的正则表达式

    Javascript校验密码复杂度的正则表达式

    这篇文章主要介绍了Javascript校验密码复杂度的正则表达式及正则表达式校验密码的方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-08-08
  • ip138中各种客户端验证js代码

    ip138中各种客户端验证js代码

    包括ip验证,身份证验证,手机号码验证,电话号码,邮政编码验证,域名验证等,其实好的代码,都在应用中,大家多去扒代码吧。
    2009-12-12
  • 正则表达式下全部符号解释说明

    正则表达式下全部符号解释说明

    正则表达式下全部符号,对于书写正则表达式的朋友一定要了解下,才能更好的发挥正则的作用于阅读别人的代码,先从基本来。
    2010-07-07
  • PHP 正则表达式效率 贪婪、非贪婪与回溯分析(推荐)

    PHP 正则表达式效率 贪婪、非贪婪与回溯分析(推荐)

    先扫盲一下什么是正则表达式的贪婪,什么是非贪婪?或者说什么是匹配优先量词,什么是忽略优先量词,好吧,下面通过实例给大家介绍下PHP 正则表达式效率 贪婪、非贪婪与回溯分析,一起看看吧
    2016-12-12
  • 正则表达式 运算符优先级介绍

    正则表达式 运算符优先级介绍

    正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似
    2016-05-05
  • grep中使用

    grep中使用"\d"匹配数字不成功的原因解决

    这篇文章主要介绍了grep中使用"\d"匹配数字不成功的原因解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • 常用正则表达式之密码格式验证大全

    常用正则表达式之密码格式验证大全

    如果密码中只包含数字,那么该密码是非常简单,当然它的安全性也相对较差,下面这篇文章主要给大家介绍了关于常用正则表达式之密码格式验证大全的相关资料,需要的朋友可以参考下
    2022-02-02
  • 正则表达式直接在EXCEL中使用的详细步骤

    正则表达式直接在EXCEL中使用的详细步骤

    这篇文章主要介绍了正则表达式直接在EXCEL中使用的详细步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03

最新评论