【问题标题】:Parse CSV file and perform conversion in Linux在 Linux 中解析 CSV 文件并执行转换
【发布时间】:2013-06-23 15:36:37
【问题描述】:

我有一个包含很多列的大 CSV 文件(几个 100 MB):

1;18Jun2013;23:58:58;;;l;o;t;s;;;;o;f;;;;;o;t;h;e;r;;;;;c;o;l;u;m;n;s;;;;;

您看到第二列是我希望格式为 %Y-%m-%d 的日期,以便在数据库中轻松插入和排序。我相信转换原始数据而不是稍后在数据库中转换更容易和更快。

主脚本使用 bash。现在我进行了如下的转换:

  sed -n '2,$p' $TMPF | while read line; do
        begin=$(echo "$line" | cut -d\; -f1)
        origdate=$(echo "$line" | cut -d\; -f2)
        #cache date translations, hash table for the poor
        eval origdateh=h$origdate
        if [ "x${!origdateh}" = "x" ]; then
        # not cached till now, need to call date, then store
            datex=$(date -d "$origdate" +%Y-%m-%d)
            eval h$origdate="$datex"
        else
        # cache hit
            datex=$(eval echo \$h$origdate)
        fi
        end=$(echo "$line" | cut -d\; -f3-)
        echo "$begin;$datex;$end" >> $TMPF2
    done

我使用 sed 从第二行开始(第一行包含 CSV 标题),我相信所有带有 echo 和 cut 的子shell都会减慢速度,所以“哈希表”真的没什么用...

谁能让这件事进展得更快?

【问题讨论】:

  • Who can make this go fast?:只有你使用专用的 CSV 解析器。
  • 这必须在 bash 中完成吗?如果你使用比 shell 更好的数组/拆分/连接实现(我在想 ruby​​/perl/python),你可能会显着提高速度。

标签: linux unix csv


【解决方案1】:

不要使用 bash 脚本,而是使用 Python 脚本。至少,这将更具可读性/可维护性,并且可能更有效。

示例代码可能如下所示(未经测试):

# file: converter.py

import datetime

def convert_line(line):
    # split line on ';'
    line = line.split(';')
    # get the date part (second column)
    # parse date from string
    date = datetime.date.strptime(line[1], '%d%a%Y')
    # convert to desired format
    # replace item in line
    line[1] = date.strftime('%Y-%m-%d')
    # return converted line
    return ';'.join(line)

while True:
    print convert_line(raw_input())

现在你只需这样做:

cat file.csv | python converter.py > file_converted.csv

替代实现:

# file: converter_2.py

import datetime

def convert_line(line):
    # split line on ';'
    line = line.split(';')
    # get the date part (second column)
    # parse date from string
    date = datetime.date.strptime(line[1], '%d%a%Y')
    # convert to desired format
    # replace item in line
    line[1] = date.strftime('%Y-%m-%d')
    # return converted line
    return ';'.join(line)

with open('file.csv') as infile, open('file_converted.csv', 'w+') as outfile:
    outfile.writelines(convert_line(line) for line in infile)

示例用法:

python converter_2.py

如果你的csv中有一些标题行,你当然不能用这个函数来转换它们。

【讨论】:

  • 它的速度非常合我的胃口(几分钟内 700 MB 文件)。
【解决方案2】:

谢谢,我尝试了第一个示例,当从 bash 脚本中调用时,以下示例似乎可以正常工作。

# file: converter.py
import datetime
def convert_line(line):
    # split line on ';'
    line = line.split(';')
    # get the date part (second column)
    # parse date from string
    date = datetime.datetime.strptime(line[1], '%d%b%Y')
    # convert to desired format
    # replace item in line
    line[1] = date.strftime('%Y-%m-%d')
    # return converted line
    return ';'.join(line)
while True:
    try:
        print convert_line(raw_input())
    except (EOFError):
        break

使用

tail +2 FILE | python csvconvert.py > xxx

跳过标题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 2021-01-09
    • 2021-10-29
    • 2012-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多