Shell-Script

Bash:將 100,000 多個字元轉換為十進制格式?

  • August 10, 2020

我正在尋找一種快速且不佔用大量 CPU 資源的解決方案,將 100,000 多行文本轉換為十進制格式。

# 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

以上對短線效果很好,不到一秒就完成了任務:

$ ./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 

是否有優雅/簡單的解決方案將大量文本文件轉換為冒號分隔的十進制值?

Perl 來救援!

perl -nE 'say join ",", map ord, split //' < file
  • -n逐行讀取輸入並執行每一行的程式碼
  • 在空的正則表達式上拆分//將輸入拆分為單個字元
  • map將每個字元映射到其順序
  • join從字元創建一個字元串,在它們之間插入逗號
  • say輸出結果

如果您不想逐行處理輸入,則可能需要進行更多調整。

您的大部分時間都花在建構數組上,而您似乎只是為了在末尾刪除一個冒號。相反,嘗試只使用一個標誌並避免完全建構一個數組,這明顯更快:

#!/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

這個解決方案有 1000 個字元:

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

這與僅使用內置函式在 bash 中的速度差不多。如果可以的話,我敦促您使用更好的工具來處理這個問題,比如上面的 perl。

引用自:https://unix.stackexchange.com/questions/603542