如何使用python re
提取中间部分(第一行,第二行和第三行)?
--089e013d100acf582104f809fd8d
Content-Type: text/plain; charset=UTF-8
first line
second line
third line
--089e013d100acf582104f809fd8d
阅读邮箱的第一部分:
#!/usr/bin/env python
import poplib
from email import parser
pop_conn = poplib.POP3_SSL('mail.company.com')
pop_conn.user('user')
pop_conn.pass_('')
#newest email has the highest message number
numMessages = len(pop_conn.list()[1])
(server_msg,body,octets) = pop_conn.retr(numMessages)
答案 0 :(得分:2)
正则表达式仅适用于简单(常规)模式。从理论上讲,正则表达式是一种表示有限状态机的方法。通常,它们用于标记化/词法分析器(将程序字符串拆分为一系列标记)或匹配常规字符串(例如罗马数字)。
您似乎正在尝试解析多部分mime文档,例如:
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="mimetest"
This part is ignored.
--mimetest
Content-Type: text/plain
Part 1
--mimetest
Content-Type: text/rtf
\rtf{\par Part 2}
--mimetest--
在这里,你有一个带有两个内部mime文档的外部mime文档。每个mime文档都有一个标题部分,用空行分隔后跟内容。
最好的方法是编写一个解析器,将标题与内容一起读入字典。然后,您可以使用正则表达式来定位边界并在边界之间提取文本,例如:
MIME_STATE_HEADER = 1
MIME_STATE_BODY = 2
def read_lines(text):
if isinstance(text, list):
return text
return re.split(r'\r?\n', text)
def parse_mime(text):
header_line = re.compile(r'^([A-Za-z\-]+): (.*)$')
state = MIME_STATE_HEADER
header = {}
body = []
for line in read_lines(text):
if state == MIME_STATE_HEADER:
if line == '':
state = MIME_STATE_BODY
continue
m = header_line.match(line)
if not m:
raise Exception('Invalid header section: %s' % line)
header[ m.group(1).lower() ] = m.group(2)
elif state == MIME_STATE_BODY:
body.append(line)
return header, body
def mime(text):
header, body = parse_mime(text)
content_type = re.compile(r'multipart/.*; boundary="(.*)"')
m = content_type.match(header['content-type'])
if m:
boundary = re.escape(m.group(1))
matcher = re.compile(r'\r?\n--%s(--)?\r?\n' % boundary)
parts = [ mime(part) for part in matcher.split('\n'.join(body))[1:-2] if part ]
return header, parts
return header, '\n'.join(body)
此代码将处理各种基于mime的文档,但有一些限制/错误:
这不支持包装的标题,例如:
Content-Type: multipart/related;
boundary="text"
它不支持不带引号的边界,例如Content-Type: multipart/related; boundary=text
。
它不支持Debian bugmail等邮件存档(例如以From email date time
开头)或HTTP / SMTP标识符/状态行。
使用这些Python正则表达式:
^
匹配行的开头$
匹配行尾[abc]
匹配任何字符a
,b
,c
(其中一个)[a-z]
匹配任何字符a
到z
\-
转义字符-
,因此可以在[]
表达式中使用a+
匹配表达式a
a*
匹配表达式a
.
匹配任何字符a?
可选地匹配a
(即匹配a
的零个或一个实例)\r
匹配回车符号(a)
捕获下一组中匹配的a
表达式的内容 - 通过m.group(n)
^([A-Za-z\-]+): (.*)$
匹配MIME标头中的标头条目,以便m.group(1)
是标题名称(例如'内容类型'),m.group(2)
是内容那个标题。
\r?\n
匹配Windows或Linux风格的行终止符(MIME文档应该使用' \ r \ n',但在保存时可以转换为\n
本地文件。)
multipart/.*; boundary="?(.*)"?
在Content-Type标头条目中找到用于边界的文本。
\r?\n--%s(--)?\r?\n
找到一个单独的边界(其中%s
是边界
动态添加)。注意:我已经通过re.escape
传递了边界字符串,以防止它被利用(即如果它包含boundary="[a-z]"
等正则表达式。
实际上,您应该使用Python中的email
模块来支持解析RFC822(email / mime)文档。此状态为documentation:"对于简单的非MIME消息,此根对象的有效内容可能是包含消息文本的字符串。对于MIME消息,根对象将从其is_multipart()方法返回True,并且可以通过get_payload()和walk()方法访问子部分。"
更新:我创建了一个read_lines
帮助器来支持字符串列表(例如来自poplib
)和一个字符串(来自例如f.read()
)。< / p>
更新:用于边界检测的--%s\r?\n(.*)\r?\n--%s
匹配器:
matcher = re.compile(r'--%s\r?\n(.*)\r?\n--%s' % (boundary, boundary))
parts = [ mime(part) for part in matcher.findall(body) ]
有两个问题:
re.compile(..., re.DOTALL)
; 使用正则表达式无法轻易解决后者问题。解决方案是在边界字符串上拆分,结果是:
[part0, None, part1, None, part2, ..., partN, '--', '']
其中part0
是第一个边界之前的部分。因此[1:-2]
用于删除part0
和两个结束匹配,if part
用于删除None
匹配。
答案 1 :(得分:0)
以下是我用来捕捉三行的简单代码:
reobj = re.compile("Content-Type:.*?\n+([^\n]+)\n+([^\n]+)\n+([^\n]+)\n*")
match = reobj.search(subject)
if match:
line1 = match.group(1)
line2 = match.group(2)
line3 = match.group(3)
else:
result = ""
这是如何运作的?
\n+
([^\n]+)
捕获每一行,这意味着&#34;匹配任何不是新行的任意数量的字符。\n+
占用任意数量的新行。第3组之后的最后一个换行符是可选的:\n*
(事实上正则表达式可以在没有它的情况下工作。)