Преобразование всех числовых сокращений в числовые значения в текстовом файле
Я хотел бы преобразовать все числовые сокращения, такие как 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
Это может сработать для вас (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