【问题标题】:How to change weird CSV delimiter?如何更改奇怪的 CSV 分隔符?
【发布时间】:2016-12-11 11:16:21
【问题描述】:

我有一个无法在 Excel 中打开的 CSV 文件。

CSV 分隔符是|~|,在行尾是|~~|

我有一些示例数据:

Education|~|Name_Dutch|~|Name_English|~|Faculty|~~|International Business|~|MB|~|MB|~|ED|~~|

Header 部分在哪里:Education|~|Name_Dutch|~|Name_English|~|Faculty|~~|

Data/Row 部分是:International Business|~|MB|~|MB|~|ED|~~|

我需要了解如何使用 Python 脚本将这个 CSV 文件更改为普通的 , 逗号分隔值。

【问题讨论】:

  • 在我看来,分隔符是相对常见的“|”,但您应该至少显示几行数据,而不仅仅是看起来像标题的内容。
  • 我给了一点数据,头部分是:Education|~|Name_Dutch|~|Name_English|~|Faculty|~~|数据部分是:国际商务|~|MB|~|MB|~|ED|~~|
  • 始终编辑您的帖子以包含您最初帖子中缺少的额外信息,切勿将其隐藏在评论中。

标签: python csv


【解决方案1】:

可以辅助内置csv模块+string.split()功能:

import csv

content = """Education|~|Name_Dutch|~|Name_English|~|Faculty|~~|International Business|~|MB|~|MB|~|ED|~~|"""

# Or read it's content from a file 

with open('output.csv', 'w+') as f:
    writer = csv.writer(f)
    lines = content.split('|~~|')
    for line in lines:
        csv_row = line.split('|~|')
        writer.writerow(csv_row)

它会输出一个名为output.csv的文件

Education,Name_Dutch,Name_English,Faculty
International Business,MB,MB,ED
""

在处理 csv 文件时,我更喜欢使用 csv 模块而不是 .replace('|~|', ','),因为 csv 模块内置了对特殊字符的支持,例如 ,

【讨论】:

    【解决方案2】:

    您提到的自定义分隔符似乎足够独特,因此您只需对它们执行 string.replace 即可。然后只写出文件。 读写部分包含您需要的所有详细信息。 https://docs.python.org/2/tutorial/inputoutput.html

    【讨论】:

      【解决方案3】:
      import csv
      
      in_name = 'your_input_name.csv'
      outname = 'your_outpt_name.csv'
      
      with open(in_name, newline='') as csvfile:
          csvreader = csv.reader(csvfile, delimiter='~', quotechar='|')
          with open(outname, "w", newline='') as outfile:
              csvwriter = csv.writer(outfile, quotechar='"', quoting=csv.QUOTE_NONNUMERIC)
              for row in csvreader:
                  line = []
                  for item in row:
                      if item != "":
                          line.append(item)
                      else:
                          csvwriter.writerow(line)
                          line = []
      

      由于csv.reader 无法将"~~" 识别为行尾,它会将其转换为"",因此对于csv.writer,我们反复准备列表部分(从csv.reader 获得)直到""已到达。

      【讨论】:

        【解决方案4】:

        如果文件很小,您可以简单地将其全部内容读入内存并替换找到的所有奇怪的分隔符,然后将其写回新版本。

        但是,如果文件很大或者您只是想节省内存使用量,也可以逐步读取文件,一次读取一个字符,然后完成需要完成的工作。

        csv.reader 构造函数的csvfile 参数“可以是任何支持迭代器协议并在每次调用其next() 方法时返回一个字符串的对象。”

        这意味着“对象”可以是生成器函数或生成器表达式。在下面的代码中,我实现了一个简单的 FSM (Finite State Machine) 来解析格式奇特的文件和 yield 它检测到的每一行输出。看起来代码很多,但操作起来非常简单,所以应该比较容易理解它是如何工作的:

        import csv
        
        def weird_file_reader(filename):
            """Generator that opens and produces "lines" read from the file while
               translating the sequences of '|~|' to ',' and '|~~|' to '\n' (newlines).
            """
            state = 0
            line = []
            with open(filename, 'rb') as weird_file:
                while True:
                    ch = weird_file.read(1)  # read one character
                    if not ch:  # end-of-file?
                        if line:  # partial line read?
                            yield ''.join(line)
                        break
                    if state == 0:
                        if ch == '|':
                            state = 1
                        else:
                            line.append(ch)
                            #state = 0  # unnecessary
                    elif state == 1:
                        if ch == '~':
                            state = 2
                        else:
                            line.append('|'+ch)
                            state = 0
                    elif state == 2:
                        if ch == '|':
                            line.append(',')
                            state = 0
                        elif ch == '~':
                            state = 3
                        else:
                            line.append('|~'+ch)
                            state = 0
                    elif state == 3:
                        if ch == '|':
                            line.append('\n')
                            yield ''.join(line)
                            line = []
                            state = 0
                        else:
                            line.append('|~~'+ch)
                            state = 0
                    else:
                        raise RuntimeError("Can't happen")
        
        with open('fixed.csv', 'wb') as outfile:
            reader = csv.reader((line for line in weird_file_reader('weird.csv')))
            writer = csv.writer(outfile)
            writer.writerows(reader)
        
        print('done')
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-11-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-30
          • 2015-10-12
          • 1970-01-01
          相关资源
          最近更新 更多