【问题标题】:String Cutting with multiple lines多行字符串切割
【发布时间】:2018-02-20 16:07:28
【问题描述】:

所以除了一些 tKintner 经验(一些 GUI 实验)之外,我还是 python 新手。

我读取了一个 .mbox 文件并将纯文本/文本复制到一个字符串中。此文本包含一个注册表单。因此,居住在伦敦枫树街为“MultiVendor XXVideos”公司工作的 Stefan 已通过电子邮件注册订阅。

Name_OF_Person: Stefan
Adress_HOME: London, Maple
    Street
 45
Company_NAME: MultiVendor
XXVideos

我想获取这些数据并放入带有列的 .csv 行 “姓名”、“地址”、“公司”、...

现在我试着切割一切。对于调试,我使用“打印”(IDE = KATE/KDE + 终端... :-D)。 问题是,数据在关键字之后包含多行,但我只得到第一行。

您将如何改进我的代码?

import mailbox
import csv
import email
from time import sleep
import string
fieldnames = ["ID","Subject","Name", "Adress", "Company"]
searchKeys = [ 'Name_OF_Person','Adress_HOME','Company_NAME']
mbox_file = "REG.mbox"
export_file_name = "test.csv"

if __name__ == "__main__":
 with open(export_file_name,"w") as csvfile:
 writer = csv.DictWriter(csvfile, dialect='excel',fieldnames=fieldnames)
 writer.writeheader()

 for message in mailbox.mbox(mbox_file):
   if message.is_multipart():
     content = '\n'.join(part.get_payload() for part in message.get_payload())
     content = content.split('<')[0] # only want text/plain.. Ill split #right before HTML starts
     #print content
   else:
     content = message.get_payload()
   idea = message['message-id']
   sub =  message['subject']
   fr = message['from']
   date = message['date']
   writer.writerow ('ID':idea,......) # CSV writing will work fine

   for line in content.splitlines():
     line = line.strip()
      for pose in searchKeys: 
       if pose in line: 
         tmp = line.split(pose)
         pmt = tmp[1].split(":")[1]
         if next in line !=: 
         print pose +"\t"+pmt
       sleep(1)
csvfile.closed

输出:

OFFICIAL_POSTAL_ADDRESS  =20

这里,行不见了.. 来自文件:

OFFICIAL_POSTAL_ADDRESS: =20
London, testarossa street 41

编辑2:

@亚尼夫 谢谢,我仍在尝试理解每一步,但只是想发表评论。我喜欢使用列表/矩阵/向量“key_value_pairs”的想法

电子邮件中的关键字数量约为 20 个字。此外,我的价值观有时会被“=”换行。 我在想这样的事情:

Search text for Keyword A, 
if true: 
 search text from Keyword A until keyword B 
 if true:
  copy text after A until B

Name_OF_=
Person: Stefan
Adress_
=HOME: London, Maple
Street
 45
Company_NAME: MultiVendor
XXVideos

也许来自 EMAIL.mbox 的 HTML 更容易处理?

<tr><td bgcolor=3D"#eeeeee"><font face=3D"Verdana" size=3D"1">
<strong>NAM=
 E_REGISTERING_PERSON</strong></font></td><td bgcolor=3D"#eeeeee"><font    
 fac=e=3D"Verdana" size=3D"1">Stefan&nbsp;</font></td></tr>

但是“=”仍然存在 我应该将 ["="," = "] 替换为 "" 吗?

【问题讨论】:

  • 你确定顺序总是一样的吗 1) Name_OF_Person:, 2) Adress_HOME: , 3) Company_NAME: ?
  • 这是我们网站上的 html 注册表格,我必须使用过去 10 年的注册表格(x~10000 封邮件)并创建一个包含所有数据的 csv。形式改变了一次,除非它总是一样的。编辑:但是在此之前和之后有大约 25 个条目,每次都有不同的行号
  • 解释不同的行号?意味着每个标题有不同的行数?只是在提出解决方案之前澄清问题
  • if next in line !=: 不可能是对的。请只粘贴实际可以运行的代码。
  • 一切都好。 :) 我解决了指定的问题。如果是这种情况,正则表达式或 Yaniv 提出的解决方案是最好的选择

