대용량 CSV 파일(300MB 이상)이 있고 2,3, 6-8열만 제거하고 Perl을 사용하여 중복 행을 제거하고 싶습니다.
참고 1: 모든 열은 ,
(쉼표)로 구분되지만 때로는 내 셀 값에 ,
(마지막 행, 열 9 및 10 참조)로 구분된 하나 이상이 포함되어 ,
있으므로 "
여전히 csv 파일을 처리할 수 있기를 원합니다. , ,
셀 내부에 있는 경우에도 마찬가지입니다 .
참고 2: input.csv 및 output.csv 파일에 대한 링크를 추가했습니다.
Col1,Col2,Col3,Col4,Col5,Col6,Col7,Col8,Col9,Col10
info 1,info 2,info 3,...,info 10
address 1,address 2,....,address 10
city 1,city 2,city 3,city 4,city 5,city 6,city 7,city 8,"city 9, extra","city 10, new"
Col1,Col4,Col5,Col9,Col10
info 1,info 4,info 5,info 9,info 10
address 1,address 4,address 5,address 9,address 10
city 1,city 4,city 5,"city 9, extra","city 10, new"
정규식을 사용하여 마지막 열을 제거하는 Perl 명령을 찾았지만 이것이 충분한지 또는 내 상황에 맞게 조정하는 방법을 모르겠습니다(다른 제안은 매우 환영합니다!).
perl -pe 's/.*\K,.*//'
Perl을 사용하여 2,3, 6-8열만 제거하고 중복 행을 제거하는 것이 가능합니까?
추신: 중복 행을 포함하도록 input.csv 파일을 업데이트했습니다.
감사합니다!
답변1
가장 간단한 방법은밀러일명 mlr
, CSV, json 및 기타 입력 또는 출력 형식의 데이터 작업을 위한 훌륭한 도구입니다. 예를 들어:
$ mlr --csv --implicit-csv-header --headerless-csv-output \
cut -x -f 2,3,6,7,8 \
then uniq -a input.csv
Col1,Col4,Col5,Col9,Col10
info 1,info 4,5,9,info 10
address 1,4,5,9,address 10
city 1,4,5,9,city 10
--implicit-csv-header
및 옵션을 함께 사용하면 --headerless-csv-output
헤더 행이 효과적으로 무시되고(즉, 다른 데이터 행과 동일하게 만들어짐) 이름이 아닌 숫자로 잘라낼 필드를 지정할 수 있습니다.
누락된 필드에 일부 정크 데이터를 추가하려면 샘플 input.csv 파일을 편집해야 했습니다. mlr
그렇지 않으면 불평할 것입니다. 또한 중복 제거가 작동하는지 테스트하기 위해 중복 입력 행을 추가했습니다.
$ cat input.csv
Col1,Col2,Col3,Col4,Col5,Col6,Col7,Col8,Col9,Col10
info 1,info 2,info 3,info 4,5,6,7,8,9,info 10
info 1,info 2,info 3,info 4,5,6,7,8,9,info 10
address 1,address 2,3,4,5,6,7,8,9,address 10
city 1, city 2,3,4,5,6,7,8,9,city 10
Perl로 하고 싶다면:
- 간단한 쉼표로 구분된 입력만 처리해야 하는 경우:
$ perl -F, -lane '
next if $seen{$_}++;
splice @F,5,3;
splice @F,1,2;
print join ",", @F' input.csv
Col1,Col4,Col5,Col9,Col10
info 1,info 4,5,9,info 10
address 1,4,5,9,address 10
city 1,4,5,9,city 10
이는 Perl의 -a
옵션을 사용하여 각 입력 행을 이라는 배열로 자동 분할합니다 @F
. 이 -F
옵션은 사용할 구분 기호를 알려줍니다.
참고 1: Perl 배열은 1이 아닌 0부터 시작합니다. 따라서 배열 요소 5는 열 6입니다. splice @$row, 5, 3
배열에서 요소 5(즉, 열 6, 7, 8)부터 시작하여 세 개의 요소를 삭제합니다. perldoc -f splice
자세히보다.
참고 2: 여기서는 역순으로 열을 제거합니다(즉, 번호가 높은 열앞으로낮은 숫자). 그렇지 않고 열 5, 6, 7을 삭제하기 전에 열 2와 3을 삭제하면 첫 번째 삭제로 인해 해당 열의 번호가 다시 매겨집니다(3, 4, 5로).
- 사용텍스트::CSV유효한 CSV(쉼표가 포함된 여러 줄로 묶인 따옴표 열 등 포함)를 처리합니다.
$ perl -MText::CSV -e '
my $csv = Text::CSV->new();
while (my $row = $csv->getline(*ARGV)) {
next if $seen{join ",", @$row}++;
splice @$row, 5, 3;
splice @$row, 1, 2;
$csv->say(*STDOUT, $row);
}' input.csv
Col1,Col4,Col5,Col9,Col10
"info 1","info 4",5,9,"info 10"
"address 1",4,5,9,"address 10"
"city 1",4,5,9,"city 10"
여기서 주목할 만한 네 가지 사항은 다음과 같습니다.
Text::CSV
핵심 Perl 모듈이 아니므로 설치가 필요합니다. 전부는 아니지만 대부분의 Linux 배포판에서 작동합니다. 예를 들어 Debian에서는sudo apt-get install libtext-csv-perl
. 그렇지 않은 경우에는cpan
Perl과 함께 제공되는 명령을 사용하여 설치할 수 있습니다 .Text::CSV의 메서드
getline()
(위에 표시$row = $csv->getline(*ARGV)
)는 배열 또는 arrayref에 대한 참조를 반환합니다. 이는 전체 배열을 가리키는 스칼라 값입니다( 자세한 내용을 확인man perlref
하고man perldata
알아보세요).$row
위의 코드에는 arrayref가 포함되어 있습니다. $row 사용/조작은 참조하는 데이터가 아닌 참조 자체에 적용됩니다. 따라서 예를 들어$row2 = $row
데이터가 아닌 참조가 복사됩니다. 두 참조 모두 동일한 데이터를 가리킵니다.@$row
arrayref를 배열로 "역참조"하여 다른 배열처럼 사용할 수 있습니다.*ARGV
in은 명령줄에 제공된 모든 파일 이름 인수에서 입력을 읽는 특수 파일 핸들입니다getline(*ARGV)
(이러한 인수는 Perl에서 @ARGV라는 배열에 저장됩니다). 파일 이름이 아닌 인수(예: 스크립트에 옵션을 처리하는 코드가 있는 경우 옵션)는 처리되어 @ARGV에서 제거된 것으로 가정됩니다. 존재하지 않거나 열 수 없는 파일 이름(예: 권한으로 인해)은 오류 메시지를 생성합니다. 즉, 사용자가 지정한 하나 이상의 파일 이름을 읽습니다. 인수는-
표준 입력으로 처리되므로 파일, 표준 입력 또는 둘 다에서 입력을 읽을 수 있습니다.
이것은 Text::CSV의 기능과 사용 방법에 대한 매우 간단하고 원시적인 예입니다. 자세한 내용과 예제를 보려면 매뉴얼 페이지를 읽어보세요.
위의 출력 예에서 볼 수 있듯이 기본적으로 Text::CSV는 공백이 포함된 텍스트 필드를 인용합니다. 이를 원하지 않으면 속성을 quote_space
0으로 설정하거나 new
다음을 사용하여 $csv 개체를 생성하여 재정의할 수 있습니다.
my $csv = Text::CSV->new({ quote_space => 0 });
또는 그 이후:
my $csv = Text::CSV->new();
$csv->quote_space(0);
그러면 출력은 다음과 같습니다.
Col1,Col4,Col5,Col9,Col10
info 1,info 4,5,9,info 10
address 1,4,5,9,address 10
city 1,4,5,9,city 10
답변2
배열로 변환하고, 생각해 보고, csv로 다시 생성하세요.
perl -pe '@c = split(","); splice(@c, 1, 2); splice(@c, 3, 3); $_ = join(", ", @c)
귀하의 필드가 참조된 경우 다음을 사용할 수 있습니다 Text::CSV
.
$ cat in.csv
Col1,Col2,Col3,Col4,Col5
one,two,three,four,five
six,"se,ven","ei,ght",nine,ten
$ perl -MText::CSV -e 'Text::CSV::csv( in => "in.csv", headers => false, on_in => sub { splice( @{@_[1]}, 1, 2) } )'
Col1,Col4,Col5
one,four,five
six,nine,ten
Perl에 대해 질문했지만 인식을 높이기 위해 캡처 도구도 고려하십시오.
cut -f '1,4,5,9,10' -d ,