1

[使用 Python3] 我有一个 csv 文件,它有两列(一个电子邮件地址和一个国家/地区代码;如果原始文件中不是这种情况,脚本实际上使它成为两列 - 有点),我想通过第二列中的值并在单独的 csv 文件中输出。

eppetj@desrfpkwpwmhdc.com       us      ==> output-us.csv
uheuyvhy@zyetccm.com            de      ==> output-de.csv
avpxhbdt@reywimmujbwm.com       es      ==> output-es.csv
gqcottyqmy@romeajpui.com        it      ==> output-it.csv
qscar@tpcptkfuaiod.com          fr      ==> output-fr.csv
qshxvlngi@oxnzjbdpvlwaem.com    gb      ==> output-gb.csv
vztybzbxqq@gahvg.com            us      ==> output-us.csv
...                             ...     ...

目前我的代码是这样做的,但不是将每个电子邮件地址写入 csv,而是覆盖之前放置的电子邮件。有人可以帮我解决这个问题吗?

我对编程和 Python 非常陌生,我可能没有以最 Python 的方式编写代码,所以我非常感谢对代码的任何反馈!

提前致谢!

代码:

import csv

def tsv_to_dict(filename):
    """Creates a reader of a specified .tsv file."""
    with open(filename, 'r') as f:
        reader = csv.reader(f, delimiter='\t') # '\t' implies tab
        email_list = []
        # Checks each list in the reader list and removes empty elements
        for lst in reader:
            email_list.append([elem for elem in lst if elem != '']) # List comprehension
        # Stores the list of lists as a dict
        email_dict = dict(email_list)
    return email_dict

def count_keys(dictionary):
    """Counts the number of entries in a dictionary."""
    return len(dictionary.keys())

def clean_dict(dictionary):
    """Removes all whitespace in keys from specified dictionary."""
    return { k.strip():v for k,v in dictionary.items() } # Dictionary comprehension

def split_emails(dictionary):
    """Splits out all email addresses from dictionary into output csv files by country code."""
    # Creating a list of unique country codes
    cc_list = []
    for v in dictionary.values():
        if not v in cc_list:
            cc_list.append(v)

    # Writing the email addresses to a csv based on the cc (value) in dictionary
    for key, value in dictionary.items():
        for c in cc_list:
            if c == value:
                with open('output-' +str(c) +'.csv', 'w') as f_out:
                    writer = csv.writer(f_out, lineterminator='\r\n')
                    writer.writerow([key])
4

3 回答 3

1

您可以通过使用 a 来简化很多defaultdict

import csv
from collections import defaultdict

emails = defaultdict(list)

with open('email.tsv','r') as f:
   reader = csv.reader(f, delimiter='\t')
   for row in reader:
      if row:
         if '@' in row[0]:
           emails[row[1].strip()].append(row[0].strip()+'\n')

for key,values in emails.items():
   with open('output-{}.csv'.format(key), 'w') as f:
       f.writelines(values)

由于您分隔的文件不是逗号分隔的,而是单列 - 您不需要 csv 模块并且可以简单地写入行。

emails字典包含每个国家/地区代码的键,以及所有匹配电子邮件地址的列表。为了确保正确打印电子邮件地址,我们删除了所有空格并添加了换行符(这样我们writelines以后可以使用)。

填充字典后,只需逐步通过键创建文件,然后写出结果列表。

于 2013-06-06T08:02:34.960 回答
1

您的代码的问题在于,每次将条目写入其中时,它都会打开相同的国家/地区输出文件,从而覆盖可能已经存在的任何内容。

避免这种情况的一种简单方法是一次打开所有输出文件进行写入并将它们存储在由国家代码键入的字典中。同样,您可以使用另一个将每个国家/地区代码与csv.writer该国家/地区输出文件的对象相关联。

更新:虽然我同意 Burhan 的方法可能更优越,但我觉得您认为我之前的回答过于冗长,因为它有所有评论——所以这里有另一个版本的基本相同的逻辑,但允许的评论最少您最好辨别其合理短的真实长度(即使使用上下文管理器)。

import csv
from contextlib import contextmanager

@contextmanager  # to manage simultaneous opening and closing of output files
def open_country_csv_files(countries):
    csv_files = {country: open('output-'+country+'.csv', 'w') 
                   for country in countries}
    yield csv_files
    for f in csv_files.values(): f.close()

with open('email.tsv', 'r') as f:
    email_dict = {row[0]: row[1] for row in csv.reader(f, delimiter='\t') if row}

countries = set(email_dict.values())
with open_country_csv_files(countries) as csv_files:
    csv_writers = {country: csv.writer(csv_files[country], lineterminator='\r\n')
                    for country in countries}
    for email_addr,country in email_dict.items():
        csv_writers[country].writerow([email_addr])
于 2013-06-06T08:33:42.753 回答
0

不是 Python 答案,但也许你可以使用这个 Bash 解决方案。

$ while read email country
do
  echo $email >> output-$country.csv
done < in.csv

这将从 中读取行in.csv,将它们分成两部分email,然后将 ( )country附加到名为.>>emailoutput-$country.csv

于 2013-06-06T07:57:27.313 回答