CSV에서 필드를 분할하고 해당 행의 필드를 새 행에 복사하는 방법

CSV에서 필드를 분할하고 해당 행의 필드를 새 행에 복사하는 방법

CSV 파일을 사용하는 대상이 있고 6번째 필드에 단어가 포함되어 있지만 최대 문자 길이는 16자입니다. 필드가 16자를 초과하는 경우 줄을 복사하여 단어를 끊지 않고 분리하고 싶습니다.

현재 파일

"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK LMNOP Q RS TUV W XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"

원하는 출력

"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5","LMNOP Q RS TUV W"
"1","2","3","4","5","XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"

답변1

GNU Awk( gawk) 를 사용하여 실행fold행/변수/코프로세스 가져오기

gawk -F, '
  BEGIN{
    OFS=FS; 
    cmd="fold -sw 16";
  }

  # if total length (16 + 2 for quotes) is within limit, print as-is
  length($NF) <= 18 {print; next}

  # else
  {
    # trim the quotes, then fold
    print substr($NF,2,length($NF)-2) |& cmd; 
    close(cmd,"to"); 
    NF--; 
    while((cmd |& getline var) > 0){

      # (optional) trim trailing whitespace
      sub(/[ \t]+$/,"",var);

      print $0, "\"" var "\"" ;
    }
    close(cmd,"from");
  }
' file.csv

작업에서 sub후행 공백을 제거합니다 fold.

fold -sw17표시된 정확한 출력을 얻으려면 16자를 후행 공백으로 묶어야 합니다 (그런 다음 제거됨). 그러나 그렇게 하면 접힌 출력의 마지막 줄이 16자 제한을 초과할 수 있습니다.

답변2

나는 큰따옴표를 유지하는 꽤 형편없는 awk 스크립트를 만들었습니다. 여기 온다:

{
    for ( i=0; i<= length($6); i+=16 )
    {
        if ( i+17 < length($6) )
        {
            if ( i == 0 )
                printf ("%s,%s,%s,%s,%s,%s\"\n", $1, $2, $3, $4, $5, substr($6,i,16))
            else
                printf ("%s,%s,%s,%s,%s,\"%s\"\n", $1, $2, $3, $4, $5, substr($6,i+1,16))
        }
        else
        {
            if ( i == 0 )
                printf ("%s,%s,%s,%s,%s,%s\n", $1, $2, $3, $4, $5, substr($6,i,16))
            else
                printf ("%s,%s,%s,%s,%s,\"%s\n", $1, $2, $3, $4, $5, substr($6,i+1,16))
        }
    }
}

출력은 다음과 같습니다

$ awk -F, -f awks csvfields
"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5"," LMNOP Q RS TUV "
"1","2","3","4","5","W XYZ 12 3456 78"
"1","2","3","4","5","90"
"9","8","7","6","5","LMN O PQ R"
$

유일한 문제는 제거된 예와는 달리 경계에 공백이 있으면 그대로 유지된다는 점입니다.

답변3

아래 코드를 사용해 보세요. 잘 작동합니다.

 k=16;for ((j=1;j<=50;j++)); do  awk -v j="$j" -v k="$k" -F "," '{if(length($NF) > 16){print $1,$2,$3,$4,$5,substr($NF,j,k)}else {print $0}}' filename; j=$(($j+16)); done|sort | uniq

산출

"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5","LMNOP Q RS TUV W"
"1","2","3","4","5","XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"

답변4

SHELL 메서드만 해당(Bash 및 Ksh93에서 테스트됨). 하지만 나는 이 접근 방식이 마음에 든다 fold. 기존 도구를 사용하기 때문이다.

# read from stdin, output to stdout
# Note no Shebang line at top so it made it easier for to try bash/ksh as interpreters

OIFS="$IFS"
IFS=,
while read f1 f2 f3 f4 f5 f6; do
    f6=${f6#\"}
    f6=${f6%\"}             # strip DQs
    if ((${#f6}<17)); then  # no action
            IFS="$OIFS"
            echo "$f1,$f2,$f3,$f4,$f5,\"$f6\""
            IFS=","
            continue
    else
            IFS="$OIFS"
            while ((${#f6}>17)); do
                    n6=${f6:0:16}
                    f6=${f6#$n6}
                    n6=${n6# }
                    n6=${n6% }
                    echo "$f1,$f2,$f3,$f4,$f5,\"$n6\""
            done
            echo "$f1,$f2,$f3,$f4,$f5,\"${f6# }\""
    fi
    IFS=","
done
IFS="$OIFS"
exit

결과:

"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5","LMNOP Q RS TUV W"
"1","2","3","4","5","XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"

using 또는 유사한 를 사용하지 않고 단어 분할 문제를 해결하려면 fold위에 표시된 주석 처리된 줄을 다음 코드로 바꿔야 합니다. 또한 두 번째 echo명령줄을 다음으로 바꿉니다.

                    c6="$f6"
                    n6=""
                    while (((${#n6}+${#nw})<=16)); do
                            n6=$n6${c6%% *}\
                            n6=${n6# }
                            eval c6=\${c6\#${c6%% *} }
                            nw=${c6%% *}
                    done
                    #n6=${f6:0:16} ### replace by above

교체하고

            echo "$f1,$f2,$f3,$f4,$f5,\"${f6# }\""

그리고

            ((${#f6}>0)) && echo "$f1,$f2,$f3,$f4,$f5,\"${f6# }\""

빈 필드를 피하기 위해 나머지는 6입니다.

다음 테스트 파일을 사용하십시오.

"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK LMNOP Q RS TUV W XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"
"1","2","3","4","5","A BB CCC DDD EEEE FFFFF GGGGGG HHHHHHH"

결과:

"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5","LMNOP Q RS TUV W"
"1","2","3","4","5","XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"
"1","2","3","4","5","A BB CCC DDD"
"1","2","3","4","5","EEEE FFFFF"
"1","2","3","4","5","GGGGGG HHHHHHH"

그러나 기존 도구는 fold사용하기가 훨씬 쉽고 기존의 간단한 도구를 기반으로 하는 UNIX 철학을 따릅니다. 그러나 쉘 프로그래밍을 좋아한다면 위의 내용이 솔루션을 얻는 한 가지 방법입니다. 코드에 대한 설명이 필요한 사람이 있으면 저에게 연락하세요.

관련 정보