2016-02-19 20 views
1

我想在Bash腳本中讀取CSV文件。我實現了成功地利用gawk並指定FPAT像:這裏如果只有非空字段被雙引號括起來,我該如何讀取CSV文件?

gawk -v LOGFILE="${LOGFILE}" 'BEGIN { 
    FPAT = "([^,]+)|(\"[^\"]+\")" 
    } 
NR == 1{ 
    # doing some logic with header 
} 
NR >= 2{ 
    # doing some logic with fields 
}' <filename> 

的問題是,該文件包含類似的數據:現在

"RAM","31st street, Bengaluru, India",,,,"7865431234",,"VALID" 

,這個數據我得到錯誤的數據,因爲它是忽略逗號,這給我提取的數據的位置數量錯誤。 例如,它告訴「7865431234」出現在第3位,而在第6位。

任何人都可以提出更改以獲取正確的字段位置嗎?

+0

這些值本身是否可以包含逗號? – neuhaus

+0

是的,因爲第二個字段是地址。它可以包含任意數量的逗號。 –

+3

我會使用perl和[Text :: CSV]模塊(http://search.cpan.org/~makamaka/Text-CSV-1.33/lib/Text/CSV.pm)。 – neuhaus

回答

2

您的FPAT要求每個字段至少包含一個字符,但您希望識別空字段爲零字符。在FPAT

gawk 'BEGIN { FPAT = "([^,]+)|(\"[^\"]+\")|" } 
{ printf "%d:%d:", NR, NF; for (i = 1; i <= NF; i++) printf("[%s]", $i); print "" }' 

注意額外|:另一種添加到FPAT允許零個字符。該操作只是標識記錄號,字段數,並用方括號括住每個字段的值。

當你的數據串提供給該腳本,輸出:

1:8:["RAM"]["31st street, Bengaluru, India"][][][]["7865431234"][]["VALID"] 

,顯示了4個空場很清楚。

現在你要做的就是處理:

"Mr ""Manipulator"", the Artisan","29th Street, Delhi, India",,,"",,,"INVALID" 

那裏有引號裏面的值雙引號。這並不可怕難以管理:

gawk 'BEGIN { FPAT = "([^,]+)|(\"([^\"]|\"\")*\")[^,]*|" } 
{ printf "%d:%d:", NR, NF; for (i = 1; i <= NF; i++) printf("%d[%s]", i, $i); print "" }' "[email protected]" 

FPAT說,一個領域是:

  • 非逗號的序列,
  • ,或者是一個領域開始與雙引號,含的零個或多個實例:

    • 非報價,或
    • 兩個雙引號

    後跟雙引號和可選的非逗號數據

  • 或爲空

注意「可選的非逗號數據」應該是空的,只出現在格式不正確的CSV數據中。

給定的輸入數據:

"RAM","31st street, Bengaluru, India",,,,"7865431234",,"VALID" 
"Mr ""Manipulator"", the Artisan","29th Street, Delhi, India",,,,,,"INVALID" 
"Some","","Empty","",Fields "" Wrapped,"",in quotes 
"Malformed" CSV,Data,"Note it has data after" a close quote,"and before a comma,",,"INVALID" 

這產生:

1:8:1["RAM"]2["31st street, Bengaluru, India"]3[]4[]5[]6["7865431234"]7[]8["VALID"] 
2:8:1["Mr ""Manipulator"", the Artisan"]2["29th Street, Delhi, India"]3[]4[]5[]6[]7[]8["INVALID"] 
3:7:1["Some"]2[""]3["Empty"]4[""]5[Fields "" Wrapped]6[""]7[in quotes] 
4:6:1["Malformed" CSV]2[Data]3["Note it has data after" a close quote]4["and before a comma,"]5[]6["INVALID"] 

注意,場數被包括作爲一個前綴添加到括號數據(所以我調整了打印格式略)。

關於唯一不能處理的格式是可以在字段的數據中嵌入換行符 - 根據基於行的輸入的性質,它假定沒有字段被拆分爲多行。 (這也意味着它不會正確識別以雙引號開頭的字段,並且在行尾之前沒有匹配的雙引號。我想你可以添加一個替代方法來識別該字段。使數據的權利。)


注意建議在Sobriqueanswer用設計來處理CSV用於處理CSV的工具。這通常是一個好主意,而且你必須處理的變體組合越複雜,它的想法就越好。這與您應該考慮使用的正則表達式非常接近。還要注意,儘管RFC 4180正式和嚴格地定義了一個CSV版本,但有多個程序(包括MS Office)可以處理不同但相關的格式。

3

如果你有csv需要解析,那麼雖然你通常可以用正則表達式來破解它,但使用解析器要容易得多。

事情是這樣的:

#!/usr/bin/env perl 

use strict; 
use warnings; 
use Text::CSV; 

my $csv = Text::CSV -> new; 
open (my $input, '<', 'flarg.csv') or die $!; 

while (my $row = $csv -> getline ($input)) { 
    if ($. == 1) { 
     # do first row stuff; 
     print "Header: ", join ",", @$row,"\n"; 
    } 
    else { 
     print join "\n", @$row; 
    } 
} 

或者更簡單,但 - 使用Text::ParseWords這是核心。

#!/usr/bin/env perl 

use strict; 
use warnings; 
use Text::ParseWords; 

while (my $line = <DATA>) { 
    my @fields = parse_line(',', 1, $line); 
    print join "\n", @fields; 
} 
__DATA__ 
"RAM","31st street, Bengaluru, India",,,,"7865431234",,"VALID" 
相關問題