可见,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(),也是可以达到预期的,代码如下: