Unix 파일에는 따옴표 안에 개행 문자가 포함되어 있습니다.

Unix 파일에는 따옴표 안에 개행 문자가 포함되어 있습니다.

따옴표 안에 따옴표와 개행 문자가 있지만 단일 열에는 없는 이상한 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

관련 정보