Last active
May 4, 2016 12:50
-
-
Save ckhung/396942e66cf212500a7258e9a41d6bb8 to your computer and use it in GitHub Desktop.
把 csv 檔的很多個同性質欄位合併成兩個欄位
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl -w | |
use strict; | |
use utf8; | |
use Getopt::Std; | |
my (%opts, @header, @decol, $x, $i); | |
%opts = ( | |
d => ',', # delimiter | |
c => '0-', # columns to be de-columned. '0-6,8,12-15' | |
); | |
getopts('d:c:', \%opts); | |
binmode(STDIN, ':encoding(utf8)'); | |
binmode(STDOUT, ':encoding(utf8)'); | |
@decol = (0) x 99; | |
foreach $x (split(',', $opts{c})) { | |
$x =~ /^(\d+)?(-?)(\d+)?$/ | |
or die "'$x' does not conform to the correct -c format '0-6,8,12-15'"; | |
if ($2) { | |
my ($a, $z) = ($1 || 0, $3 || 99); | |
@decol[$a..$z] = (1) x ($z-$a+1); | |
} else { | |
@decol[$1] = 1; | |
} | |
} | |
while (<STDIN>) { | |
chomp; | |
s/\015//g; | |
my @f = split(/\s*$opts{d}\s*/); | |
next if (/^#/ || !join('', @f)); | |
if (!@header) { | |
@header = @f; | |
@decol = @decol[0..$#f]; | |
next; | |
} | |
my ($out) = ''; | |
for ($i=0; $i<=$#header && $i<=$#f; ++$i) { | |
$out .= "$f[$i]$opts{d}" unless $decol[$i]; | |
} | |
for ($i=0; $i<=$#header && $i<=$#f; ++$i) { | |
print "$out$header[$i]$opts{d}$f[$i]\n" if $decol[$i]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
這個有點難解釋.. 學生在整理一些政府公開資料, 其中有一些來自 「中華民國統計資訊網」 的資料 下載之後長得像這樣。 縱軸是時間, 橫軸是縣市別。 這樣不好用。想要把橫軸合併成 「縣市別」 一個欄位就好,像這樣。
可以用這支小程式這樣處理:
decolumn-csv.pl -c 2- < edu-emp.csv > edu-emp-decolumned.csv
這會保留 0 及 1 欄; 第 2 欄到最後會被拆成很多列,除了先前保留的欄位之外, 每列只剩兩欄: 原先的欄位名稱(縣市名稱)及對應的值。可用的選項及預設值有:
-d ,
: 以 「,」 為分隔符號-c 0-
: 「0-」 這些欄都要刪掉。 可接受的語法長得像這樣:「-3,7-9,15,20-
」 表示要刪掉 0,1,2,3,7,8,9,15,20一直到最末欄。遇到空白列或是以 # 開頭的列, 會自動略過。
以上面的範例資料檔為例, 建議應該先把第0欄(教育程度別)填滿再來處理,第0欄的資訊才不會消失。