【问题标题】:Separating integer and fractional part of a decimal number分隔十进制数的整数和小数部分
【发布时间】:2021-08-20 13:45:55
【问题描述】:

我想分隔一个十进制数字,将整数部分存储在 bash 变量 ts 中,将小数部分存储在变量 fr 中。

尝试了参数扩展,但继续获取原始数字。

t=13.491675 
ts=${t#![0-9]*}
fr=${t%*![0-9]}

【问题讨论】:

  • 为什么不在. 上拆分?您是否还有其他需要拆分且未被. 分隔的数字?您是否必须使用 1000 的分隔符来处理数字?您是否需要支持欧洲号码(即逗号而不是句号)?我很惊讶您没有收到错误消息(例如,-bash: ![0: event not found

标签: bash parameter-expansion


【解决方案1】:

这应该适用于任何decimal separator

shopt -s extglob
t=13.491675
ts="${t%%[^0-9]+([0-9])}"
fr="${t##+([0-9])[^0-9]}"

【讨论】:

  • 为什么extglob的使用需要加分?使用任何东西有什么意义?如果这是一个技术(而不是修辞)问题,答案是extglob 启用(例如)+(...) 构造。 Bash 以多种方式使用 glob,不仅用于匹配文件系统路径。 Glob 也用于字符串比较和诸如此类的扩展。
  • 非常好,点赞。即使根据您的 Wikipedia 链接,我们也不能 100% 确定它在南极是否有效。更严重的是,由于我们不知道小数分隔符是否应保留在小数部分,因此添加一个保留它的解决方案可能会很有趣 ("${t##+([0-9])}")。
  • 因为这里不需要。这也可以使用普通的 glob 来实现,因此投反对票。
  • 请用普通的 glob 发布一个 100% 等效的示例。
  • @AndrejPodzimek Oguz 可能一直在考虑这两个:${t%%[,.]*}${t##*[,.]}。在任何情况下,不要把这些当成个人,只是我们律师在谈论 Bash 法律的复杂性:)
【解决方案2】:

使用普通的 POSIX 扩展:

#!/usr/bin/env sh

t=13.491675

# Trim-out shortest trailing dot followed by any number of any character
ts=${t%.*}

# Cut shortest leading any number of any character followed by a dot
fr=${t#*.}

# Debug printout
printf 't=%s\nts=%d\nfr=%d\n' "$t" "$ts" "$fr"

或者使用 Bash 的 here-string 与 Internal Field S分隔符设置为点:

#!/usr/bin/env bash

t=13.491675

IFS=. read -r ts fr <<<"$t"

printf 't=%s\nts=%d\nfr=%d\n' "$t" "$ts" "$fr"

或与 IFS 相同,将不带引号的变量作为参数拆分

#!/usr/bin/env sh

t=13.491675

# Save IFS
__OIFS="$IFS"

IFS=.
set -- $t
ts=$1
fr=$2

IFS=$__OIFS

printf 't=%s\nts=%d\nfr=%d\n' "$t" "$ts" "$fr"

【讨论】:

  • 您可以unset IFS 将其恢复为默认值吗?而不是使用临时的__OIFS
【解决方案3】:

让我们首先将数字视为数字并使用bc(如果可用):

$ t=13.491675
$ read ts fr < <(printf 't=%s; print t/1," ",t-t/1\n' "$t" | bc)
$ echo "$ts + $fr = $t"
13 + .491675 = 13.491675

同样可以用awk的计算能力来完成:

$ read ts fr < <(echo "$t" | awk '{printf("%d %f\n", int($1), $1-int($1))}')
$ echo "$ts + $fr = $t"
13 + 0.491675 = 13.491675

注意小数部分中多余的前导0

或混合使用printf 提取整数部分和bc 提取小数部分:

$ t=13.491675
$ printf -v ts '%.0f\n' "$t"
$ fr=$(printf '%s-%d\n' "$t" "$i" | bc)
$ echo "$ts + $fr = $t"
13 + .491675 = 13.491675

或者,如果bc 不是一个选项,printf 和 bash 参数扩展来完成这项工作:

$ t=13.491675
$ printf -v ts '%.0f\n' "$t"
$ fr="${t#$i}"
$ echo "$ts + $fr = $t"
13 + .491675 = 13.491675

为了去掉小数点分隔符,如果需要,我们可以多使用一个参数扩展:

$ fr="${fr:1}"

或:

$ fr="${fr:2}"

对于基于awk 的解决方案。

【讨论】:

    猜你喜欢
    • 2012-05-28
    • 2020-03-29
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 2016-02-24
    • 2020-12-06
    • 2020-05-18
    • 2017-07-30
    相关资源
    最近更新 更多