2016/02/04

Asterisk : The Cookbook 食譜 030 - 表示法 Expressions

Q030: 在撥號計劃設定檔中有看到類似四則運算,可以說明是怎麼用的嗎?

前面幾則對撥號計劃的設定其實已經說的很多了,基本的使用照理也沒什麼大問題才對。但是要設計自動話務員這類複雜的使用環境的話還有一個課題要說,就是所謂的『表示法』,也就是類似程式語言中的各項運算。

在 Asterisk 的運算中,邏輯運算跟 C 語言一樣,以 0 為假,以非 0 為真,如果有疑問的話,可以隨便找一本程式語言的書來翻翻看。

還記得前面曾經提到一個內建變數,指向現有的分機號碼的 ${EXTEN} 嗎?還記得曾經提過可以用 Set() 設定變數嗎?是的,變數是可以運算的。為了簡少本文長度,直接以實例說明:

  same => n,Set(COUNT=3)
  same => n,Set(NEWCOUNT=$[${COUNT} + 1])
  same => n,SayNumber(${NEWCOUNT})

上面應該有看到變數運算要擺在 $[] 裡面, 而且仍然不變採用 ${} 來取得變數。同樣的,上面也看到了加法,底下就來說說除了加法以外的其它運算子,有些我就懶得打字了。

邏輯判斷  |, &, =, >, <, >=, <=, !=
  有發現嗎?等於的判斷只有一個等號
四則運算  +, -, *, /, %
  最後面 % 是『餘數』的意思
正規表示法 :, =~
  因為第一個是冒號 ':' 特別提出來,因為要學正規表示法篇幅會變很大,雖然它很強大,但是除非相當進階才會需要,這邊就略過。

先總結一下,上面的運算子在其他語言中也都很常見,只是感覺混合了 C, Shell script, 所以差異之處自己要記住。Asterisk 早期版本要求運算子前後一定要有空白,而且通常寫程式時也都會要求我們把式子寫的『明確』一點,請看下例:

  劣: same => n,Set(TEST=$[${COUNT}+1])
  優: same => n,Set(TEST=$[ ${COUNT} + 1 ])

上面 Set() 是 Application, 而 ${} 則是變數引用, $[] 是變數運算,其中大中小括號的配對請自己小心閱讀,不要有了左邊漏了右邊。

接下來,在變數引用裡面可以使用函數運算,底下直接用例子說明:
  same => n,SayNumber(${LEN(${TEST})})
上面的 LEN() 會計算後面參數字串 ${TEST}的長度

接下來介紹一個特別的函數,TIMEOUT(), 它會傳回一個變數,沒錯,直接看用法:

  same => n, Set(TIMEOUT(digit)=30)

因為 TIMEOUT() 傳回變數,所以它本身不必用 ${} 括住,其中 digit 是 TIMEOUT() 可以用的三個類型之一。

條件判斷也是透過函數來表達,底下也是以實例來說明:

GotoIf(expression?destination1:destination2)
=================================

exten => 345,1,NoOp()    ; 通常用複雜運算用 NoOp() 開頭
  same => n,Set(TEST=1)
  same => n,GotoIf($[${TEST} = 1]?weasels:iguanas)
  same => n(weasels),Playback(weasels-eaten-phonesys)
  same => n,Hangup()
  same => n(iguanas),Playback(office-iguanas)
  same => n,Hangup()

這邊先補充說明,在講權值時引入 same => n 這樣的表示法時沒說到的部份就是,因為 n 只代表繼續上一個權值,當我們需要參考到某個權值時,可以在 n 後面用 (LABEL) 的方式給予標記,就像上面例子那樣使用,就不多說了。比較特別的是下面的用法也是允許的,就是判斷成立反而不跳走而是繼續下一個,同理也可以像第二條:
same => n,GotoIf($[${TEST} = 1]?:iguanas)
same => n,GotoIf($[${TEST} != 1]?iguanas)

上面範例還有一種寫法更易閱讀,跳到分機號碼去了:
exten => 345,1,NoOp()
  same => n,Answer()
  same => n,Set(TEST=1)
  same => n,GotoIf($[${TEST} = 1]?weasels,1:iguanas,1)
exten => weasels,1,
  same => n,Playback(weasels-eaten-phonesys)
  same => n,Hangup()
exten => iguanas,1,NoOp()
  same => n,Playback(office-iguanas)
  same => n,Hangup()

講到這邊篇幅已經很長了,但是仍然不得不提醒一件事,去翻一下 Shell Script, 就可以發現字串最好用 "" 括住,例如:

劣: same => n,GotoIf($[${TEST} = invalid]?err_handle)
    當 ${TEST} 未設定或是空字串時就會出錯。
優: same => n,GotoIf($[ "${TEST}" = "invalid"]?err_handle)

同樣道理:

劣: same => n,GotoIf($[${TEST} < 1]?err_handle)
  當 ${TEST} 未設定或是其實它是空字中時就會出錯
優: same => n,GotoIf($[ 0${TEST} < 1]?err_handle)

一個良好的 Asterisk 服務,應該能夠根據不同日期時間進行不同的服務,因此底下再特別提出 GotoIfTime() 函數。

GotoIfTime(times,days_of_week,days_of_month,months?label)
實例: same => n,GotoIfTime(09:00-17:59,mon-fri,*,*?open,s,1)
==============================================
times 可能的實例:
  "5:00 PM", "09:00-17:00", "18:00-0900"
  最後的實例會相當於下班時間,系統會自行處理跨日
days_of_week 可能的實例:
  "mon", "tue", "wed", "the", "fri", "sat", "sun", "sun-mon", "sat&sun"
  所以像週一三五的話是 "mon&wed&fri"
days_of_mon 可能的實例:
  "1",...,"31",  "7-12", "5&15&25"
months 可能的實例:
  "jan", ..., "dec", "jan-apr&jun&oct-dec"
以上,如果要『全部』的話就用星號 "*"

函數就暫時說這麼多,詳細可以在 asterisk -rc 的 CLI 環境中以命令 'core show functions' 取得清單


0 意見: