【问题标题】:Python csv: Split column to columns and then to rows by delimiterPython csv:将列拆分为列,然后按分隔符拆分为行
【发布时间】:2019-09-04 07:47:37
【问题描述】:

我在 csv 文件中有一个列,其中包含这种格式的人员详细信息:

+--------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|  Team  |                                                                                                Members                                                                                                 |
+--------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Team 1 | OK-10:Jason:Jones:ID No:00000000:male:my notes                                                                                                                                                         |
| Team 2 | OK-10:Mike:James:ID No:00000001:male:my notes OZ-09:John:Rick:ID No:00000002:male:my notes                                                                                                             |
| Team 3 | OK-08:Michael:Knight:ID No:00000004:male:my notes2 OK-09:Helen:Rick:ID No:00000005:female:my notes3 OZ-10:Jane:James:ID No:00000034:female:my notes23 OK-09:Mary:Jane:ID No:00000023:female:my notes46 |
+--------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

实际的csv格式:

"Team", "Members"                                                                                                 
 Team 1, OK-10:Jason:Jones:ID No:00000000:male:my notes                                                                                                                                                         
 Team 2, OK-10:Mike:James:ID No:00000001:male:my notes OZ-09:John:Rick:ID No:00000002:male:my notes                                                                                                             
 Team 3, OK-08:Michael:Knight:ID No:00000004:male:my notes2 OK-09:Helen:Rick:ID No:00000005:female:my notes3 OZ-10:Jane:James:ID No:00000034:female:my notes23 OK-09:Mary:Jane:ID No:00000023:female:my notes46

我想将它们拆分成一个新的 csv 文件,如下所示:

+-------+-------------+-------------+----------------+------------------+---------------+---------------+--------------+
| Team  | Member_Rank | Member_Name | Member_Surname | Member_ID_Method | Member_ID_Num | Member_Gender | Member_Notes |
+-------+-------------+-------------+----------------+------------------+---------------+---------------+--------------+
| Team1 | OK-10       | Jason       | Jones          | ID No            |      00000000 | male          | my notes     |
| Team2 | OK-10       | Mike        | James          | ID No            |      00000001 | male          | my notes     |
| Team2 | OZ-09       | John        | Rick           | ID No            |      00000002 | male          | my notes     |
+-------+-------------+-------------+----------------+------------------+---------------+---------------+--------------+

拆分细节:

拆分行分隔符:' O&-' 其中 & 只能是 'K' 或 'Z'

拆分列分隔符:':',新 csv 文件中的列号是固定的

(一个团队可以包含多个成员,没有上限)

更新

通过使用@Adirio 提供的这段代码,我只能从具有多个成员的字段中获取最后一个成员:

import csv
import re


members_split_regex = re.compile(r'(O[KZ]-\d+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+)(?= O[KZ]|$)')

with open('test.csv') as input_file, open('output_csv.csv', 'w', newline='') as output_file:
    csv_reader = csv.DictReader(input_file)
    fieldnames = csv_reader.fieldnames.copy()
    fieldnames.remove('Members')
    csv_writer = csv.DictWriter(output_file, extrasaction='ignore', fieldnames=fieldnames + ['Member_Rank', 'Member_Name', 'Member_Surname', 'Member_ID_Method', 'Member_ID_Num', 'Member_Gender', 'Member_Notes'])
    csv_writer.writeheader()
    for row in csv_reader:
        for member_tuple in members_split_regex.findall(row['Members']):
                member_dict = {}
                (
                    member_dict['Member_Rank'],
                    member_dict['Member_Name'],
                    member_dict['Member_Surname'],
                    member_dict['Member_ID_Method'],
                    member_dict['Member_ID_Num'],
                    member_dict['Member_Gender'],
                    member_dict['Member_Notes']
                ) = member_tuple
                print(row['Members'])
                print(member_tuple)
                member_dict.update(row)
                csv_writer.writerow(member_dict)

打印结果:

行['成员'] ->

OK-1:name1:sunrmae2:ID No:id1233123:male:note12 OK-10:name2:sunrame2:Passport No:asda3243242:female:note2 OZ-1:nma3:surname3:护照号码:asd213131:other:note 56

打印(成员元组)->

('OZ-1', 'nma3', 'surname3', '护照号', 'asd213131', '其他', '注 56')

【问题讨论】:

标签: python csv


【解决方案1】:

假设这个输入是 CSV

Team,Members
Team 1,OK-10:Jason:Jones:ID No:00000000:male:my notes
Team 2,OK-10:Mike:James:ID No:00000001:male:my notes OZ-09:John:Rick:ID No:00000002:male:my notes
Team 3,OK-08:Michael:Knight:ID No:00000004:male:my notes2 OK-09:Helen:Rick:ID No:00000005:female:my notes3 OZ-10:Jane:James:ID No:00000034:female:my notes23 OK-09:Mary:Jane:ID No:00000023:female:my notes46

这可以通过正则表达式、csv.DictReader 和 csv.DictWriter 来实现:

import csv
import re

output = []

members_split_regex = re.compile(r'(O[KZ]-\d+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+)(?= O[KZ]|$)')

