따옴표 안에 따옴표와 개행 문자가 있지만 단일 열에는 없는 이상한 CSV 파일이 있습니다. 이제 열을 "개행"으로 식별하고 개행을 일부 구분 기호로 바꿔야 합니다.
3개의 열이 있는데, 세 번째 열에는 큰따옴표와 각 특수 문자가 포함된 HTML 텍스트가 포함됩니다. 그러나 큰따옴표는 와 같은 큰따옴표로 이스케이프됩니다 "<This ""is"" string>"
.
입력하다:
아이디, 이름, 문자
"1","abc","Line 1"
"2","def","Line2
""line2"",line2"
"3","ghi","line3"
산출:
ID, Name, text
"1","abc","Line 1"
"2","def","Line2 ""line2"",line2"
"3","ghi","line3"
답변1
파일에는 실제 문제가 없습니다. 줄바꿈과 큰따옴표가 포함되어 있습니다. CSV 파서가 이를 올바르게 처리합니다. 이스케이프된 큰따옴표 "
(큰따옴표 필드 동안)를 사용하는 것은 CSV 파일에 포함된 큰따옴표를 이스케이프하는 올바른 방법입니다.
교체임베디드CSV 파일에 @
개행 문자를 포함하려면 다음을 수행하세요.
$ csvformat -M '@' file.csv | tr '\n@' '@\n'
1,abc,Line 1
2,def,"Line2@""line2"",line2"
3,ghi,line3
이것은 csvformat
다음에서 사용됩니다.csvkit 툴킷. 이는 CSV 파일을 다시 포맷할 수 있는 적절한 CSV 파서입니다.
위의 명령 파이프라인은 먼저 모든 줄 바꿈을 대체합니다.아니요역할을 포함합니다 @
. 그런 다음 tr
남은 개행 문자와 @
문자를 교체하여 개행 문자가 포함된 CSV 파일로 마무리했습니다 @
.
이는 파일의 원본 데이터에 문자가 포함되어 있지 않다는 사실에 의존합니다 @
.
개행 문자가 원래 있었던 위치 대신 공백이 있는 토큰을 원할 경우 위에 표시된 tr '\n@' ' \n'
토큰을 대신 사용하세요.tr
$ csvformat -M '@' file.csv | tr '\n@' ' \n'
1,abc,Line 1
2,def,"Line2 ""line2"",line2"
3,ghi,line3
이렇게 하면 원래 개행 문자를 다시 삽입하는 것이 불가능하지는 않더라도 매우 어려워집니다.다른데이터의 공백(예: 첫 번째 행의 세 번째 필드에 있는 공백)
csvformat
불필요한 큰따옴표를 모두 제거하지 않고 다음과 함께 사용 하시겠습니까 -U 1
?
$ csvformat -U 1 -M '@' file.csv | tr '\n@' ' \n'
"1","abc","Line 1"
"2","def","Line2 ""line2"",line2"
"3","ghi","line3"
Miller를 사용하여 더 간단한 답변 얻기(2022년 10월):
$ cat file
ID,Name,text
"1","abc","Line 1"
"2","def","Line2
""line2"",line2"
"3","ghi","line3"
$ mlr --csv put '$text = gsub($text,"\n"," ")' file
ID,Name,text
1,abc,Line 1
2,def,"Line2 ""line2"",line2"
3,ghi,line3
그러면 CSV 파일(일반 헤더로 가정)을 읽고 gsub()
필드의 줄 바꿈을 공백으로 바꿉니다.text
답변2
sed를 사용해 볼 수 있습니다.
sed '
:A
2,$ {
/[^"]\"$/! {
N
bA
}
s/\n//g
}
' infile
마지막 문자가 "이면 2부터 끝까지 모든 줄을 캡처합니다.
그렇지 않으면 개행 문자를 가져와 루프를 다시 시작합니다.
루프 끝에서 각 "\n"을 제거합니다.
답변3
sed
다음과 같이 확장된 정규식 지원을 활용하여 GNU 버전을 사용하여 이 작업을 수행할 수 있습니다 .
명령줄:
$ sed -Ee '
1b
/^("[^"]*"[^"]*)*$/!{
N;s/\n/ /;s/^/\n/;D
}
' input.csv
결과:
ID,Name,Text
"1","abc","Line 1"
"2","def","Line2 ""line2"",line2"
"3","ghi","line3"
설명하다:
-E
확장 정규식 모드를 켭니다.1b
헤더는 변경되지 않고 표준 출력으로 전송됩니다./^("[^"]*"[^"]*)*$/
큰따옴표로 완전히 균형 잡힌 행을 일치시킵니다.- 따라서 이를 부정하면 불균형 행, IOW가 발생하고 후속 행에서 닫는 큰따옴표를 찾아야 합니다.
- 다음 줄을 읽고 이를 패턴 공간에 추가하고
N
개행을 제거합니다. - 패턴 공간이 균형을 이룰 때까지 이 과정을 반복합니다.
POSIX
sed
위의 내용을 일부 변경해야 합니다.
$ sed -e '
1b
/^\("[^"]*"[^"]*\)*$/b
N;s/\n/ /;H;s/.*//;x;D
' input.csv
답변4
Raku(이전 Perl_6) 사용
raku -MText::CSV -e 'my $csv=Text::CSV.new; .perl.put for $csv.getline_all(open($*ARGFILES, :r, :!chomp));'
입력 예:
ID, Name, text
"1","abc","Line 1"
"2","def","Line2
""line2"",line2"
"3","ghi","line3"
예제 출력:
$["ID", "Name", "text"]
$["1", "abc", "Line 1"]
$["2", "def", "Line2\n\"line2\",line2"]
$["3", "ghi", "line3"]
Raku 프로그래밍 언어와 특수 모듈(예: Text::CSV
)을 사용하여 따옴표와 포함된 줄 바꿈을 처리할 수 있습니다. 시각화를 위해 \n
호출된 역할을 추가했습니다 .perl
(참고용으로 .raku
도 괜찮습니다). 포함된 줄 바꿈을 밑줄로 변경하려면 필드에 매핑을 추가하세요(아래에 첨부된 코드).
raku -MText::CSV -e 'my $csv=Text::CSV.new; .put for $csv.getline_all(open($*ARGFILES, :r, :!chomp)).map(*.subst("\n","_", :g));'
출력 업데이트(1):
ID Name text
1 abc Line 1
2 def Line2_"line2",line2
3 ghi line3
"큰" 큰 따옴표가 필요한지 여부는 OP의 원래 게시에서 실제로 불분명합니다. .perl
위의 코드에 콜백을 추가하면 이스케이프된 큰따옴표(아래)가 제공되는데, 이는 더 이상적일 수 있습니다.
출력 업데이트(2):
"ID Name text"
"1 abc Line 1"
"2 def Line2_\"line2\",line2"
"3 ghi line3"
https://modules.raku.org/dist/Text::CSV:cpan:HMBRAND
https://github.com/Tux/CSV
https://raku.org