簡體   English   中英

如果僅非空字段用雙引號引起來,我如何讀取CSV文件?

[英]How can I read a CSV file if only non-empty fields are wrapped by double quotes?

我正在嘗試在Bash腳本中讀取CSV文件。 我成功地使用gawk並指定FPAT來實現該目標,例如:

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位。

誰能建議更改以獲取正確的字段位置?

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"]

這清楚地顯示了四個空字段。

現在您所要做的就是處理:

"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 "" }' "$@"

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"]

請注意,字段號作為括號數據的前綴包括在內(因此我略微調整了打印格式)。

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


請注意Sobrique 答案中的建議,以使用專門用於處理CSV的工具來處理CSV。 通常這是一個好主意,並且您必須處理的變體集越復雜,它就越好。 您應該考慮使用的正則表達式非常復雜。 還要注意,盡管RFC 4180正式且嚴格地定義了CSV版本,但仍有多個程序(包括MS Office)處理不同但相關的格式。

如果您有需要解析的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"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM