私は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
答え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,