BASH文字クラス別にすべての文字数を計算する

BASH文字クラス別にすべての文字数を計算する

BASHのマニュアルページで定義されているように、文字CLASSでランダムファイル内のすべての文字を効率的に計算する必要があります。

[[:alnum:]], [[:alpha:]], [[:ascii:]], [[:blank:]], [[:cntrl:]], [[:digit:]], [[ :図:]]、[[:下部:]]、[[:印刷:]]、[[:punct:]]、[[:Space:]]、[[:上部:]]、[[:Word :]]と[[:xdigit:]]

ファイルを処理した後、各結果の数がゼロであっても1行に表示されます。

インターネット検索では、同様のコンテンツを見つけることができませんでした。

任意のファイル(/tmp/f1.txt)にはさまざまなテキスト/データが含まれます。

私はELFバイナリやUnicode(またはあらゆる形式のマルチバイト)コンテンツを扱いたくありません。

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

この問題をよりよく処理する必要がありますが、これはうまくいきます。

関連情報