Преобразование всех числовых сокращений в числовые значения в текстовом файле

Я хотел бы преобразовать все числовые сокращения, такие как 1K, 100K, 1M и т. Д. В текстовом файле, в простые числовые значения, такие как 1000, 100000, 1000000 и т. Д.

Так, например, если у меня есть следующий текстовый файл:

      1.3K apples
87.9K oranges
156K mangos
541.7K carrots
1.8M potatoes

Я хотел бы преобразовать его в следующее в bash:

      1300 apples
87900 oranges
156000 mangos
541700 carrots
1800000 potatoes

Я использовал команду для замены совпадающих строк числовых сокращений их полными числовыми значениями, например:

      sed -e 's/1K/1000/g' -e 's/1M/1000000/g' text-file.txt

Моя проблема в том, что я не могу найти и заменить ВСЕ возможные сокращения номеров, когда происходит изменение. Я бы хотел сделать это хотя бы до одного десятичного сокращения.

10 ответов

Использовать numfmt от GNU coreutils, не изобретайте велосипед.

      $ numfmt --from=si <file
1300 apples
87900 oranges
156000 mangos
541700 carrots
1800000 potatoes

Если сокращенные числа могут отображаться как любое поле, вы можете использовать:

      numfmt --from=si --field=- --invalid=ignore <file

Не могли бы вы попробовать следовать, написано и протестировано с показанными образцами в GNU awk.

      awk '
{
  if(sub(/[kK]$/,"",$1)){
    $1*=1000
  }
  if(sub(/[mM]$/,"",$1)){
    $1*=1000000
  }
}
1
' Input_file

Explanation: Добавление подробного объяснения вышеизложенного.

      awk '                     ##Starting awk program from here.
{
  if(sub(/[kK]$/,"",$1)){ ##Checking condition if 1st field ends with k/K then do following. Substituting k/K in first field with NULL here.
    $1*=1000              ##Multiplying 1000 with current 1st field value here.
  }
  if(sub(/[mM]$/,"",$1)){ ##Checking condition if 1st field ends with m/M then do following. Substituting m/M in first field with NULL here.
    $1*=1000000          ##Multiplying 1000000 with current 1st field value here.
  }
}
1                         ##1 will print current line here.
' Input_file              ##Mentioning Input_file name here.

Результат будет следующим.

      1300 apples
87900 oranges
156000 mangos
541700 carrots
1800000 potatoes

Другой awk вариант:

      awk '{q = substr($1, length($1));
$1 *= (q == "M" ? 1000000 : (q=="K"?1000:1))} 1' file

1300 apples
87900 oranges
156000 mangos
541700 carrots
1800000 potatoes

Это выполняет глобальную замену (если у вас есть>1 строка для преобразования на строку):

      perl -pe 's{\b(\d+(?:\.\d+)?)([KM])\b}{ $1*1000**(index("KM",$2)+1) }ge' file

Немного более программным способом и на основе этого ответа вы можете создать список всех возможных коэффициентов преобразования и при необходимости выполнить умножение:

      awk 'BEGIN{f["K"]=1000; f["M"]=1000000}
     match($1,/[a-zA-Z]+/){$1 *= f[substr($1,RSTART,RLENGTH)]}
     1' file

С GNU awk для gensub():

      $ awk '
    BEGIN { mult[""]=1; mult["k"]=1000; mult["m"]=100000 }
    { $1 *= mult[gensub(/[^[:alpha:]]/,"","g",tolower($1))] }
1' file
1300 apples
87900 oranges
156000 mangos
541700 carrots
180000 potatoes

Другой вариант может заключаться в использовании только bash и шаблона с группами захвата, где вы можете захватывать либо M или же K. Если шаблон совпадает, проверьте один из них, установите множитель и используйте bc

      while IFS= read -r line
do
  if [[ $line =~ ^([[:digit:]]+(\.[[:digit:]]+)?)([MK])( .*)$ ]];then
    echo "$(bc <<< "${BASH_REMATCH[1]} * $([ ${BASH_REMATCH[3]} == "K" ] && echo "1000" || echo "1000000") / 1")${BASH_REMATCH[4]}"
  fi
done < text-file.txt

Выход

      1300 apples
87900 oranges
156000 mangos
541700 carrots
1800000 potatoes

Демо Bash

Это может сработать для вас (GNU sed):

      sed -E '1{x;s/^/K00M00000/;x}
        :a;G;s/([0-9])(\.([0-9]))?([KM])(.*)\n.*\4(0*).*/\1\3\6\5/i;ta
        P;d' file

Создайте поиск и сохраните его в удерживаемом пространстве.

Добавьте поиск в каждую строку и используйте сопоставление с образцом, чтобы заменить ключи в поиске его значением.

Наконец, распечатайте строку, если больше не найдено совпадений.

Дано:

      $ cat file
1.3K apples
87.9K oranges
156K mangos
541.7K carrots
1.8M potatoes

Просто для смеха, чистый Bash (с sed и bc):

      while read -r x y 
do 
    new_x=$(echo "$x" | sed -E 's/^([[:digit:].]*)[kK]/\1\*1000/; s/^([[:digit:].]*)[mM]/\1\*1000000/' | bc)
    printf "%'d %s\n" "$new_x" "$y"
done <file  

Печать:

      1,300 apples
87,900 oranges
156,000 mangos
541,700 carrots
1,800,000 potatoes

вот как преобразовать их в обаbase-2иbase-10весы от килограмма до недавнего добавленияquetta-(Q)(10^30)

-- (плюс один частный случай обработки B(illion)как G):

      echo '1.3K apples
87.9K oranges
156K mangos
541.7K carrots
1.8M potatoes
1189.135311B peaches
1189.135311G grapes
73.3231T sourgrapes' | gtee >( gcat -b >&2;) | 

.

      {m,g,n}awk '

 ($!NF = sprintf("%s %s %s %s", __ = toupper($++_), __, __, $++_))^!_ + \
 ($_   = __ * ((_____ = (_+=_)^_*_--) + _-_^_--)^(sub("B$","G",__)^!_ * \
                    index(____="KMGTPEZYRQ",___=substr(__,length(__)))))^!_ + \
 ($++_ = __ * _____^index(____, ___))^(_-=_)' CONVFMT='%.f' |

column -t

.

           1  1.3K apples
     2  87.9K oranges
     3  156K mangos
     4  541.7K carrots
     5  1.8M potatoes
     6  1189.135311B peaches
     7  1189.135311G grapes
     8  73.3231T sourgrapes

1.3K          1300            1331            apples
87.9K         87900           90010           oranges
156K          156000          159744          mangos
541.7K        541700          554701          carrots
1.8M          1800000         1887437         potatoes
1189.135311B  1189135311000   1276824317816   peaches
1189.135311G  1189135311000   1276824317816   grapes
73.3231T      73323100000000  80619601034582  sourgrapes
Другие вопросы по тегам