내용은 다음과 같습니다 test.txt
. 일반적으로 22개 열입니다.
BusinessDate,SourceSystemId,IceIndexId,IceIndexName,ComponentId,ComponentReferenceType,ComponentType,ComponentName,ComponentIssuerCIS,ComponentIssuerName,ComponentWeighting,IceCurveID,IceCurveName,RiskyCurveCIS,OriginalWeighting,DerivedWeighting,indexType,cafName,indexStartDate,indexCurrency,componentCurrency
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,20173QAG6,CUSIP,BOND,GCCFC 2007-GG9 A-M,FCMT7US,COML MORT TST 2007-GG9,0.04,19063270,risky_20173QAG6_FCMT7US.usd,FCMT7US,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,61753JAF6,CUSIP,BOND,MSC 2007-IQ13 AM,Z01IYUS,MORGAN STNLY CAP I TST 2007-IQ13,0.04,19059680,risky_61753JAF6_Z01IYUS.usd,Z01IYUS,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,12345400,risky_itraxx_europe32_14.eur,XSNOREFOB258,ISIN,BOND,NOREFOB_BANCO_SANTANDER_SA,BBDERES,BANCO SANTANDER SA, MADRID HO,0.008,20286090,risky_bank_bsch_14.eur,BBDERES,0.008,0.008,indexCds,index_risky_itraxx_europe32_14.eur,2019-09-18,EUR,EUR
문제 기록인 열이 22개 이상인 행을 찾아서 쉼표로 바꾸고 싶습니다.
bcz BANCO SANTANDER SA, MADRID HO
는 키워드이므로 쉼표로 구분하면 안 됩니다. 쉼표 없이 사용해야 합니다 BANCO SANTANDER SA MADRID HO
.
답변1
어떤 입력 행에 21개 이상의 필드가 있는지 감지하는 것은 매우 쉽습니다. 예를 들어
awk -F, 'NF>21' input.txt
그것을 고치는 것은 그리 쉬운 일이 아닙니다. 스크립트에서는 어떤 필드가 false인지(또는 반대로 어떤 필드에 쉼표가 포함되어서는 안 되는지) 알 수 있는 쉬운 방법이 없기 때문에 이러한 줄을 수동으로 편집해야 합니다(예: vi
또는 또는 선호하는 편집기 사용).nano
이는 단순한(또는 복잡한) 검색 및 대체 휴리스틱이 아닌 실제 지능이 필요한 작업입니다. 또한 데이터 세트에 대한 실질적인 지식이 필요합니다.
그렇기 때문에 사실이다CSV파일에는 따옴표 안에 문자열 필드가 포함되어 있으며 실제 CSV 파서가 따옴표 붙은 문자열 필드를 이해하는 이유도 있습니다.
따옴표로 묶인 문자열 필드가 있는 실제 CSV를 생성하기 위해 쉼표로 구분된 파일에서 무엇이든 얻을 수 있는 경우 처리는 다음과 같습니다.많은더 쉬워졌습니다. 이것이 이 문제에 대한 진정한 해결책입니다. 문제의 근원을 해결하는 것입니다.
다른 답변에서는 최소한 수행해야 할 작업 중 일부는 공백으로 시작하는 필드를 이전 필드와 병합하는 것이라고 지적합니다.
이렇게 하려면 입력을 올바른 형식의 CSV로 변환해야 합니다. 예를 들어:
$ perl -e '
use Text::CSV qw(csv);
$csv = Text::CSV->new();
while($row = $csv->getline(ARGV)) {
# merge fields beginning with whitespace with the previous field.
for ($i=1; $i <= @$row; $i++) {
if ($row->[$i] =~ m/^\s/) {
$row->[$i-1] .= "," . $row->[$i];
$row->[$i] = undef;
};
};
# delete any undef-ed fields
@$row = grep{defined $_} @$row;
$csv->say(STDOUT, $row);
};
' input.txt
노트:
이
$csv->getline()
명령은 CSV 데이터의 전체 행을 가져옵니다. 이는 모두 한 줄에 있거나 여러 줄의 인용 문자열로 인해 여러 줄에 걸쳐 분산되어 있습니다.이는 현재 입력 파일과 특별히 관련이 없지만(CSV가 아니기 때문에 CSV 파일과 약간 비슷해 보임) 실제 CSV 파일로 작업할 때 유용합니다.
예제 출력:
BusinessDate,SourceSystemId,IceIndexId,IceIndexName,ComponentId,ComponentReferenceType,ComponentType,ComponentName,ComponentIssuerCIS,ComponentIssuerName,ComponentWeighting,IceCurveID,IceCurveName,RiskyCurveCIS,OriginalWeighting,DerivedWeighting,indexType,cafName,indexStartDate,indexCurrency,componentCurrency
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,20173QAG6,CUSIP,BOND,"GCCFC 2007-GG9 A-M",FCMT7US,"COML MORT TST 2007-GG9",0.04,19063270,risky_20173QAG6_FCMT7US.usd,FCMT7US,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,61753JAF6,CUSIP,BOND,"MSC 2007-IQ13 AM",Z01IYUS,"MORGAN STNLY CAP I TST 2007-IQ13",0.04,19059680,risky_61753JAF6_Z01IYUS.usd,Z01IYUS,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,12345400,risky_itraxx_europe32_14.eur,XSNOREFOB258,ISIN,BOND,NOREFOB_BANCO_SANTANDER_SA,BBDERES,"BANCO SANTANDER SA, MADRID HO",0.008,20286090,risky_bank_bsch_14.eur,BBDERES,0.008,0.008,indexCds,index_risky_itraxx_europe32_14.eur,2019-09-18,EUR,EUR
이렇게 하면 네 번째 행에 있는 두 개의 문제 필드가 다음으로 병합되었습니다."BANCO SANTANDER SA, MADRID HO"
알아채다모두공백이 포함된 필드(및 기타 잠재적으로 문제가 있는 문자)도 큰따옴표로 묶습니다. 즉, 출력은 이제 올바른 형식의 CSV입니다.
이는 우리가 알고 있는 한 가지 문제만 해결합니다. 우리(즉, 당신)가 아직 모르는 다른 것들이 있을 수도 있습니다. 예를 들어 추가 쉼표가 있을 수 있지만 바로 뒤에 오는 공백은 없을 수 있습니다.
이 스크립트(알고리즘의 변형을 구현하는 다른 답변과 마찬가지로)는나머지필드는 공백 문자가 있는 입력 줄로 시작해야 합니다. 예제 입력에는 아무것도 없지만 헤더 1개와 데이터 행 3개로 구성된 샘플 크기를 가정하는 것은 안전하지 않습니다.
이것진짜해결 방법은 앞에서 언급한 대로 남아 있습니다.소스에서 문제를 해결하세요.손상된 쓰레기 대신 올바른 형식의 CSV를 출력하도록 합니다.
올바르게 인용된 CSV를 생성하기 위해 이 출력을 생성하는 프로그램을 얻을 수 없는 경우 다른 옵션은 열 구분 기호를 사용하는 것입니다.데이터에 없음. 파이프 문자 |
, 세미콜론 ;
또는 탭 문자( 0x09
, Ctrl-I
, \t
)는 일반적으로 구분 기호로 적합합니다.
답변2
실제로 원하는 것은 공백으로 시작하는 모든 필드를 이전 필드 끝까지 결합하는 것입니다.
$ awk -F, '{print NF}' file
21
21
21
22
$ cat tst.awk
BEGIN { FS=OFS="," }
{
rec = $1
for (i=2; i<=NF; i++) {
rec = rec ( $i ~ /^[[:space:]]/ ? "" : OFS) $i
}
print rec
}
$ awk -f tst.awk file
BusinessDate,SourceSystemId,IceIndexId,IceIndexName,ComponentId,ComponentReferenceType,ComponentType,ComponentName,ComponentIssuerCIS,ComponentIssuerName,ComponentWeighting,IceCurveID,IceCurveName,RiskyCurveCIS,OriginalWeighting,DerivedWeighting,indexType,cafName,indexStartDate,indexCurrency,componentCurrency
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,20173QAG6,CUSIP,BOND,GCCFC 2007-GG9 A-M,FCMT7US,COML MORT TST 2007-GG9,0.04,19063270,risky_20173QAG6_FCMT7US.usd,FCMT7US,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,61753JAF6,CUSIP,BOND,MSC 2007-IQ13 AM,Z01IYUS,MORGAN STNLY CAP I TST 2007-IQ13,0.04,19059680,risky_61753JAF6_Z01IYUS.usd,Z01IYUS,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,12345400,risky_itraxx_europe32_14.eur,XSNOREFOB258,ISIN,BOND,NOREFOB_BANCO_SANTANDER_SA,BBDERES,BANCO SANTANDER SA MADRID HO,0.008,20286090,risky_bank_bsch_14.eur,BBDERES,0.008,0.008,indexCds,index_risky_itraxx_europe32_14.eur,2019-09-18,EUR,EUR
$ awk -f tst.awk file | awk -F, '{print NF}'
21
21
21
21
답변3
목표가 공백으로 시작하는 필드를 가로채는 것이라면 sed 및 Miller(https://github.com/johnkerl/miller) 예
sed -r 's/, /|/g' input.csv | mlr --csv put -S 'for (k in $*) {$[k] = gsub($[k], "[|]", ", ");}'
당신은 할 것
BusinessDate,SourceSystemId,IceIndexId,IceIndexName,ComponentId,ComponentReferenceType,ComponentType,ComponentName,ComponentIssuerCIS,ComponentIssuerName,ComponentWeighting,IceCurveID,IceCurveName,RiskyCurveCIS,OriginalWeighting,DerivedWeighting,indexType,cafName,indexStartDate,indexCurrency,componentCurrency
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,20173QAG6,CUSIP,BOND,GCCFC 2007-GG9 A-M,FCMT7US,COML MORT TST 2007-GG9,0.04,19063270,risky_20173QAG6_FCMT7US.usd,FCMT7US,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,61753JAF6,CUSIP,BOND,MSC 2007-IQ13 AM,Z01IYUS,MORGAN STNLY CAP I TST 2007-IQ13,0.04,19059680,risky_61753JAF6_Z01IYUS.usd,Z01IYUS,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,12345400,risky_itraxx_europe32_14.eur,XSNOREFOB258,ISIN,BOND,NOREFOB_BANCO_SANTANDER_SA,BBDERES,"BANCO SANTANDER SA, MADRID HO",0.008,20286090,risky_bank_bsch_14.eur,BBDERES,0.008,0.008,indexCds,index_risky_itraxx_europe32_14.eur,2019-09-18,EUR,EUR
답변4
이 시도,
awk -F ',' '{a=$1;for (i=2;i<=10;i++) a=a","$i ;
for (i=11;i<=(NF-11);i++) a=a$i;
for (i=(NF-10);i<=NF;i++) a=a","$i;
print a}' input.csv
BusinessDate,SourceSystemId,IceIndexId,IceIndexName,ComponentId,ComponentReferenceType,ComponentType,ComponentName,ComponentIssuerCIS,ComponentIssuerName,ComponentWeighting,IceCurveID,IceCurveName,RiskyCurveCIS,OriginalWeighting,DerivedWeighting,indexType,cafName,indexStartDate,indexCurrency,componentCurrency
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,20173QAG6,CUSIP,BOND,GCCFC 2007-GG9 A-M,FCMT7US,COML MORT TST 2007-GG9,0.04,19063270,risky_20173QAG6_FCMT7US.usd,FCMT7US,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,61753JAF6,CUSIP,BOND,MSC 2007-IQ13 AM,Z01IYUS,MORGAN STNLY CAP I TST 2007-IQ13,0.04,19059680,risky_61753JAF6_Z01IYUS.usd,Z01IYUS,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,12345400,risky_itraxx_europe32_14.eur,XSNOREFOB258,ISIN,BOND,NOREFOB_BANCO_SANTANDER_SA,BBDERES,BANCO SANTANDER SA MADRID HO,0.008,20286090,risky_bank_bsch_14.eur,BBDERES,0.008,0.008,indexCds,index_risky_itraxx_europe32_14.eur,2019-09-18,EUR,EUR
위 코드는 열 11을 열 NF-11에 결합합니다...