Bash

用結果替換數學方程

  • July 28, 2022

在文件中用結果替換使用某些預定義的正則表達式找到的方程的最佳方法是什麼。

假設每個方程公式都兼容bc -l(帶有浮點數處理的基本計算器)。

例如,說方程由[[and分隔]](僅作為範例):

輸入將是:

Results show that each unit should generate
approx. [[7*9/2.0]]Wh per day.
All the same ...

期望的輸出:

Results show that each unit should generate
approx. 31.5Wh per day.
All the same ...

我最好的嘗試:

while read line; do
   
   if [[ $line =~ \[\[.*\]\] ]]; then
   
       equ=`echo "$line" | sed "s|.*\[\[||" | sed "s|]].*||"`
       res=`echo "$equ" | bc -l | awk '{print $1+0}'`
       
       new_line=`echo $line | sed "s|\[\[.*]]|$res|"`
       
       echo $new_line
       
   else
       
       echo $line
       
   fi

done < $infile

輸出:

Results show that each unit should generate
approx. 31.5Wh per day.
All the same ...

但是想知道是否沒有更簡單的方法(沒有 while 循環)。

此外,如果每行只有一個方程,這將起作用。

兼容bc -l,你說?我想你最好的選擇是執行bc -l,那麼。你可以用 Perl 很容易地做到這一點。如果我們有math.txt這樣的:

two times [[3*7]] is [[2*3*7]]
[[scale=6; a=4; a*s(3.141/4)]]

這將掃描它並在[[...]]through中傳遞塊bc -l

$ perl -pe 's,\[\[(.*?)\]\], $a=qx/echo "$1" | bc -l /; chomp $a; $a ,ge' math.txt 
two times 21 is 42
2.828008

它只是擷取[[和之間的任何內容]],將其作為輸入推到bc -l,並用輸出替換括號中的塊。

請注意,這確實會bc為每個塊執行一個新實例,因此變數分配不會保留在塊之間。(但是你可以設置scale每個塊,就像我在上面所做的那樣。)匹配是非貪婪的,因此每行有多個塊可以工作,但這確實意味著結束分隔符不能作為表達式的一部分出現,即為什麼我用]]. (使用括號,可能會發生衝突:例如((3*(a+(b+c))))會失敗,並且您需要用空格分隔括號,例如((3*(a+(b+c) ) ))。)

括號在正則表達式中仍然很特殊,因此它們與\[\[and匹配\]\];正則表達式中的括號用於擷取內部部分。不過,可能有更好的方法來處理bc列印的換行符。

為每個算術塊啟動一個新程序似乎有點繁重,但它是一個相當簡單的解決方案。

**請注意,這對於敵對輸入是不安全的!**當塊的內容通過 shell 傳遞給 forbc時,算術表達式中的任何 shell 語法都將被處理。例如,這將執行uname命令:

[[ $(uname -a >&2 ) ]]

這可以通過bc從 Perl 打開一個管道來解決,但它可能不適合單行。

引用自:https://unix.stackexchange.com/questions/711570