Bash:100,000文字以上の文字を10進形式に変換しますか?

Bash:100,000文字以上の文字を10進形式に変換しますか?

私は100,000行以上のテキストを10進形式に変換できる高速でCPU集約的なソリューションを探しています。

# random ascii
string='QPWOEIRUTYALSKDJFHGZMXNCBV,./;[]75498053$#!@*&^%(*'

convert () {
    for ((b=0; b<${#string}; b++ ))
    do
        # convert to dec, append colon character, add to array
        arr+=$(printf '%d,' "'${string:$b:1}");
    done;
    # show array contents
    printf '%s' "${arr[@]::-1}"
}

time convert

上記の方法は短期間の作業に適しており、作業は1秒以内に完了します。

$ ./stackexchange.sh

81,80,87,79,69,73,82,85,84,89,65,76,83,75,68,74,70,72,71,90,77,88,78,67,66,86,44,46,47,59,91,93,55,53,52,57,56,48,53,51,36,35,33,64,42,38,94,37,40,42
real    0m0.059s
user    0m0.032s
sys     0m0.016s

ただし、これは多くの文字を含むファイルには適したソリューションではありません。以下の機能により、CPU が急増し、デフォルトでタスクを完了できません。まあ、数分後にCtrl + cを押して停止しました。以下は、変数が変更されたのと同じスクリプトですstring

# random ascii
string="$(cat /tmp/100000-characters.txt)"

convert () {
    for ((b=0; b<${#string}; b++ ))
    do
        arr+=$(printf '%d,' "'${string:$b:1}");
    done;
    printf '%s' "${arr[@]::-1}"
}

time convert

私もwhileループを試しました。 100,000文字のファイル変換に成功しましたが、まだ完了するのに長い時間がかかりました。

string="$(cat /tmp/100000-characters.txt)"

convert () {
    # iteracte through each like 
    while read -r -n1 char; do
        arr+=$(printf '%d,' "'$char");
    done <<< "$string"
    
    printf '%s' "${arr[@]::-3}"
}
time convert 

大きなテキストファイルをコロンで区切られた10進値に変換するエレガントでシンプルなソリューションはありますか?

答え1

Perlが救出に来る!

perl -nE 'say join ",", map ord, split //' < file
  • -n入力内容を1行ずつ読み、各行のコードを実行します。
  • 分ける空の正規表現で//入力を単一文字に分割
  • 地図各文字をその文字にマッピング注文する
  • 参加する文字から文字列を作成し、その間にカンマを挿入します。
  • 説明する出力結果

入力を1行ずつ処理したくない場合は、追加の調整が必要な場合があります。

答え2

ほとんどの時間は配列の作成にかかり、最後にコロンを削除するためにこれを行うようです。代わりに、フラグのみを使用して配列全体を構築することを避けてください。それからはるかに速くなります。

#!/bin/bash

string='QPWOEIRUTYALSKDJFHGZMXNCBV,./;[]75498053$#!@*&^%(*'

convert() {
    local first=1
    for ((b=0; b<${#string}; b++ )); do
        (( first )) && first=0 || printf ,
        printf '%d' "'${string:$b:1}"
    done
}

time convert

比較時間です。まず、初期ソリューションには1000文字が含まれています。

real  0m0.454s
user  0m0.439s
sys   0m0.057s

このソリューションの文字数は1,000文字です。

real  0m0.148s
user  0m0.147s
sys   0m0.001s

これは、組み込みコマンドを使用してbashを入力するのと同じくらい高速です。可能であれば、上記のPerlのようにこれを処理するためのより良いツールを購入することをお勧めします。

答え3

hexdumpこれが/の目的ですod

<input hexdump -ve '/1 ",%u"' | tail -c+2

例えば。

メソッドのように、各文字のコードポイント1の値ではなく、各バイトの値を印刷します。 ASCII文字のみを含む例では効果はありません。

Unicodeコードポイントを取得するには、まず入力をUCS4に変換します。比較する:

$ printf %s 'Stéphane' | hexdump -ve '/1 ",%u"' | tail -c+2
83,116,195,169,112,104,97,110,101
$ printf %s 'Stéphane' | iconv -t ucs-4le | hexdump -ve '/4 ",%u"' | tail -c+2
83,116,233,112,104,97,110,101

リトルエンディアンプロセッサ(x86)を持つUTF-8ロケールで、最初の方法がé(U + 00E9)文字のUTF-8エンコーディングの2バイト(195および169)をダンプする方法を確認し、2番目の方法は233(0xe9 )を印刷します。


1bashの組み込み関数printfは通常、シングルバイト文字マッピングを持つロケールのバイト値を印刷するため、その文字セットにコードポイントを提供し、ほとんどのシステムでUnicodeコードになるマルチバイト文字マッピングの場合、ポイントの広い文字値

答え4

文字列が名前付きファイルに保存されていると仮定すると、file次のようになります。Python各文字の序数を評価します。

$ python3 -c 'import sys
with open(sys.argv[1]) as fh: s=fh.read()
print(*[ord(c) for c in s.rstrip("\n")], sep=",")
' ./file
  • ファイルは文字列変数sに格納されます。

  • リストを理解する構成を使用して文字列を文字ごとに繰り返し、組み込み関数を使用して各文字列の序数を評価し、リスト区切り記号ord()としてコンマを使用して印刷される匿名リストに累積します。

あるいは、Linuxユーティリティのgnuバージョンを使用することもできますxargs+grep。これにより、printfの呼び出し回数が最小限に抑えられます。

$ printf '%s\0' "$string"   \
| grep -oz '.'              \
| xargs -r0 printf "'%s\\0" \
| xargs -r0 printf '%d\n'   \
| paste -sd,

関連情報