使用正则表达式在Python中查找和捕获字符

2 投票
3 回答
1890 浏览
提问于 2025-04-16 07:06

在我解决一个来自 Python Challenge 的问题时,我尝试这样做:

我需要从一个文本文件中读取内容,文件里的字符如下:

DQheAbsaMLjTmAOKmNsLziVMenFxQdATQIjItwtyCHyeMwQTNxbbLXWZnGmDqHhXnLHfEyvzxMhSXzd
BEBaxeaPgQPttvqRvxHPEOUtIsttPDeeuGFgmDkKQcEYjuSuiGROGfYpzkQgvcCDBKrcYwHFlvPzDMEk
MyuPxvGtgSvWgrybKOnbEGhqHUXHhnyjFwSfTfaiWtAOMBZEScsOSumwPssjCPlLbLsPIGffDLpZzMKz
jarrjufhgxdrzywWosrblPRasvRUpZLaUbtDHGZQtvZOvHeVSTBHpitDllUljVvWrwvhpnVzeWVYhMPs
kMVcdeHzFZxTWocGvaKhhcnozRSbWsIEhpeNfJaRjLwWCvKfTLhuVsJczIYFPCyrOJxOPkXhVuCqCUgE
luwLBCmqPwDvUPuBRrJZhfEXHXSBvljqJVVfEGRUWRSHPeKUJCpMpIsrV.......

我想要的是遍历这个文本文件,找出那些被三个大写字母包围的小写字母。

为此,我写了一个Python脚本,代码如下:

import re

pattern = re.compile("[a-z][A-Z]{3}([a-z])[A-Z]{3}[a-z]")
f = open('/Users/Dev/Sometext.txt','r')
for line in f:
    result = pattern.search(line)
    if result:
       print result.groups()

 f.close()

但是这个脚本并没有返回我想要的小写字母列表,而是返回了所有符合正则表达式条件的文本块,比如:

aXCSdFGHj
vCDFeTYHa
nHJUiKJHo
.........
.........

有人能告诉我我到底哪里做错了吗?而且有没有其他方法可以在整个文件上运行正则表达式搜索,而不需要逐行遍历?

谢谢

3 个回答

1
import re

with open('/Users/Dev/Sometext.txt','r') as f: 
    tokens = re.findall(r'[a-z][A-Z]{3}([a-z])[A-Z]{3}[a-z]', f.read())

    for token ins tokens:
        print token

findall的作用:

它会返回字符串中所有不重叠的模式匹配结果,结果以字符串列表的形式呈现。这个字符串是从左到右扫描的,匹配结果会按照找到的顺序返回。如果模式中有一个或多个分组,它会返回一个分组的列表;如果模式有多个分组,结果会是一个包含多个元组的列表。空匹配也会包含在结果中,除非它们与另一个匹配的开头相接触。

这可能是re模块中最有用的函数。

read()函数会把整个文件读入一个大字符串中。如果你需要对整个文件进行正则表达式匹配,这个功能特别有用。

注意:根据文件的大小,你可能更倾向于像你第一次尝试时那样逐行读取文件。

2

我建议你使用“前瞻”和“后顾”的技巧:

(?<=[A-Z]{3})(?<![A-Z].{3})([a-z])(?=[A-Z]{3})(?!.{3}[A-Z])

这样做就不会出现匹配重叠的问题。

解释:

(?<=[A-Z]{3})  # assert that there are 3 uppercase letters before the current position
(?<![A-Z].{3}) # assert that there is no uppercase letter 4 characters before the current position
([a-z])        # match a lowercase character (all characters in the example are ASCII)
(?=[A-Z]{3})   # assert that there are 3 uppercase letter after the current position
(?!.{3}[A-Z])  # assert that there is no uppercase letter 4 characters after the current position
2

result.groups() 改成 result.group(1),这样你就能得到单个字母的匹配结果。

你代码的第二个问题是,它无法在一行中找到多个结果。所以你需要用 re.findallre.finditer,而不是 re.searchfindall 会返回字符串或者字符串的元组,而 finditer 则返回匹配对象。

这是我处理同样问题的方法:

import urllib
import re    

pat = re.compile('[a-z][A-Z]{3}([a-z])[A-Z]{3}[a-z]')
print ''.join(pat.findall(urllib.urlopen(
    "http://www.pythonchallenge.com/pc/def/equality.html").read())) 

注意,re.findallre.finditer 返回的结果是不会重叠的。所以当你用上面的模式和 re.findall 在字符串 'aBBBcDDDeFFFg' 中查找时,你只会找到 'c',而不会找到 'e'。幸运的是,这个Python挑战题目没有这样的例子。

撰写回答