awk khi cả dấu phân cách và dấu ngoặc kép được sử dụng cho một trường


7

Tôi có một tập tin theo định dạng sau:

field1|field2|field3
field1|"field2|field2"|field3

Lưu ý hàng thứ hai chứa dấu ngoặc kép. Chuỗi trong dấu ngoặc kép thuộc về trường 2. Làm thế nào để giải nén điều này bằng cách sử dụng awk? Tôi đã googling không có kết quả. Tôi đã thử điều này mà không có may mắn là tốt

FS='"| "|^"|"$' '{print $2}'  

Câu trả lời:


10

Nếu bạn có một phiên bản gần đây của gawkbạn là may mắn. Có FPATtính năng, được ghi lại ở đây

awk 'BEGIN {
 FPAT = "([^|]+)|(\"[^\"]+\")"
}
{
 print "NF = ", NF
 for (i = 1; i <= NF; i++) {
    sub(/"$/, "", $i); sub(/^"/, "", $i);printf("$%d = %s\n", i, $i)
 }
}' file

NF =  3
$1 = field1
$2 = field2
$3 = field3
NF =  3
$1 = field1
$2 = field2|field2
$3 = field3

Bạn có thể thay thế + bằng * FPAT = "([^|]*)|(\"[^\"]+\")"để xử lý các trường trống, chẳng hạn như||
Reza Sanaie

Xuất sắc. Tuy nhiên, trong trường hợp tôi đang sử dụng điều này trên các tệp được phân tách bằng dấu phẩy thì nó không đối phó với dấu ngoặc kép trong trường, vì vậy tôi đang sử dụng FPAT = "([^,]*)|(\"([^\"]|\"\")*\")". Đối với ở trên với phân định đường ống nó sẽ được FPAT = "([^|]*)|(\"([^\"]|\"\")*\")".
Reg Whitton

Vậy, nếu tôi không có sẵn FPAT thì sao?
musicin3d

@ musicin3d, trong trường hợp đó, hãy xem giải pháp perl của
Sobrique

1

Đây là một cái gì đó mà bạn nhận được csv- nếu dấu phân cách là một phần của trường, nó sẽ được trích dẫn. Điều đó đột nhiên làm cho nhiệm vụ phân tích cú pháp RẤT NHIỀU hơn, bởi vì bạn không thể phân tách trên một delim.

May mắn thay, nếu perllà một tùy chọn, bạn có Text::CSVmô-đun xử lý trường hợp này:

#!/usr/bin/env perl
use strict;
use warnings;

use Text::CSV;

my $csv = Text::CSV -> new ( { 'sep_char' => '|' } );

while ( my $row =  $csv -> getline ( *STDIN ) ) {
   print $row -> [1],"\n";
}

Có lẽ có thể ngưng tụ điều này thành một nội tuyến / có thể điều chỉnh được nếu bạn thích - đại loại như:

perl -MText::CSV -e 'print map { $_ -> [1] ."\n" } @{ Text::CSV -> new ( { 'sep_char' => '|' } ) -> getline_all ( *ARGV )};

-2

Bạn có thể muốn định dạng dữ liệu này sedđể có thể phân tích cú pháp awkdễ dàng hơn. ví dụ:

$ sed 's/"//g' awktest1.txt 
field1|field2|field3
field1|field2|field2|field3

$ sed 's/"//g' awktest1.txt > awktest2.txt

$ awk 'BEGIN {FS = "|"} ; {print $2}' awktest2.txt 
field2
field2

Nhưng một lần nữa, tôi không biết bản chất của dữ liệu bạn đang làm việc.


2
Ý tưởng rõ ràng là có field2|field2một trường duy nhất trong dòng thứ hai.
klimpergeist
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.