zshの文字列で数値を丸め/切り捨てる(または外部ツールを使用)

zshの文字列で数値を丸め/切り捨てる(または外部ツールを使用)

bcインターフェースに「閉じ込められた」迷惑をかけずに直感的に使用できるようにインターフェースを作成しようとしています。結果を表示する方法(文字列であると仮定)に関する別の詳細にとらわれていたので、テストする時間はあまりありませんでした。

四捨五入しても切っても構いません。どちらも大丈夫です。以下をご覧いただくとすぐにご理解いただけます。私はzshを使用していますが、ある時点や他の重要な状況では使用しないので、外部ツールは問題ありません。それはただのデスクトップツールです。

calc () {
    result=`bc <<EOF
    scale=3;
    $@
    EOF`
    echo ${result//%0/} # doesn't work; will only remove one zero
                        # also, if there are only zeroes, should
                        # remove dot as well - what about .333, etc.?
}

編集する

noglob以下の解決策、特に引用符を削除する方法に本当に感動しました!

しかし、浮動小数点計算を強制するために点を使用することは決して覚えていません(このような一般的な計算機は使用しません)。特に、浮動小数点がまったく異なる結果(望ましい結果である可能性が高い)を生成するかどうかわからない計算では、少し危険です。

また、以下の計算は、いくつかの見苦しい出力(あまりにも長い間違いと末尾の点が示されている)を示しています。

おそらくこれ(一部)を@Gilleの出力形式と組み合わせる必要があるようです。回答次のような?完璧に機能したら、ここに結果を投稿します。 (編集する:承諾しました回答良い結果。この回答に関するコメントを必ずお読みください。 )

calc () {
  echo $(($*));
}
alias calc='noglob calc'

calc 1./3
0.33333333333333331
calc 7.5 - 2.5
5.

答え1

独自の算術を使用して、zsh次のようにすることができます。

calc() printf '%.6g\n' $(($*))
alias 'calc=noglob calc'

123.ただし、これは浮動小数点として扱われ、浮動小数点計算をトリガーするために数字を入力する必要があることを意味します。

.この問題を解決するには、16進数(または他の進数の数字)や変数名または型の数字ではなく一連の10進数を追加できます。12e-20たとえば、次のようになります。

setopt extendedglob
calc() printf '%.6g\n' $((${*//(#bm)(([0-9.]##[eE][-+][0-9]##|[[:alnum:]_#]#[.#_[:alpha:]][[:alnum:]_#]#)|([0-9]##))/$MATCH${match[3]:+.}}))
alias 'calc=noglob calc'

bcその時点では、末尾のゼロを使用してカットする方が簡単だと思うかもしれません。

また見てくださいawk

calc() awk "BEGIN{print $*}"

少数の演算子と数学関数をサポートしますが、これだけで十分です。

答え2

私が正しく理解したら、末尾のゼロと末尾のポイントを削除したいと思います。この場合、EXTENDED_GLOB設定すると次のようになります。

${result//%.#0##/}

つまり、文字列()の末尾にある%0個以上の点().#と、その後に1つ以上の0(0##)が一致します。

""しかし、もしresultそうなら、これは返されます0。戻り値を次に復元するために、最初の項目を別の代替として使用できます0

${${result//%.#0##/}:-0}

答え3

bc結果は長い整数または小数で印刷できます。以下は、複数行に分割された長い整数を連結し、小数点以下の小数点以下のゼロを削除するスクリプトです。

calc () {
  emulate -L zsh; setopt extended_glob
  local line
  bc <<EOF |
scale=3
$@
EOF
    while read line; do
      if [[ $line = *.* ]]; then
        print -r -- ${${${line%%0##}/#%0#./0}%.}
      else
        print -r -- $line
      fi
    done
}

書かれた方法は、素数をきれいに印刷する明確な方法ではなく、引数置換によるテキスト操作に近いです。

  • ${…%%0##}最長のサフィックス一致0##、つまり末尾のゼロを削除します。
  • ${…/#%0#./0}0文字列がオプションの先行ゼロ()(#%パターンのプレフィックス)のみで構成されている場合、文字列は次のように設定されます。${VAR/PATTERN/REPLACEMENT}0#.
  • ${…%.}末尾を削除します.(存在する場合)。

ステップを分ける方が明確だと思います。

if [[ $line = *.* ]]; then line=${line%%0##}; fi
if [[ $line = . ]]; then line=0; else line=${line%.}
print -r -- $line

答え4

文字列操作や子処理なしでasm.jsと同じテクノロジを使用してこれを実行できます。

echo $((123.45|0))  # prints 123

これは、一部の演算子(ビットごとのORなど)が整数に対してのみ実行できるという事実を利用します。

関連情報