두 개의 다른 csv 파일이 있습니다. 하나는 확장된 열 이름을 포함하고 다른 하나는 동일한 열 이름에 대한 바로 가기를 포함합니다.
예를 들어:
csv 파일 1은 다음과 같습니다.
gender,aciclovir drug,aclidinium bromide abc,acenocoumarol drdd
male,2008,2009,2009
csv 파일 2는 다음과 같습니다.
gender,aciclovir,aclidinium bromide,ajmaline
male,2008,2009,2010
이제 파일 2의 열과 공통 단어가 있는 파일 1의 열을 추출하려고 합니다.
내 예에 원하는 출력을 넣으려면 다음을 수행하십시오.
gender,aciclovir drug,aclidinium bromide abc
male,2008,2009
답변1
두 파일의 헤더가 특별한 CSV 참조가 없는 쉼표로 구분된 필드 이름의 간단한 목록이라고 가정하면 다음 명령을 사용하여 파일의 다른 줄에서 필드 이름을 추출할 수 있습니다.
head -n 1 file | tr , '\n'
또는 sed
,
sed -e 'y/,/\n/' -e q file
또한 모든 필드 이름에 정규식에 있는 특수 문자( .
, [
, *
, \
, ^
(필드 이름 시작 부분) 및 $
(필드 이름 끝 부분))가 포함되어 있지 않다고 가정하면 이를 사용하여 집합을 만들 수 있습니다. Will 내의 정규식은 file2
필드 이름의 시작 부분과 일치합니다 file1
( ^
각 줄의 시작 부분에 삽입하면 이렇게 됩니다).
head -n 1 file2 | tr , '\n' | sed 's/^/^/'
또는 sed
,
sed -e 'y/,/\n/' -e q file2 | sed 's/^/^/'
아니면 sed
전화 한통으로
sed -e 'y/,/\n/' -e 's/^/^/' -e 's/\n/&^/g' -e q file2
또는 GNU를 사용하여 sed
,
sed -e 's/^/^/' -e 's/,/\n^/g' -e q file2
필드 이름 목록에 이러한 표현식을 적용하여 file1
이 파일에서 추출해야 하는 필드 이름을 얻을 수 있습니다.
grep -f <( head -n 1 file2 | tr , '\n' | sed 's/^/^/' ) <( head -n 1 file1 | tr , '\n' )
질문에 표시된 데이터를 고려하면 결과는 다음 목록이 됩니다.
gender
aciclovir drug
aclidinium bromide abc
file2
의 필드 이름이 의 필드 이름 두 개 이상과 일치하는 경우 이 목록에 중복된 항목이 포함될 수 있습니다 file1
.
그런 다음 이러한 필드 이름의 쉼표로 구분된 목록을 만들고 이를 cut
하위 명령에 대한 인수 로 사용할 수 있습니다.밀러마지막으로 필요한 필드를 추출합니다 file1
.
mlr --csv cut -f "$( grep -f <( head -n 1 file2 | tr , '\n' | sed 's/^/^/' ) <( head -n 1 file1 | tr , '\n' ) | tr '\n' , )" file1
이것은 우리에게 줄 것이다
gender,aciclovir drug,aclidinium bromide abc
male,2008,2009
답변2
사용행복하다(이전 Perl_6)
raku -MText::CSV -e ' \
#read headers of each csv, match column names on first word;
my $csvA = Text::CSV.new; my $csvB = Text::CSV.new;
my $fhA = "csv1.csv".IO.open; my $fhB = "csv2.csv".IO.open;
my @hdrA = $csvA.header($fhA).column-names; my @hdrB = $csvB.header($fhB).column-names;
my %fld = @hdrA.map(*.words[0]) (&) @hdrB.map(*.words[0]);
close $fhA; close $fhB;
#read full csv file into @whole array;
my $fhA_redux = "csv1.csv".IO.open;
my @whole; my $csv = Text::CSV.new;
while $csv.getline($fhA_redux) -> $row {
@whole.push: $row;
}; close $fhA_redux;
#output array that has been @whole>>.[index] filtered for desired columns;
.join(",").put for @whole>>.[@hdrA.map(*.words[0]).grep(/@(%fld.keys)/, :k)];'
Raku는 Perl 프로그래밍 언어 계열의 언어입니다. 유니코드와 강력한 정규식 구현에 대한 고급 지원을 제공합니다.
위의 외부 모듈은 Text::CSV
CSV를 구문 분석하는 데 사용됩니다. 파일 핸들은 Text::CSV.new()
객체처럼 정의됩니다. 파일 핸들( )의 첫 번째 라인이 구문 분석되어 로 저장되도록 이 $csvA
객체 에 대해 작동합니다 . 마찬가지로 파일 핸들( )의 첫 번째 라인이 구문 분석되어 로 저장되도록 이 객체를 조작합니다 .header
$fhA
column-names
@hdrA
$csvB
header
$fhB
column-names
@hdrB
"교차점"을 얻기 위해 @
각 서명 헤더 배열은 ASCII "set-intersection" 연산자를 사용하여 다른 배열과 비교됩니다 (&)
. 여기서 유니코드 기호를 선호하는 경우 이를 사용할 수 있습니다 ∩
. 교차점은 %fld
해시로 저장됩니다.
비교(교차) 행에서 각 배열 요소를 로 분할한 words
다음 [0]
정확한 일치를 얻는 대신 각 열의 첫 번째 단어가 일치하는지 테스트하여 일치 기준을 변경할 수 있습니다. 결과는 일치하는 세 개의 열입니다.
입력 예:
#csv1.csv
gender,aciclovir drug,aclidinium bromide abc,acenocoumarol drdd
male,2008,2009,2009
#csv2.csv
gender,aciclovir,aclidinium bromide,ajmaline
male,2008,2009,2010
출력 예(인용되지 않음):
gender,aciclovir drug,aclidinium bromide abc
male,2008,2009
출력 예(큰따옴표, >>.raku
위 코드의 마지막 줄 맨 끝에 추가됨):
"gender","aciclovir drug","aclidinium bromide abc"
"male","2008","2009"
출력이 필요한 경우 csv
다음 마크다운 문서가 이를 나타냅니다.
# and write CSV file, filtered as above
my $fh_out = open "new.csv", :w;
$csv.say($fh_out, $_) for @whole>>.[@hdrA.map(*.words[0]).grep(/@(%fld.keys)/, :k)];
$fh_out.close;
https://github.com/Tux/CSV/blob/master/doc/Text-CSV.md
https://docs.raku.org
https://raku.org