标签: python string csv cut


【解决方案1】:

我会在输入行上进行“例行”解析循环,并维护一个current_keycurrent_value 变量,作为某个 > 在您的数据中可能是“烦人的”,并且分布在多行中。

我在下面的代码中演示了这种解析方法,并对您的问题进行了一些假设。例如,如果输入行以空格开头,我假设它一定是这种“烦人”值的情况(分布在多行中)。这些行将使用一些可配置的字符串(参数join_lines_using_this)连接成一个值。另一个假设是您可能希望从键和值中去除空格。

随意调整代码以适应您对输入的假设,并在它们不成立时引发异常!

# Note the usage of .strip() in some places, to strip away whitespaces. I assumed you might want that.
def parse_funky_text(text, join_lines_using_this=" "):

    key_value_pairs = []

    current_key, current_value = None, ""
    for line in text.splitlines():
        line_split = line.split(':')
        if line.startswith(" ") or len(line_split) == 1:
            if current_key is None:
                raise ValueError("Failed to parse this line, not sure which key it belongs to: %s" % line)
            current_value += join_lines_using_this + line.strip()
        else:
            if current_key is not None:
                key_value_pairs.append((current_key, current_value))
                current_key, current_value = None, ""
            current_key = line_split[0].strip()
            # We've just found a new key, so here you might want to perform additional checks,
            # e.g. if current_key not in sharedKeys: raise ValueError("Encountered a weird key?! %s in line: %s" % (current_key, line))
            current_value = ':'.join(line_split[1:]).strip()

    # Don't forget the last parsed key, value
    if current_key is not None:
        key_value_pairs.append((current_key, current_value))

    return key_value_pairs

示例用法:

text = """Name_OF_Person: Stefan
Adress_HOME: London, Maple
    Street
 45
Company_NAME: MultiVendor
XXVideos"""

parse_funky_text(text)

将输出:

[('Name_OF_Person', 'Stefan'), ('Adress_HOME', 'London, Maple Street 45'), ('Company_NAME', 'MultiVendor XXVideos')]

【讨论】:

  • 虽然,我也喜欢这个建议:)
【解决方案2】:

您在 cmets 中指出您从内容中输入的字符串应该是相对一致的。如果是这种情况,并且您希望能够将该字符串拆分为多行,那么最简单的做法是将\n 替换为空格,然后只解析单个字符串。

我故意将我的答案限制为仅使用字符串方法,而不是发明一个巨大的函数来做到这一点。原因:1)您的流程已经足够复杂,2)您的问题实际上归结为如何跨多行处理字符串数据。如果是这样,并且模式是一致的,这将完成这项工作

content = content.replace('\n', ' ')

然后,您可以在结构一致的标题中的每个边界上进行拆分。

content = content.split("Name_OF_Person:")[1] #take second element of the list
person = content.split("Adress_HOME:")[0] # take content before "Adress Home"
content = content.split("Adress_HOME:")[1]  #take second element of the list
address = content.split("Company_NAME:")[0] # take content before 
company = content.split("Adress_HOME:")[1]  #take second element of the list (the remainder) which is company

通常,我会建议使用正则表达式。 (https://docs.python.org/3.4/library/re.html)。从长远来看,如果您需要再次执行此类操作,正则表达式将在花费时间处理数据方面获得回报。要使正则表达式函数跨多行“剪切”,您将使用re.MULTILINE 选项。所以它最终可能看起来像re.search('Name_OF_Person:(.*)Adress_HOME:', html_reg_form, re.MULTILINE)

【讨论】:

  • 它们非常强大。 (如果有时不是有点混乱,但基本模式会让你走得很远)。如果我有帮助,请不要忘记接受答案:)
  • 是的,我想我必须在你和@yaniv 的 2 个答案之间创建一个混合体
猜你喜欢
  • 2014-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多