with open('test.csv') as f:
    csv_reader = csv.DictReader(f)
    for row in csv_reader:
        team = row['Team']
        members = row['Members']
        split_members = members_split_regex.findall(members)
        for member in split_members:
                (member_rank, member_name, member_surname, member_id_method,
                 member_id_num, member_gender, member_notes) = member

                output.append({'Team': team, 'Member_Rank': member_rank, 'Member_Name': member_name,
                               'Member_Surname': member_surname, 'Member_ID_Method': member_id_method,
                               'Member_ID_Num': member_id_num, 'Member_Gender': member_gender,
                               'Member_Notes': member_notes})

with open('output_csv', 'w', newline='') as f:
    csv_writer = csv.DictWriter(f, fieldnames=['Team', 'Member_Rank', 'Member_Name', 'Member_Surname', 'Member_ID_Method', 'Member_ID_Num', 'Member_Gender', 'Member_Notes'])
    csv_writer.writeheader()
    csv_writer.writerows(output)

输出文件是

Team,Member_Rank,Member_Name,Member_Surname,Member_ID_Method,Member_ID_Num,Member_Gender,Member_Notes
Team 1,OK-10,Jason,Jones,ID No,00000000,male,my notes
Team 2,OK-10,Mike,James,ID No,00000001,male,my notes 
Team 2,OZ-09,John,Rick,ID No,00000002,male,my notes
Team 3,OK-08,Michael,Knight,ID No,00000004,male,my notes2 
Team 3,OK-09,Helen,Rick,ID No,00000005,female,my notes3 
Team 3,OZ-10,Jane,James,ID No,00000034,female,my notes23 
Team 3,OK-09,Mary,Jane,ID No,00000023,female,my notes46

【讨论】:

  • 我可以推荐(O[KZ]-\d+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+?)(?= O[KZ]|$)吗?
  • @Adirio 你为什么会这样?它更复杂,当前的正则表达式可以完成工作
  • @DeepSpace 'ID No' 不固定,例如可以是'Passport No'
  • 你在硬编码ID No,强制ID为8位数字,如果前一个字段不是ID No,则可能不是数字,不接受名称中的空格和姓氏(复合名称很常见),不允许在注释列中使用O 字符等。
  • @netdev 使用他的解决方案,但在re.compile(r'...') 中使用我的正则表达式,你应该得到你正在寻找的解决方案。
【解决方案2】:

基于@DeepSpace 的答案,但有一个固定的regex 并添加了新要求:

import csv
import re


members_split_regex = re.compile(r'(O[KZ]-\d+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+):([a-zA-Z0-9 ]+)(?= O[KZ]|$)')

with open('test.csv') as input_file, open('output_csv', 'w', newline='') as output_file:
    csv_reader = csv.DictReader(input_file)
    fieldnames = csv_reader.fieldnames.copy()
    fieldnames.remove('Members')
    csv_writer = csv.DictWriter(output_file, extrasaction='ignore', fieldnames=fieldnames + ['Member_Rank', 'Member_Name', 'Member_Surname', 'Member_ID_Method', 'Member_ID_Num', 'Member_Gender', 'Member_Notes'])
    csv_writer.writeheader()
    for row in csv_reader:
        for member_tuple in members_split_regex.findall(row['Members']):
            member_dict = {}
            (
                member_dict['Member_Rank'],
                member_dict['Member_Name'],
                member_dict['Member_Surname'],
                member_dict['Member_ID_Method'],
                member_dict['Member_ID_Num'],
                member_dict['Member_Gender'],
                member_dict['Member_Notes']
            ) = member_tuple
            member_dict.update(row)
            csv_writer.writerow(member_dict)

主要区别在于我从字典中删除了该列,以便我们可以使用它来更新我们的新字典。这样,我们不仅复制了“团队”列,还复制了任何其他不是“成员”的列。为此,还要复制阅读器的字段名,删除“成员”项,并将新的项添加到写入者的字段名中。

使用的正则表达式不硬编码任何字段,允许姓名和姓氏中的空格,注释中的大写 Os,以及不仅仅是 8 位数字的 ID 字段。

【讨论】:

  • @joumaico ty 否决了您要求我发布的答案,以报复我对您的无效答案投反对票
  • @netdev 此解决方案基于已接受的解决方案,其中包含您在评论中提出的新要求。
  • @DeepSpace 随意将更改包含在您的答案中,我将删除它。我无意复制您的代码并称其为我的,只是想回答您在答案的 cmets 中提到的他的新要求。
  • 可以满足我的所有要求!但是最后一个问题只是为了更好地理解 python,是否有可能不硬编码所有字段名,而是获取现有字段名并仅添加新字段名?像这样的东西:csv_writer = csv.DictWriter(f, fieldnames=[ Get_all_existing_fields() , 'Member_Rank', 'Member_Name', 'Member_Surname', 'Member_ID_Method', 'Member_ID_Num', 'Member_Gender', 'Member_Notes'])
  • @netdev 看看编辑后的答案,它也使这个自动
猜你喜欢
  • 1970-01-01
  • 2019-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-18
  • 2022-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多