Skip to content

Instantly share code, notes, and snippets.

@ckhung
Last active May 4, 2016 12:50
Show Gist options
  • Save ckhung/396942e66cf212500a7258e9a41d6bb8 to your computer and use it in GitHub Desktop.
Save ckhung/396942e66cf212500a7258e9a41d6bb8 to your computer and use it in GitHub Desktop.
把 csv 檔的很多個同性質欄位合併成兩個欄位
#!/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];
}
}
@ckhung
Copy link
Author

ckhung commented May 4, 2016

這個有點難解釋.. 學生在整理一些政府公開資料, 其中有一些來自 「中華民國統計資訊網」 的資料 下載之後長得像這樣。 縱軸是時間, 橫軸是縣市別。 這樣不好用。想要把橫軸合併成 「縣市別」 一個欄位就好,像這樣

可以用這支小程式這樣處理: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欄的資訊才不會消失。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment