아래와 같은 파일이 있습니다.Test.csv
"pav",12345,"ABCD,EF;xyz23;15rtg",,
"xyz",,"C4DEF;x23yu;rtg",,
수정 후:
cat Test.csv
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
이것삼""로 구분된 하위 문자열을 포함하는 rd 필드는 ;
해당 하위 문자열로 대체되어야 합니다.
답변1
다음이 사용됩니다csvkit
참조 필드에 쉼표가 포함된 CSV 데이터를 직접 구문 분석하면 awk
오류가 발생하기 쉽기 때문입니다.
그러면 올바른 형식의 세 번째 열이 생성됩니다.
csvcut -c 3 file.csv |
sed -r 's/^"|"$//g' |
awk -F';' -vOFS=';' '{ for (i=1; i<=NF; ++i) $i = substr($i, 0, 2) } { printf("\"%s\"\n", $0) }' >tmp-3rd
주어진 입력에 대해 이는 다음을 생성합니다.
"AB;xy;15"
"C4;x2;rt"
csvcut
세 번째 열이 잘립니다.sed
모든 큰따옴표가 줄의 첫 번째나 마지막에 나타나면 데이터에서 제거됩니다.- 프로그램 은 -구분된 필드를
awk
반복하여;
필드당 2자 길이로 줄입니다. 큰따옴표로 데이터를 인쇄합니다. - 출력은 파일에 기록됩니다
tmp-3rd
.
그런 다음 원래 데이터로 다시 조립하십시오(이는 bash
절차적 대체를 수행하는 데 사용할 수 있는 다른 쉘이라고 가정합니다 <(...)
).
paste -d, <( csvcut -c 1,2 file.csv ) tmp-3rd <( csvcut -c 4,5 file.csv ) | csvformat
paste
열은 쉼표로 구분되어 함께 그룹화됩니다.- 첫 번째 프로세스는 원본 파일의 처음 두 열을 대체하고 두 번째 프로세스는 마지막 두 열을 대체합니다. 중간에는 수정된 세 번째 열을 제공합니다.
csvformat
선택적인 단계로 필요에 따라 필드를 참조하거나 역참조하여 데이터를 전달합니다 .
출력은 다음과 같습니다
pav,12345,AB;xy;15,,
xyz,,C4;x2;rt,,
임시 파일의 필요성을 우회합니다.
paste -d, \
<( csvcut -c 1,2 file.csv ) \
<( csvcut -c 3 file.csv | sed -r 's/^"|"$//g' |
awk -F';' -vOFS=';' '{ for (i=1; i<=NF; ++i) $i = substr($i, 0, 2) } { printf("\"%s\"\n", $0) }' ) \
<( csvcut -c 4,5 file.csv ) | csvformat
답변2
그리고perl
;
세 번째 필드에서만 가정
$ perl -pe 's/"\K[^;"]*;[^"]*(?=")/$&=~s|([^;]{2})[^;]+|$1|gr/e' ip.txt
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
"\K
"
관심 문자열 앞과 관심 문자열 뒤에서 일치합니다(?=")
."
그러나"
이는 예측 문자열이므로 캡처 문자열 자체의 일부가 아닙니다.[^;"]*;[^"]*
;
-OR 이 아닌"
문자 뒤에 문자가;
아닌"
문자가 오는 것과 일치합니다.$&=~s|([^;]{2})[^;]+|$1|gr
일치하는 문자열에 대해 또 다른 교체를 수행합니다.e
Modifier를 사용하면 교체 부품에 Perl 코드를 사용할 수 있습니다.
세 번째 필드만 제한
$ cat ip.txt
"pav",12345,"ABCD,EF;xyz23;15rtg",,
"xyz",,"C4DEF;x23yu;rtg",,
"foo;12,23;good",124,253
12,5232,"xyz","ijk;5545;62"
$ perl -pe 's/^("[^"]*",|[^,]*,){2}"\K[^;"]*;[^"]*(?=")/$&=~s|([^;]{2})[^;]+|$1|gr/e' ip.txt
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
"foo;12,23;good",124,253
12,5232,"xyz","ijk;5545;62"
답변3
정확하고 견고함파이썬3.x 솔루션(기반csv.reader목적):
parse_csv.py
스크립트:
import csv, sys
with open(sys.argv[1]) as f:
reader = csv.reader(f)
for l in reader:
l = [s if ';' not in s else ';'.join(_[:2] for _ in s.split(';')) for s in l]
print(','.join(i if not i or i.isnumeric() else '"{}"'.format(i) for i in l))
용법:
python3 parse_csv.py Test.csv
산출:
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
Python의 모듈은 csv
데이터에 대한 강력하고 유연한 지원을 제공합니다.csv
답변4
복잡한 GNUAWK
솔루션( csv
데이터 구문 분석):
awk -v FPAT='"[^"]+"|[^",]+|,,' '{
for (i=1;i<=NF;i++) {
if ($i~/^".*;./) {
len=split($i,a,";"); v=substr(a[1],1,3);
for (j=2;j<=len;j++) v= v";"substr(a[j],1,2);
v=v"\042"
} printf "%s%s",(v? v: ($i~/^,,/? (i==NF? ",":""):$i )),
(i==NF? ORS:OFS); v=""
}
}' OFS=',' Test.csv
FPAT='"[^"]+"|[^",]+|,,'
- 필드 값에 대한 복잡한 정규식 패턴 정의if ($i~/^".*;./) ...
- 현재 필드에 문자가$i
포함되어 있는 경우;
len=split($i,a,";")
- 필드 값을$i
구분 기호로 배열로 분할합니다. 생성된 요소/블록의 개수가 할당됩니다.a
;
len
v=substr(a[1],1,3);
- 선행 문자를 포함하여 필요한 길이의 첫 번째 블록을 캡처합니다"
."AB
에서 추출됩니다"ABCD,EF
for (j=2;j<=len;j++) ...
- 남은 청크/항목을 반복합니다.v=v"\042"
-"
처리된 시퀀스에 후행 큰따옴표를 추가합니다v
.\043
큰따옴표로 묶인 char 을 나타내는 ASCII 8진수 코드입니다"
.($i~/^,,/? (i==NF? ",":""):$i )
- 각각의 빈 필드는 단일 쉼표와 공통 구분 기호를 사용하여,,
다시 생성됩니다 . 이는 불필요한 쉼표 혼란을 피하기 위한 것입니다.,
,
"pav",,,
(i==NF? ORS:OFS)
- 마지막 필드가 발견되면i==NF
- 레코드 구분자를 인쇄하고ORS
, 그렇지 않으면 - 필드 구분자를 인쇄합니다.OFS
산출:
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,