将所有数字缩写转换为文本文件中的数值

chi*_*ppa 46 bash awk sed

我想将文本文件中的所有数字缩写(例如 1K、100K、1M 等)转换为纯数值,例如 1000、100000、1000000 等。

例如,如果我有以下文本文件:

1.3K apples
87.9K oranges
156K mangos
541.7K carrots
1.8M potatoes
Run Code Online (Sandbox Code Playgroud)

我想在 bash 中将其转换为以下内容:

1300 apples
87900 oranges
156000 mangos
541700 carrots
1800000 potatoes
Run Code Online (Sandbox Code Playgroud)

我使用的命令是用完整的数值替换匹配的数字缩写字符串,如下所示:

sed -e 's/1K/1000/g' -e 's/1M/1000000/g' text-file.txt
Run Code Online (Sandbox Code Playgroud)

我的问题是,当发生变化时,我无法找到并替换所有可能的数字缩写。我想这样做直到至少有一位十进制缩写。

ogu*_*ail 97

numfmt从 GNU coreutils使用,不要重新发明轮子。

$ numfmt --from=si <file
1300 apples
87900 oranges
156000 mangos
541700 carrots
1800000 potatoes
Run Code Online (Sandbox Code Playgroud)

如果缩写数字可能显示为任何字段,则您可以使用:

numfmt --from=si --field=- --invalid=ignore <file
Run Code Online (Sandbox Code Playgroud)


Rav*_*h13 33

您能否尝试使用 GNU 中显示的示例进行跟踪、编写和测试awk

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

说明:为以上添加详细说明。

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.
Run Code Online (Sandbox Code Playgroud)

输出如下。

1300 apples
87900 oranges
156000 mangos
541700 carrots
1800000 potatoes
Run Code Online (Sandbox Code Playgroud)


anu*_*ava 17

另一种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
Run Code Online (Sandbox Code Playgroud)


row*_*oat 15

这将执行全局替换(如果每行有 >1 个字符串要转换):

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


kva*_*our 8

以更多的编程方式,并基于此答案,您可以创建所有可能转换因子的列表,并在需要时执行乘法运算:

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


The*_*ird 8

另一种选择可能是仅使用 bash 和带有捕获组的模式,您可以在其中捕获MK. 如果模式匹配,则测试其中之一并设置乘数并使用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
Run Code Online (Sandbox Code Playgroud)

输出

1300 apples
87900 oranges
156000 mangos
541700 carrots
1800000 potatoes
Run Code Online (Sandbox Code Playgroud)

Bash 演示


Ed *_*ton 8

使用用于 gensub() 的 GNU awk:

$ 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
Run Code Online (Sandbox Code Playgroud)


daw*_*awg 7

鉴于:

$ cat file
1.3K apples
87.9K oranges
156K mangos
541.7K carrots
1.8M potatoes
Run Code Online (Sandbox Code Playgroud)

只是为了傻笑,纯 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  
Run Code Online (Sandbox Code Playgroud)

印刷:

1,300 apples
87,900 oranges
156,000 mangos
541,700 carrots
1,800,000 potatoes
Run Code Online (Sandbox Code Playgroud)


pot*_*ong 7

这可能对你有用(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
Run Code Online (Sandbox Code Playgroud)

创建查找并将其存储在保留空间中。

将查找附加到每一行并使用模式匹配将查找中的键替换为其值。

最后在找不到更多匹配项时打印该行。