BASH 문자 클래스별로 모든 문자 수 계산

BASH 문자 클래스별로 모든 문자 수 계산

BASH 매뉴얼 페이지에 정의된 대로 문자 CLASS별로 임의 파일의 모든 문자를 효율적으로 계산해야 합니다.

[[:alnum:]], [[:alpha:]], [[:ascii:]], [[:blank:]], [[:cntrl:]], [[:digit:]], [[ :그림:]], [[:하단:]], [[:인쇄:]], [[:punct:]], [[:Space:]], [[:상단:]], [[:Word :]] 및 [[:xdigit:]]

파일을 처리한 후 각 결과의 개수가 0이더라도 한 줄에 표시합니다.

인터넷 검색에서는 유사한 콘텐츠를 찾는 데 실패했습니다.

임의의 파일( /tmp/f1.txt)에는 다양한 텍스트/데이터가 포함됩니다.

나는 ELF 바이너리나 유니코드(또는 모든 형태의 멀티바이트) 콘텐츠를 다루고 싶지 않습니다.

CR줄 수( 및/또는 ) 는 신경 쓰지 않고 LF위 클래스를 통해 누적된 대상 파일의 각 "문자" 수만 신경 씁니다.

function()나는 이것이 결국 더 큰 bash 스크립트 사이의 표준이 되도록 의도하고 있습니다 . bash/sed/awk 등이 필요합니다. Perl/python/ruby는 그다지 필요하지 않습니다.

샘플 데이터 파일은 다음과 같습니다.

  • 0바이트, 즉 콘텐츠가 전혀 없습니다.

  • 단일 문자

  • 단어

  • 여러 단어를 공백으로 구분하세요.

  • 여러 줄에 공백 및/또는 캐리지 리턴 및/또는 줄 바꿈이 포함되어 있습니다.

  • 여러 줄 파일의 경우 마지막 줄의 끝을 나타내는 CR또는 가 없을 수 있습니다 (그러나 모든 문자는 여전히 계산되어야 합니다).LF

답변1

file=myfile
for class in alnum alpha blank cntrl digit graph lower print punct space upper xdigit
do
  printf '%7s: %d\n' "$class" "$(tr -Cd "[:${class}:]" < "$file" | wc -m)"
done

asciiword표준 문자 클래스가 아니며 구체적 입니다 bash. 밑줄이 그어져 word있고 문자 0~127이므로 다음과 같이 할 수 있습니다.alnumascii

printf '%7s: %d\n' word "$(tr -Cd "_[:alnum:]" < "$file" | wc -m)"
printf '%7s: %d\n' ascii "$(LC_ALL=C tr -cd '\0-\177' < "$file" | wc -c)"

(coreutils-8.22부터 GNU 구현은 tr멀티바이트 문자와 함께 작동할 수 없습니다.)

최소한 GNU libc를 사용하는 시스템에서는 다음을 실행할 수도 있습니다.

$ locale ctype-class-names
upper;lower;alpha;digit;xdigit;space;print;graph;blank;cntrl;punct;alnum;combining;combining_level3

해당 로캘에 정의된 문자 클래스 목록을 찾습니다.

답변2

재미있는 수업인 것 같아요! 그것은 무엇입니까?

이렇게 하면 대부분의 경우 sed가 :ascii: 또는 :word:를 지원하지 않는 것 같습니다.

for f in alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit
do
  echo "$f: $(sed s/[^[:$f:]]//g b.txt | tr -d '\n' | wc -c)"
done

우리는 모든 것을 삭제하기 위해 sed를 사용합니다와는 별개로문자에 관심을 갖고 빈 줄을 모두 제거하고 남은 문자 수를 얻습니다.

+/-1 또는 10배 오류를 제외하고 비교적 정확해야 합니다.

답변3

어떤 캐릭터가 어떤 범주에 속하는지는 찾아보지 않겠습니다. 아마도 여러분이 알아낼 수 있거나 다른 답변을 찾아볼 수도 있을 것입니다. 하지만 이렇게 하면 파일 문자를 하나도 잃지 않고 명확하게 표현할 수 있습니다.

 _c2o() { od -A n -t o1 -w1 -v | tr -dc '0-9\n' ; } 
 _c2o <file
 163
 150
 072
 040
 167
 141
 162
 156
 151
 156
 147

저는 이 기능을 다양한 방법으로 사용하고 있습니다. 각 줄은 8진수 형식으로 표시되는 바이트입니다. 물론 od매우 구성 가능합니다. 그러나 이 방법을 사용하면 매우 쉽게 목표 값에 대해 행 카운터를 구현할 수 grep있습니다 sed. 그것은 케이크 조각입니다. 그리고 그것은 매우 빠릅니다.

좋아요, 그래서 저는 수업을 계속했습니다:

_classes() { set -- ${classes=alnum alpha blank cntrl digit graph lower print punct space upper xdigit}
        while ${1+:} false ; do
                printf %b $(printf '\\%04o\n' $(seq 0 127)) |
                tr -dc "[:${1}:]" | {
                        printf "$1='"
                        _c2o
                        printf "'\n"
                } ; shift
        done
}

위의 명령을 실행하면 다음과 같은 출력이 표시됩니다.

xdigit='060
061
062
063
064
065
066
067
070
...
'

거기에서 나는 다음과 같은 것을 상상할 것입니다.

eval "$(_classes)"
for class in $classes ; do
    eval "$class=\$(_c2o <file | grep -c -F "$class")"
done

이 문제를 더 잘 처리해야 하지만 이것이 효과가 있습니다.

관련 정보