많은 데이터 필드(>50)가 포함된 단순화된 CSV(한 줄에 최대 한 줄)가 있는 경우 각 데이터 필드의 최대 문자 길이를 어떻게 계산한 다음 모든 개수를 txt 파일로 내보낼 수 있습니까? 그런데 열 헤더가 포함된 파일의 첫 번째 줄을 무시하고 싶습니다.
예를 들어, 입력이 주어지면
These,are,the,column_headings_which_may_be_very_long_but_they_don't_count
abcdefghij,abcdefghijk,abcdefghijkl,abc
aardvark,bat,cat,dog
ant,bee,cow,abcdefghijklm
최종 결과는 다음과 유사할 수 있습니다. 여기서 첫 번째 열은 원본 파일의 데이터 필드를 나타내고 두 번째 열은 필드의 최대 길이를 나타냅니다.
1 | 10
2 | 11
3 | 12
4 | 13
즉, 열 1의 가장 긴 값은 10( abcdefghij
) 길이이고, 열 2의 가장 긴 값은 11( abcdefghijk
) 길이입니다.
나는 이 사이트에서 몇 가지 조사를 했고 특정 데이터 필드를 지정할 때 매우 간단한 방법으로 최대 길이를 계산하는 여러 가지 방법을 찾았습니다. 예를 들어, 파일에서 두 번째 필드의 최대 길이를 계산하려면 cut 및 wc 명령을 사용하십시오.
cut -d, -f2 test.csv | wc -L
하지만 어떻게 명령을 가져와 모든 데이터 필드에 반복한 다음 출력할 수 있습니까?
답변1
귀하의 질문을 올바르게 이해하면 귀하의 요구 사항이 충족됩니다.
awk -F, 'NR!=1 { if (max_NF < NF) max_NF = NF;
for (i=1; i<=NF; i++) if (max[i] < length($i)) max[i] = length($i) }
END { for (i=1; i<=max_NF; i++) printf "%-2d | %d\n", i, max[i] }'
답변2
샘플 파일에 대한 링크는 표시되지 않지만 awk
명령을 사용하여 이 작업을 수행할 수 있습니다.
보유하고 있는 구분 기호와 계산해야 하는 정확한 필드를 지정할 수 있는 경우.
awk '{ FS = "," } ; { if(NR!=1) gsub(/"/, "", $2) ; print NR "|" length($2) } ' test.csv
이 출력을 원하는 파일로 리디렉션할 수 있습니다.
답변3
사용밀러( mlr
)각 필드 값의 최대 길이를 계산합니다. 입력은 CSV로 읽히고 출력은 "xtab" 파일(파일당 하나의 키+값 쌍)로 생성됩니다.
$ mlr --c2x stats1 -a maxlen --fr . file
These_maxlen 10
are_maxlen 11
the_maxlen 12
column_headings_which_may_be_very_long_but_they_don't_count_maxlen 13
--fr .
이 작업의 인수는 stats1
이름이 정규식과 일치하는 모든 필드 .
(즉, 명명된 각 필드)의 최대 길이를 계산하는 것입니다.
보시다시피 Miller는 필드 이름을 유지하고 _maxlen
각 필드에 접미사를 추가했습니다.
첫 번째 행이 헤더가 아닌 레코드인 것처럼 CSV 파일을 읽으려면 해당 첫 번째 행을 제거하고 동일한 최대 계산을 수행합니다.
$ mlr --c2x -N filter -x 'NR == 1' then stats1 -a maxlen --fr . file
1_maxlen 10
2_maxlen 11
3_maxlen 12
4_maxlen 13
추가 작업을 사용하면 모든 필드 이름에서 접미사를 제거 rename
할 수 있습니다 ._maxlen
$ mlr --c2x -N filter -x 'NR == 1' then stats1 -a maxlen --fr . then rename -r '(.*)_maxlen$,\1' file
1 10
2 11
3 12
4 13
답변4
사용행복하다(이전 Perl_6)
~$ raku -ne 'BEGIN my @a;
unless ++$ == 1 {
@a.push: $_.split(",").map: *.chars;
};
END say( ++$ ~ " | " ~ $_ ) for ([Z] @a).map: *.max;' file
또는:
~$ raku -ne 'BEGIN my @a;
once next;
@a.push: $_.split(",").map: *.chars;
END say( ++$ ~ " | " ~ $_ ) for ([Z] @a).map: *.max;' file
이것은 Perl 프로그래밍 언어 중 하나인 Raku로 작성된 답변입니다. Raku는 유니코드에 대한 고급 지원을 제공하므로 문자 수가 정확합니다.
먼저 ( awk
비슷한) -ne
한 줄씩 비자동 인쇄 명령줄 플래그를 사용합니다.
- 배열은
BEGIN
블록 단위로 선언됩니다. - 헤더 행(첫 번째 답변)을 제거하려면
++$
익명 카운터( )를 사용하여 첫 번째 행을 건너뛰세요. 또는 (두 번째 답변) 다음을once next
사용할 수 있습니다. split
블록/루프 본문 내에서 각 줄은 쉼표로 읽혀지고 각 결과 요소는map
문자 수를 얻기 위해 입력됩니다. 이것들은 배열chars
로 푸시됩니다 .@a
- 모든 라인을 읽고 나면
END
블록이 실행됩니다. 행과 열이 교환되도록 배열이 변환@a
됩니다 .[Z]
이런 일이 발생하면map
각 배열 위치의 요소로 들어가서 익명 카운터를max
사용하여 줄 번호를 제공하여 .finally 출력 데이터를 얻을 수 있습니다(문자열 연결은 물결표를 통해 수행됨).++$
~
입력 예:
These,are,the,column_headings_which_may_be_very_long_but_they_don't_count
abcdefghij,abcdefghijk,abcdefghijkl,abc
aardvark,bat,cat,dog
ant,bee,cow,abcdefghijklm
예제 출력:
1 | 10
2 | 11
3 | 12
4 | 13
참고: 행당 열 수를 확인하는 동안 오류가 발생하지 않습니다. [Z]
변환은 단순히 과도한 수의 행을 공통 행(예: 예에서는 4개 열)으로 자릅니다. 행당 열 수에 관계없이 Raku에서 이 작업을 수행하려면 아래 첫 번째 링크를 참조하세요.
https://unix.stackexchange.com/a/774828/227738
https://docs.raku.org/언어/unicode
https://raku.org