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그 시점에서는 후행 0을 사용하고 자르는 것이 더 쉽다고 생각할 수도 있습니다 .

또한보십시오 awk:

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

더 적은 수의 연산자와 수학 함수를 지원하지만 이것만으로도 충분할 수 있습니다.

답변2

내가 올바르게 이해했다면 후행 0과 후행 점을 제거하고 싶습니다. 이 경우 EXTENDED_GLOB설정하면 다음을 사용할 수 있습니다.

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

즉, 문자열( ) 끝에 있는 %0개 이상의 점( ) .#과 그 뒤에 하나 이상의 0( 0##)이 일치합니다.

""그러나 만약 result그렇다면, 이것은 반환될 것입니다 0. 반환 값을 다음으로 복원하기 위해 첫 번째 항목을 또 다른 대체할 수 있습니다 0.

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

답변3

bc결과는 긴 정수 또는 소수로 인쇄될 수 있습니다. 다음은 여러 줄로 분할된 긴 정수를 연결하고 소수점 이하 소수점 이하의 0을 제거하는 스크립트입니다.

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}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)가 정수에 대해서만 수행될 수 있다는 사실을 활용합니다.

관련 정보