目次
UWSC(Umiumi Windows SCript)本体とPro版に付随するRecIE・UWSC Debugger・Uws2Exe・UWSC Cross Referenceの使い方の説明です。
UWSCの導入
ダウンロード
現在、UWSC公式サイト(http://www.uwsc.info)は閲覧できませんが、Internet Archiveという過去のWebページを保存しているサイトを利用することでダウンロードできます。
最新バージョン
UWSCの最新バージョンは5.3.0.2でUWSCの詳細情報 : Vector ソフトを探す!ではFree版のみダウンロードでき、ダウンロード(Internet Archive)ではFree版・Pro版ともにダウンロードすることができます。
過去バージョン
UWSC(Internet Archive)でアーカイブを見ることはでき、一部のバージョンはダウンロードすることも可能です。Pro版は2007年3月20日のVer4.2以降からのバージョンでダウンロードできます。
Wayback Machine(Internet Archive)で過去のバージョンをリストで見ることができ一部はダウンロードすることができます。リンク先のZIPファイルはFree版、EXEファイルはPro版のファイルで、例えばUWSC Ver4.7aの場合、Free版がhttp://www.uwsc.info/uwsc47a.zip、Pro版がhttp://uwsc.info/uwscpro47a.exeのリンクとなります。
以下がダウンロードできるバージョンの表です。GET_UWSC_VERで取得できる値も載せておきます。
Ver4.6aはAxfc UpLoader -4059768.zip-でダウンロードできます。
| ファイル名 | About | GET_UWSC_VER | プログラム名 | About日付 |
|---|---|---|---|---|
| UWSCPRO46A.zip | 4.6a | 4.61 | UWSC Pro 4.6a | 2010/05/07 |
Ver4.3b1より前のものは、旧公式サイトであるうみうみ屋さん(http://www.h7.dion.ne.jp/~umiumi/)にあります。Wayback Machine
UWSCのアップデートの履歴は、公式サイト(UWSC(Internet Archive))トップページの新着情報/お知らせを参考に載せておきます。
インストール
Free版はダウンロードしたZIPファイルを解凍するだけでインストールは不要です。C:\Programs\などわかりやすい場所に移動させておきましょう。
Pro版は、ダウンロードしたuwscproXXX.exe(XXXはバージョン)を実行しインストール作業を行います。
ユーザーアカウント制御が表示される場合はいを選択します。
UWSCをインストールするには使用許諾契約書の同意に同意する必要があるので、内容をよく確認して同意するを選択します。
以下の項目で必要ものにチェックを入れてください。
- デスクトップにUWSCのショートカットを作成
- ファイル拡張子.uwsにUWSCを関連付け
- スタートアップにUWSCのショートカットを作成
設定内容の確認し問題がなければインストールをクリックしてください。
インストールの完了です。
インストール先はC:\Program Files (x86)\UWSC\です。
Pro版の試用期間は初回インストールから14日間です。それ以降も利用するには、ライセンスキーの登録が必要です。
https://total-uninstall.jp.uptodown.com/windows(試用期間30日)でレジストリを削除すると試用期間をリセットできます。
インストール済みプログラムでUWSCを選択し、アンインストールすることでリセットできます。
Total Uninstall Essential Editionを起動したらインストール済みプログラムを選択します。一覧からUWSCを選択します。フィルタにUWSCと入力すると見つけやすくなります。
UWSCを選択したらアンインストールをクリックします。アンインストールプロファイルの選択で解析済みプログラムのアンインストールが選択されているのを確認し、起動をクリックします。
途中以下のようなダイアログが表示されますが、これはTotal Uninstallではなく通常のアンインストール処理なのでいいえを選択します。
選択されているプログラムを確認し、問題なければアンインストールをクリックします。
Pro版の登録
UWSC起動時に表示される以下の画面のユーザー登録からライセンスキーの登録ができます。
メイン画面が表示されている場合は、設定メニュ
をクリックしAboutを選択、タスクトレイにある場合はアイコンを右クリックしAboutを選択で表示されます。
購入時に取得したライセンスキーを入力しOKをクリックします。
ライセンスキーが正しければ以下のようなメッセージが表示され、UWSC Proはシェアウェアです。登録済みと表示が変わります。
ライセンスキーの確認方法
伝票番号がわかる場合
Vectorで購入した方は、ベクターPCショップ お申込状況確認で伝票番号とメールアドレスもしくは電話番号を入力することでライセンスキーを確認することができます。
伝票番号を忘れた場合は、ベクターPCショップ : ヘルプ Q&A・お問い合わせのページにある伝票番号がわかりませんの項目を参考にしてください。以下に引用を記載しておきます。
伝票番号はお手続き時のメールに記載しております。メールが残っていない場合は以下をご参照ください。
伝票番号の記載のあるメールは、「お支払いのご案内メール」と「ライセンスキーのご案内メール」です。
他のメールにも記載のあるものがございますが、どちらのメールもお手元にない場合は、ご購入履歴からお調べしますののでお問い合わせください。
お問い合わせする際、下記のご記入をお知らせください。
・お申込時にご入力いただいたお名前
・ご入力いただいたお電話番号
・ソフト名
・お申込時のメールアドレスお問い合わせは下記より行なうことができます。
他のパソコンでPro版の登録をしている場合
新しいパソコンに買い替えてUWSCのPro版を使いたいけどライセンスキーがわからない場合は、すでにPro版をインストールしているパソコンのレジストリを解析することにより新しいパソコンでもPro版を使うことができます。
ライセンスキーを所有している人ができる内容であって、Pro版を購入していない人が使えるようになるわけではありません。
この方法はライセンスキーを特定するのではなく、ライセンスキーの登録情報を新しいパソコンにコピーするだけです。
公式ページにも(1ライセンス:1人の使用者もしくは1台のコンピュータのどちらかといたします)とあるので、同じ人が使う分には問題ないと思います。
ライセンスキーに関わるレジストリはコンピューター\HKEY_USERS\<SID>\SOFTWARE\Classes\VirtualStore\MACHINE\Software\Wow6432Node\Umiumi\UWSC\SNにあります。
プログラムでレジストリの値を取得・設定
まずUWSC Pro版がインストールされているパソコンでの処理で、以下のプログラムを実行しレジストリから値を取得します。
DIM SWbemLocator = CREATEOLEOBJ("WbemScripting.SWbemLocator")
DIM SWbemServices = SWbemLocator.ConnectServer
DIM query = "SELECT * FROM Win32_UserAccount WHERE Name = '" + TRIM(DOSCMD("echo %username%")) + "'"
SWbemObjectSet = SWbemServices.ExecQuery(query)
GETOLEITEM(SWbemObjectSet)
DIM SID = ALL_OLE_ITEM[0].SID
DIM WshShell = CREATEOLEOBJ("WScript.Shell")
DIM SN = WshShell.RegRead("HKEY_USERS\" + SID + "\SOFTWARE\Classes\VirtualStore\MACHINE\Software\Wow6432Node\Umiumi\UWSC\SN")
PRINT SN
SENDSTR(0, SN)
FUKIDASI("クリップボードに値をコピーしました")
SLEEP(3.000)この値を新しいパソコンで登録します。UWSC Pro版がインストールされている状態で、以下のプログラムを実行してください。11行目のSNに上のプログラムで取得した値を代入してから実行してください。このプログラムでレジストリを書き換えるので自己責任でお願いします。
DIM SWbemLocator = CREATEOLEOBJ("WbemScripting.SWbemLocator")
DIM SWbemServices = SWbemLocator.ConnectServer
DIM query = "SELECT * FROM Win32_UserAccount WHERE Name = '" + TRIM(DOSCMD("echo %username%")) + "'"
SWbemObjectSet = SWbemServices.ExecQuery(query)
GETOLEITEM(SWbemObjectSet)
DIM SID = ALL_OLE_ITEM[0].SID
DIM WshShell = CREATEOLEOBJ("WScript.Shell")
DIM subKey = "HKEY_USERS\" + SID + "\SOFTWARE\Classes\VirtualStore\MACHINE\Software\Wow6432Node\Umiumi\UWSC\"
DIM SN = "" // 取得した値を代入
IFB SN = "" THEN
MSGBOX("SNに値が設定されていないので終了します。")
EXIT
ENDIF
IF regKeyExists(subKey + "TM") AND !regKeyExists(subKey + "SN") THEN WshShell.RegWrite(subKey + "SN", SN, "REG_SZ")
FUNCTION regKeyExists(name)
DIM WshShell = CREATEOLEOBJ("WScript.Shell")
TRY
WshShell.RegRead(name)
RESULT = TRUE
EXCEPT
RESULT = FALSE
ENDTRY
FEND手動でレジストリの値を取得・設定
手動で追加する場合は、以下の手順で登録します。
まずUWSCのライセンスキーの場所を調べるためにSIDが必要なため調べます。コマンドプロンプトで以下を実行しログインユーザーのSIDを取得しておきます。
whoami /userUWSCでも以下のプログラムを実行することで取得することができます。
DIM SWbemLocator = CREATEOLEOBJ("WbemScripting.SWbemLocator")
DIM SWbemServices = SWbemLocator.ConnectServer
DIM query = "SELECT * FROM Win32_UserAccount WHERE Name = '" + TRIM(DOSCMD("echo %username%")) + "'"
SWbemObjectSet = SWbemServices.ExecQuery(query)
GETOLEITEM(SWbemObjectSet)
PRINT ALL_OLE_ITEM[0].SID+Rでファイル名を指定して実行を開きregeditと入力し、レジストリエディターを開きます。
レジストリでコンピューター\HKEY_USERS\S-1-5-21-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxx-xxxx\SOFTWARE\Classes\VirtualStore\MACHINE\Software\Wow6432Node\Umiumi\UWSC\をアドレスバーに貼り付けて移動します。S-1-5-21-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxx-xxxxは取得したSIDに置き換えてください。
このときキー名に既定とTMがあることを確認してください。ない場合はパスが間違っている可能性があります。
編集-新規-文字列値を選択すると新しい値 #1という項目が作成されるので、SNというキー名に書き換えます。
作成したキー名を右クリックし修正で値のデータに前のパソコンで取得した値を貼り付けます。
以下のようになればPro版を使うことができるようになるはずです。UWSCを起動していた場合はソフトを起動し直してください。
アンインストール
スタートをクリックし、UWSCもしくはUWSC Proフォルダ内にある同名のプログラムを右クリックし、アンインストールを選択します。
コントロール パネル\プログラム\プログラムと機能が開くので、一覧からUWSCを選択し、アンインストールをクリックしプログラムをパソコンから削除します。
メイン画面/動作記録と再生
タスクバーのをクリック、アプリ一覧にあるUWSCフォルダのUWSC(Pro版はUWSC ProフォルダのUWSC Pro)でUWSCを起動できます。
UWSCのインストール場所はC:\Program Files (x86)\UWSC\UWSC.exeです。UWSC.exeをダブルクリックすることで起動することもできます。メイン画面が表示されない場合はタスクトレイに格納されているのでUWSCアイコンを右クリック、タスクトレイから出るで表示されます。
メイン画面
- 起動時画面

- 記録実行後画面

![]() |
読込み | スクリプトファイルを読み込みます。(拡張子は".UWS"のみです) |
![]() |
保存 | 動作記録をスクリプトファイルとして保存します。 |
![]() |
再生 | 記録したものを再生します。 |
![]() |
動作記録 | 動作記録を開始します。 |
![]() |
設定 | 各種設定のメニュが出ます。 |
読込み
開くスクリプトのファイル名、実行回数、パラメータを指定します。実行回数には繰り返し実行する回数を指定します。
パラメータは引数を半角スペースで区切り、半角スペースを含む文字列は"(ダブルクォーテーション)で囲みます。受け取った引数はUNICODE文字列なので計算に使う場合はVAL関数 (スクリプト関数)などで数値化する必要があります。
パラメータは実行する度に渡され、PARAM_STRで受け取った引数にアクセスできます。改行コードは<#CR>、ダブルクォーテーションは<#DBL>、タブは<#TAB>で入力します。
以下はパラメータの例です。
第一引数:12、第二引数:51、第三引数:63を指定する場合。
12 51 63第一引数:abc、第二引数:d eを指定する場合。
abc "d e"第一引数:"xyz"を指定する場合。
<#DBL>xyz<#DBL>動作記録
記録ボタンを押してからSTOPボタン又は停止ホットキーが押されるまでの動作を記録します
- 低レベル記録
- キーボードとマウスの押し下げ情報を座標と共に低レベル関数で記録します。記録はマウスクリックかキー操作がされるか、又は マウス移動を0.5秒停止して開始した所から始まります。
MMV,ACW,GETID,BTN,KBD - 高レベル記録
- 高レベル関数を使用して記録します、座標は記録されません。
オブジェクトの選択操作は必ずマウスでしてください、キーボードで選択操作をした場合は記録できません。
多段メニューはメニューが出る毎にクリックを実行してください。
記録できないアプリやオブジェクトがあります。
保存にて記録をスクリプトファイルとして保存できます(スクリプトですので自分で修正したり制御したりできます)
GETID,CLKITEM,SLEEP
再生
再生ボタンで再生します。スクリプトファイルをドロップしてもOKです。
引数にスクリプトファイル名を指定してUWSCを起動してもOKです(この時はスクリプトが終了するとUWSC自体も常駐せずに終了します)。
スクリプトファイル名の後にパラメーターを付ければ 変数PARAM_STRに渡せます。
停止ホットキー(デフォルト:Alt+F2)にて中断できます。
再生ホットキー(デフォルト:Alt+F1)にて一時停止ができます。
設定メニュ/設定画面
設定メニュ
一つ目がタスクトレイ内にあるときの設定メニュー、二つ目がタスクトレイ外にあるときの設定メニューです。
RecIE(Web記録)、Uws2Exe(EXE作成)、Debugger(デバッグ) は UWSC Pro版の機能です。
タスクトレイ内外共通の項目
- 設定(X)
- 設定画面を開きます。
- RecIE(Web記録)(R)
- RecIEを起動します。
- Uws2Exe(EXE作成)(U)
- Uws2Exeを起動します。
- Debugger(デバッグ)(D)
- Debuggerを起動します。
- .INI/.LOG Folder(F)
- UWSC.INIがあるフォルダ(C:\Users\username\AppData\Roaming\UWSC\)を開きます。
- Help(H)
- UWSCヘルプ(C:\Program Files (x86)\UWSC\uwsc.chm)を開きます。
- About(A)
- UWSC Aboutを開きます。バージョンや最新版のチェック、Pro版への登録の有無が確認できます。
- 終了(Z)
- UWSCを終了します。
設定メニュ(タスクトレイ内)
タスクトレイ上のアイコンで右クリックすると設定メニュが出ます。
- タスクトレイから出る(W)
- UWSCをタスクトレイから出し、ウィンドウを表示させます。
設定メニュ(タスクトレイ外)
タスクトレイ外(メイン画面)で設定をクリックと設定メニュが出ます。
- タスクトレイに格納(W)
- UWSCをタスクトレイに格納します。
- ランチメニュ(M)、ランチメニュの設定(Z)...
- スクリプトファイルを 登録しておき 選択起動できます。(スクリプトファイル以外の EXEや関連付けされたファイル等も登録できます)。
ランチメニュ
タスクトレイ上にあるUWSCのアイコンを左クリックすることでランチメニュの設定と登録しているスクリプトの一覧が表示されます。
スクリプト登録
スクリプト設定を行います。
UWSCが起動している場合、ホットキーでここに登録したスクリプトの一覧を表示させることができます。頻繁に使うスクリプトを登録しておくとすぐに起動できるので便利です。
スクリプトは35個まで登録することができ、ホットキー0〜9、A〜Yまで利用できます。Zはランチメニュの設定(Z)を開くのに使われているためホットキーには使用できません。
スクリプト設定

タスクトレイ上のアイコンで左ダブルクリック:タスクトレイから出て通常状態になります。
タスクトレイ上で終了すると次回起動時はタスクトレイ起動になります。
階層化は、同じような処理をグループ化するときに利用します。
以下にランチメニュに登録しておくと便利なスクリプトを記載しておきます。
スクリプトはドキュメント\UWSC\Scripts\フォルダなど同じところにまとめておくと管理しやすくなります。
-
項目取得
- タイトル・クラス名を取得
- カーソル座標と色情報を取得
- CLKITEMで操作できる項目を取得
- CHKBTNで操作できる項目を取得
- GETSTRで取得できるすべての項目を取得
- GETITEMで取得できるすべての項目を取得
- GETSLCTLSTで操作できる項目を取得
-
クリップボード文字列の操作
- 大文字に変換
- 小文字に変換
- ひらがなに変換
- カタカナに変換
- 半角文字に変換
- 全角文字に変換
- タイトル・クラス名
- 座標・色情報
- CLKITEM
- CHKBTN
- GETSTR
- GETITEM
- GETSLCTLST
- 大文字
- 小文字
- ひらがな
- カタカナ
- 半角文字
- 全角文字
PUBLIC ttl, cls
SETHOTKEY(VK_ESC, EMPTYPARAM, "forceQuit")
SETHOTKEY(VK_C, MOD_ALT, "sendToClipboard")
WHILE TRUE
DIM ID = GETID(GET_FROMPOINT_WIN)
ttl = STATUS(ID, ST_TITLE)
cls = STATUS(ID, ST_CLASS)
FUKIDASI(ttl + "<#CR>" + cls)
SLEEP(0.001)
WEND
PROCEDURE forceQuit()
EXITEXIT
FEND
PROCEDURE sendToClipboard()
SENDSTR(0, "DIM ID = GETID(<#DBL>" + ttl + "<#DBL>, <#DBL>" + cls + "<#DBL>)")
FENDHASHTBL rgb
WHILE TRUE
DIM x = G_MOUSE_X
DIM y = G_MOUSE_Y
DIM c = PEEKCOLOR(x, y)
rgb["r"] = decToHex(c AND $FF)
rgb["g"] = decToHex((c AND $FF00) / $100)
rgb["b"] = decToHex((c AND $FF0000) / $10000)
IF LENGTH(rgb["r"]) = 1 THEN rgb["r"] = "0" + rgb["r"]
IF LENGTH(rgb["g"]) = 1 THEN rgb["g"] = "0" + rgb["g"]
IF LENGTH(rgb["b"]) = 1 THEN rgb["b"] = "0" + rgb["b"]
c = "" + rgb["b"] + rgb["g"] + rgb["r"]
font = "$" + invertedColor(c)
back = IIF("$" + c = "$000000", "$000001", "$" + c) // $000000は$FFFF00になるので$000001
msg = "(x, y)<#TAB>(" + x + ", " + y + ")<#CR>" + _
"赤<#TAB>" + rgb["r"] + "(" + hexToDec(rgb["r"]) + ")" + "<#CR>" + _
"緑<#TAB>" + rgb["g"] + "(" + hexToDec(rgb["g"]) + ")" + "<#CR>" + _
"青<#TAB>" + rgb["b"] + "(" + hexToDec(rgb["b"]) + ")"
DIM ID = GETID(GET_FUKIDASI_WIN)
DIM ofs = 25
fx = x + IIF(x >= G_SCREEN_W / 2, -1 * (STATUS(ID, ST_WIDTH) + ofs), ofs)
fy = y - STATUS(ID, ST_HEIGHT) * (y / G_SCREEN_H)
FUKIDASI(msg, fx, fy, IIF(x >= G_SCREEN_W / 2, 4, 3), 10, "メイリオ", font, back)
SLEEP(0.001)
WEND
//////////////////////////////////////////////////
// 【引数】
// arr : 追加される配列(参照引数)
// tmp : 追加する配列
// 【戻り値】
// 追加した後の配列の要素数
//////////////////////////////////////////////////
FUNCTION arrayMerge(Var arr[], tmp[])
FOR n = 0 TO UBound(tmp)
arrayPush(arr, tmp[n])
NEXT
RESULT = UBound(arr)
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 配列。参照引数。
// 【戻り値】
// 引数に指定した配列の最後の要素
//////////////////////////////////////////////////
FUNCTION arrayPop(Var array[])
DIM n = UBound(array)
DIM res = array[n]
RESIZE(array, n-1)
RESULT = res
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 要素を追加する配列(参照引数)
// values : 追加する要素をvalue1から指定
// 【戻り値】
// 処理後の配列の要素の数
//////////////////////////////////////////////////
FUNCTION arrayPush(var array[], value1 = EMPTY, value2 = EMPTY, value3 = EMPTY, value4 = EMPTY, value5 = EMPTY, value6 = EMPTY, value7 = EMPTY, value8 = EMPTY, value9 = EMPTY, value10 = EMPTY, value11 = EMPTY, value12 = EMPTY, value13 = EMPTY, value14 = EMPTY, value15 = EMPTY, value16 = EMPTY)
DIM i = 1
WHILE EVAL("value" + i) <> EMPTY
DIM res = RESIZE(array, UBound(array) + 1)
array[res] = EVAL("value" + i)
i = i + 1
WEND
RESULT = LENGTH(array)
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 逆順にする配列
// 【戻り値】
//
//////////////////////////////////////////////////
PROCEDURE arrayReverse(Var array[])
DIM cnt = LENGTH(array)
FOR i = 0 TO INT(cnt / 2) - 1
swap(array[i], array[cnt-(i+1)])
NEXT
FEND
//////////////////////////////////////////////////
// 【引数】
// needle : 検索する値
// haystack : 配列
// 【戻り値】
// needleが見つかった場合に配列のキー
//////////////////////////////////////////////////
FUNCTION arraySearch(needle, haystack[])
DIM i = 0
FOR item IN haystack
IFB item = needle THEN
RESULT = i
EXIT
ENDIF
i = i + 1
NEXT
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 配列
// 【戻り値】
// arrayの最初の値。配列arrayは、要素一つ分だけ短くなり、全ての要素は前にずれます。
//////////////////////////////////////////////////
FUNCTION arrayShift(Var array[])
DIM res = array[0]
SHIFTARRAY(array, -1)
RESIZE(array, UBound(array) - 1)
RESULT = res
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 要素を加えられる配列
// values : 加える値をvalue1から順に指定
// 【戻り値】
// 処理後の配列の要素の数
//////////////////////////////////////////////////
FUNCTION arrayUnshift(var array[], value1 = EMPTY, value2 = EMPTY, value3 = EMPTY, value4 = EMPTY, value5 = EMPTY, value6 = EMPTY, value7 = EMPTY, value8 = EMPTY, value9 = EMPTY, value10 = EMPTY, value11 = EMPTY, value12 = EMPTY, value13 = EMPTY, value14 = EMPTY, value15 = EMPTY, value16 = EMPTY)
DIM tmp[-1]
DIM i = 1
WHILE EVAL("value" + i) <> EMPTY
arrayPush(tmp, EVAL("value" + i))
i = i + 1
WEND
arrayMerge(tmp, array)
RESIZE(array, UBound(tmp))
SETCLEAR(array, EMPTY)
FOR i = 0 TO UBound(tmp)
array[i] = tmp[i]
NEXT
RESULT = LENGTH(array)
FEND
//////////////////////////////////////////////////
// 【引数】
// bin : 2進数
// signFlg : 符号付きならばTrue
// 【戻り値】
// 10進数に変換した値
//////////////////////////////////////////////////
FUNCTION binToDec(bin, signFlg = TRUE)
DIM dec = 0
DIM decimalFlg = IIF(POS(".", bin), TRUE, FALSE)
IFB COPY(bin, 1, 1) = "1" AND signFlg THEN
DIM msb = IIF(decimalFlg, POS(".", bin) - 1, LENGTH(bin))
DIM lsb = IIF(decimalFlg, POS(".", bin) - LENGTH(bin), 0)
DIM dec2 = POWER(2, msb) - 1
FOR i = -1 TO lsb STEP -1
dec2 = dec2 + POWER(2, i)
NEXT
DIM a = binToDec(bin, FALSE)
DIM b = dec2
dec = -1 * (bitXor(a, b) + POWER(2, lsb))
ELSE
IFB decimalFlg THEN
DIM integer = COPY(bin, 1, POS(".", bin) - 1)
DIM decimal = COPY(bin, POS(".", bin) + 1)
FOR i = 1 TO LENGTH(decimal)
dec = dec + COPY(decimal, i, 1) * POWER(2, -1 * i)
NEXT
ELSE
integer = bin
ENDIF
FOR i = 1 TO LENGTH(integer)
dec = dec + COPY(integer, i, 1) * POWER(2, LENGTH(integer) - i)
NEXT
ENDIF
RESULT = dec
FEND
//////////////////////////////////////////////////
// 【引数】
// bin : 2進数
// 【戻り値】
// 16進数に変換した値
//////////////////////////////////////////////////
FUNCTION binToHex(bin)
HASHTBL bh
bh["0000"] = "0"; bh["0001"] = "1"; bh["0010"] = "2"; bh["0011"] = "3";
bh["0100"] = "4"; bh["0101"] = "5"; bh["0110"] = "6"; bh["0111"] = "7";
bh["1000"] = "8"; bh["1001"] = "9"; bh["1010"] = "A"; bh["1011"] = "B";
bh["1100"] = "C"; bh["1101"] = "D"; bh["1110"] = "E"; bh["1111"] = "F";
// 小数ならば
IFB POS(".", bin) <> 0 THEN
DIM num = COPY(bin, 1, POS(".", bin) - 1)
DIM frac = COPY(bin, POS(".", bin) + 1)
num = strPad(num, CEIL(LENGTH(num) / 4) * 4, "0", LEFT)
frac = strPad(frac, CEIL(LENGTH(frac) / 4) * 4, "0", RIGHT)
DIM hex = ""
FOR i = 1 TO LENGTH(num) STEP 4
hex = hex + bh[COPY(num, i, 4)]
NEXT
hex = hex + "."
FOR i = 1 TO LENGTH(frac) STEP 4
hex = hex + bh[COPY(frac, i, 4)]
NEXT
RESULT = hex
ELSE
len = CEIL(LENGTH(bin) / 4) * 4
FOR i = 1 TO len - LENGTH(bin)
bin = "0" + bin
NEXT
bin = REPLACE(FORMAT(bin, len), " ", "0")
hex = ""
FOR i = 1 TO LENGTH(bin) / 4
str = COPY(bin, i * 4 - 3, 4)
hex = hex + bh[str]
NEXT
RESULT = hex
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// arg1 : 数値1(10進数)
// arg2 : 数値2(10進数)
// 【戻り値】
// 2つの数値のビット毎の論理積
//////////////////////////////////////////////////
FUNCTION bitAnd(arg1, arg2)
DIM args[1] = arg1, arg2
DIM bins[1]
DIM decimals[1]
DIM integers[1]
DIM keta[1]
IFB ABS(arg1) <> arg1 OR ABS(arg2) <> arg2 THEN
RESULT = ERR_VALUE
EXIT
ENDIF
FOR i = 0 TO 1
bins[i] = decToBin(args[i])
decimals[i] = 0
IFB POS(".", bins[i]) <> 0 THEN
integers[i] = COPY(bins[i], 1, POS(".", bins[i]) - 1)
decimals[i] = COPY(bins[i], POS(".", bins[i]) + 1)
ELSE
integers[i] = bins[i]
ENDIF
NEXT
keta[0] = IIF(LENGTH(integers[0]) > LENGTH(integers[1]), LENGTH(integers[0]), LENGTH(integers[1]))
integers[0] = strPad(integers[0], keta[0], "0", LEFT)
integers[1] = strPad(integers[1], keta[0], "0", LEFT)
keta[1] = IIF(LENGTH(decimals[0]) > LENGTH(decimals[1]), LENGTH(decimals[0]), LENGTH(decimals[1]))
decimals[0] = strPad(decimals[0], keta[1], "0", RIGHT)
decimals[1] = strPad(decimals[1], keta[1], "0", RIGHT)
DIM bin = ""
FOR i = 1 TO keta[0]
bin = bin + (VAL(COPY(integers[0], i, 1)) AND VAL(COPY(integers[1], i, 1)))
NEXT
bin = bin + "."
FOR i = 1 TO keta[1]
bin = bin + (VAL(COPY(decimals[0], i, 1)) AND VAL(COPY(decimals[1], i, 1)))
NEXT
RESULT = binToDec(bin)
FEND
//////////////////////////////////////////////////
// 【引数】
// num : 10進数もしくは2進数の値
// bit : ビット
// 【戻り値】
// ビットを反転した値
//////////////////////////////////////////////////
FUNCTION bitNot(num, bit = EMPTY)
IFB isString(num) THEN
DIM res = ""
FOR i = 1 TO LENGTH(num)
DIM str = COPY(num, i, 1)
IFB str = "0" OR str = "1" THEN
res = res + (1 - VAL(str))
ELSE
res = res + str
ENDIF
NEXT
RESULT = res
ELSE
DIM exponent = IIF(bit = EMPTY, CEIL(LOGN(2, num + 1)), bit)
RESULT = POWER(2, exponent) - num - 1
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// arg1 : 数値1(10進数)
// arg2 : 数値2(10進数)
// 【戻り値】
// 2つの数値のビット毎の排他的論理和
//////////////////////////////////////////////////
FUNCTION bitXor(arg1, arg2)
DIM args[1] = arg1, arg2
DIM bins[1]
DIM decimals[1]
DIM integers[1]
DIM keta[1]
IFB ABS(arg1) <> arg1 OR ABS(arg2) <> arg2 THEN
RESULT = ERR_VALUE
EXIT
ENDIF
FOR i = 0 TO 1
bins[i] = decToBin(args[i])
decimals[i] = 0
IFB POS(".", bins[i]) <> 0 THEN
integers[i] = COPY(bins[i], 1, POS(".", bins[i]) - 1)
decimals[i] = COPY(bins[i], POS(".", bins[i]) + 1)
ELSE
integers[i] = bins[i]
ENDIF
NEXT
keta[0] = IIF(LENGTH(integers[0]) > LENGTH(integers[1]), LENGTH(integers[0]), LENGTH(integers[1]))
integers[0] = strPad(integers[0], keta[0], "0", LEFT)
integers[1] = strPad(integers[1], keta[0], "0", LEFT)
keta[1] = IIF(LENGTH(decimals[0]) > LENGTH(decimals[1]), LENGTH(decimals[0]), LENGTH(decimals[1]))
decimals[0] = strPad(decimals[0], keta[1], "0", RIGHT)
decimals[1] = strPad(decimals[1], keta[1], "0", RIGHT)
DIM bin = ""
FOR i = 1 TO keta[0]
bin = bin + (VAL(COPY(integers[0], i, 1)) XOR VAL(COPY(integers[1], i, 1)))
NEXT
bin = bin + "."
FOR i = 1 TO keta[1]
bin = bin + (VAL(COPY(decimals[0], i, 1)) XOR VAL(COPY(decimals[1], i, 1)))
NEXT
RESULT = binToDec(bin)
FEND
//////////////////////////////////////////////////
// 【引数】
// color : Color値
// flg : #RRGGBB形式で返す場合Trueを指定
// 【戻り値】
// 赤成分、緑成分、青成分を格納した配列、もしくは#RRGGBB形式の文字列
//////////////////////////////////////////////////
FUNCTION colorToRGB(color, flg = FALSE)
DIM array[2]
array[0] = color AND $FF
array[1] = (color AND $FF00) / $100
array[2] = (color AND $FF0000) / $10000
IFB flg THEN
DIM rgb = ""
FOR item IN array
DIM hex = decToHex(item)
rgb = rgb + COPY(hex, LENGTH(hex)-1)
NEXT
RESULT = "#" + rgb
ELSE
RESULT = SLICE(array)
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// num : 単位換算する数値
// before : 変換前の単位
// after : 変換後の単位
// 【戻り値】
// 指定した単位に変換した数値
//////////////////////////////////////////////////
FUNCTION convert(num, before, after)
HASHTBL unit
// 重量
unit["g,sg"] = "num * 6.85217658567918 * POWER(10, -5)"
unit["g,lbm"] = "num * 2.20462262184878 * POWER(10, -3)"
unit["g,u"] = "num * 6.02217 * POWER(10, +23)"
unit["g,ozm"] = "num * 3.52739619495804 * POWER(10, -2)"
unit["sg,g"] = "num * 1.45939029372064 * POWER(10, +4)"
unit["sg,lbm"] = "num * 3.21740485564304 * POWER(10, +1)"
unit["sg,u"] = "num * 8.78869644513561 * POWER(10, +27)"
unit["sg,ozm"] = "num * 5.14784776902887 * POWER(10, +2)"
unit["lbm,g"] = "num * 4.5359237 * POWER(10, +2)"
unit["lbm,sg"] = "num * 3.10809501715673 * POWER(10, -2)"
unit["lbm,u"] = "num * 2.7316103628429 * POWER(10, +26)"
unit["lbm,ozm"] = "num * 1.6 * POWER(10, +1)"
unit["u,g"] = "num * 1.66053100460465 * POWER(10, -24)"
unit["u,sg"] = "num * 1.13782516695463 * POWER(10, -28)"
unit["u,lbm"] = "num * 3.66084421703269 * POWER(10, -27)"
unit["u,ozm"] = "num * 5.8573507472523 * POWER(10, -26)"
unit["ozm,g"] = "num * 2.8349523125 * POWER(10, +1)"
unit["ozm,sg"] = "num * 1.94255938572295 * POWER(10, -3)"
unit["ozm,lbm"] = "num * 6.25 * POWER(10, -2)"
unit["ozm,u"] = "num * 1.70725647677681 * POWER(10, +25)"
// 距離
unit["m,mi"] = "num * 6.21371192237334 * POWER(10, -4)"
unit["m,Nmi"] = "num * 5.39956803455724 * POWER(10, -4)"
unit["m,in"] = "num * 3.93700787401575 * POWER(10, +1)"
unit["m,ft"] = "num * 3.28083989501312 * POWER(10, +0)"
unit["m,yd"] = "num * 1.09361329833771 * POWER(10, +0)"
unit["m,ang"] = "num * 1 * POWER(10, +10)"
unit["m,pica"] = "num * 2.36220472440945 * POWER(10, +2)"
unit["mi,m"] = "num * 1.609344 * POWER(10, +3)"
unit["mi,Nmi"] = "num * 8.68976241900648 * POWER(10, -1)"
unit["mi,in"] = "num * 6.336 * POWER(10, +4)"
unit["mi,ft"] = "num * 5.28 * POWER(10, +3)"
unit["mi,yd"] = "num * 1.76 * POWER(10, +3)"
unit["mi,ang"] = "num * 1.609344 * POWER(10, +13)"
unit["mi,pica"] = "num * 3.8016 * POWER(10, +5)"
unit["Nmi,m"] = "num * 1.852 * POWER(10, +3)"
unit["Nmi,mi"] = "num * 1.15077944802354 * POWER(10, +0)"
unit["Nmi,in"] = "num * 7.29133858267717 * POWER(10, +4)"
unit["Nmi,ft"] = "num * 6.0761154855643 * POWER(10, +3)"
unit["Nmi,yd"] = "num * 2.02537182852143 * POWER(10, +3)"
unit["Nmi,ang"] = "num * 1.852 * POWER(10, +13)"
unit["Nmi,pica"] = "num * 4.3748031496063 * POWER(10, +5)"
unit["in,m"] = "num * 2.54 * POWER(10, -2)"
unit["in,mi"] = "num * 1.57828282828283 * POWER(10, -5)"
unit["in,Nmi"] = "num * 1.37149028077754 * POWER(10, -5)"
unit["in,ft"] = "num * 8.33333333333333 * POWER(10, -2)"
unit["in,yd"] = "num * 2.77777777777778 * POWER(10, -2)"
unit["in,ang"] = "num * 2.54 * POWER(10, +8)"
unit["in,pica"] = "num * 6 * POWER(10, +0)"
unit["ft,m"] = "num * 3.048 * POWER(10, -1)"
unit["ft,mi"] = "num * 1.89393939393939 * POWER(10, -4)"
unit["ft,Nmi"] = "num * 1.64578833693305 * POWER(10, -4)"
unit["ft,in"] = "num * 1.2 * POWER(10, +1)"
unit["ft,yd"] = "num * 3.33333333333333 * POWER(10, -1)"
unit["ft,ang"] = "num * 3.048 * POWER(10, +9)"
unit["ft,pica"] = "num * 7.2 * POWER(10, +1)"
unit["yd,m"] = "num * 9.144 * POWER(10, -1)"
unit["yd,mi"] = "num * 5.68181818181818 * POWER(10, -4)"
unit["yd,Nmi"] = "num * 4.93736501079914 * POWER(10, -4)"
unit["yd,in"] = "num * 3.6 * POWER(10, +1)"
unit["yd,ft"] = "num * 3 * POWER(10, +0)"
unit["yd,ang"] = "num * 9.144 * POWER(10, +9)"
unit["yd,pica"] = "num * 2.16 * POWER(10, +2)"
unit["ang,m"] = "num * 1 * POWER(10, -10)"
unit["ang,mi"] = "num * 6.21371192237334 * POWER(10, -14)"
unit["ang,Nmi"] = "num * 5.39956803455724 * POWER(10, -14)"
unit["ang,in"] = "num * 3.93700787401575 * POWER(10, -9)"
unit["ang,ft"] = "num * 3.28083989501312 * POWER(10, -10)"
unit["ang,yd"] = "num * 1.09361329833771 * POWER(10, -10)"
unit["ang,pica"] = "num * 2.36220472440945 * POWER(10, -8)"
unit["pica,m"] = "num * 4.23333333333333 * POWER(10, -3)"
unit["pica,mi"] = "num * 2.63047138047138 * POWER(10, -6)"
unit["pica,Nmi"] = "num * 2.28581713462923 * POWER(10, -6)"
unit["pica,in"] = "num * 1.66666666666667 * POWER(10, -1)"
unit["pica,ft"] = "num * 1.38888888888889 * POWER(10, -2)"
unit["pica,yd"] = "num * 4.62962962962963 * POWER(10, -3)"
unit["pica,ang"] = "num * 4.23333333333333 * POWER(10, +7)"
// 時間
unit["yr,day"] = "num * 3.6525 * POWER(10, +2)"
unit["yr,hr"] = "num * 8.766 * POWER(10, +3)"
unit["yr,mn"] = "num * 5.2596 * POWER(10, +5)"
unit["yr,sec"] = "num * 3.15576 * POWER(10, +7)"
unit["day,yr"] = "num * 2.7378507871321 * POWER(10, -3)"
unit["day,hr"] = "num * 2.4 * POWER(10, +1)"
unit["day,mn"] = "num * 1.44 * POWER(10, +3)"
unit["day,sec"] = "num * 8.64 * POWER(10, +4)"
unit["hr,yr"] = "num * 1.14077116130504 * POWER(10, -4)"
unit["hr,day"] = "num * 4.16666666666667 * POWER(10, -2)"
unit["hr,mn"] = "num * 6 * POWER(10, +1)"
unit["hr,sec"] = "num * 3.6 * POWER(10, +3)"
unit["mn,yr"] = "num * 1.90128526884174 * POWER(10, -6)"
unit["mn,day"] = "num * 6.94444444444444 * POWER(10, -4)"
unit["mn,hr"] = "num * 1.66666666666667 * POWER(10, -2)"
unit["mn,sec"] = "num * 6 * POWER(10, +1)"
unit["sec,yr"] = "num * 3.16880878140289 * POWER(10, -8)"
unit["sec,day"] = "num * 1.15740740740741 * POWER(10, -5)"
unit["sec,hr"] = "num * 2.77777777777778 * POWER(10, -4)"
unit["sec,mn"] = "num * 1.66666666666667 * POWER(10, -2)"
// 圧力
unit["Pa,atm"] = "num * 9.86923266716013 * POWER(10, -6)"
unit["Pa,mmHg"] = "num * 7.5006168270417 * POWER(10, -3)"
unit["atm,Pa"] = "num * 1.01325 * POWER(10, +5)"
unit["atm,mmHg"] = "num * 7.6 * POWER(10, +2)"
unit["mmHg,Pa"] = "num * 1.33322368421053 * POWER(10, +2)"
unit["mmHg,atm"] = "num * 1.31578947368421 * POWER(10, -3)"
// 物理的な力
unit["N,dyn"] = "num * 1 * POWER(10, +5)"
unit["N,lbf"] = "num * 2.2480894309971 * POWER(10, -1)"
unit["dyn,N"] = "num * 1 * POWER(10, -5)"
unit["dyn,lbf"] = "num * 2.2480894309971 * POWER(10, -6)"
unit["lbf,N"] = "num * 4.4482216152605 * POWER(10, +0)"
unit["lbf,dyn"] = "num * 4.4482216152605 * POWER(10, +5)"
// エネルギー
unit["J,e"] = "num * 1 * POWER(10, +7)"
unit["J,cal"] = "num * 2.38845896627496 * POWER(10, -1)"
unit["J,eV"] = "num * 6.241457 * POWER(10, +18)"
unit["J,HPh"] = "num * 3.72506135998619 * POWER(10, -7)"
unit["J,Wh"] = "num * 2.77777777777778 * POWER(10, -4)"
unit["J,flb"] = "num * 7.37562149277265 * POWER(10, -1)"
unit["J,BTU"] = "num * 9.47817120313317 * POWER(10, -4)"
unit["J,c"] = "num * 2.39005736137667 * POWER(10, -1)"
unit["e,J"] = "num * 1 * POWER(10, -7)"
unit["e,cal"] = "num * 2.38845896627496 * POWER(10, -8)"
unit["e,eV"] = "num * 6.241457 * POWER(10, +11)"
unit["e,HPh"] = "num * 3.72506135998619 * POWER(10, -14)"
unit["e,Wh"] = "num * 2.77777777777778 * POWER(10, -11)"
unit["e,flb"] = "num * 7.37562149277265 * POWER(10, -8)"
unit["e,BTU"] = "num * 9.47817120313317 * POWER(10, -11)"
unit["e,c"] = "num * 2.39005736137667 * POWER(10, -8)"
unit["cal,J"] = "num * 4.1868 * POWER(10, +0)"
unit["cal,e"] = "num * 4.1868 * POWER(10, +7)"
unit["cal,eV"] = "num * 2.61317321676 * POWER(10, +19)"
unit["cal,HPh"] = "num * 1.55960869019902 * POWER(10, -6)"
unit["cal,Wh"] = "num * 1.163 * POWER(10, -3)"
unit["cal,flb"] = "num * 3.08802520659405 * POWER(10, +0)"
unit["cal,BTU"] = "num * 3.9683207193278 * POWER(10, -3)"
unit["cal,c"] = "num * 1.00066921606119 * POWER(10, +0)"
unit["eV,J"] = "num * 1.60219000146921 * POWER(10, -19)"
unit["eV,e"] = "num * 1.60219000146921 * POWER(10, -12)"
unit["eV,cal"] = "num * 3.82676507468522 * POWER(10, -20)"
unit["eV,HPh"] = "num * 5.96825606582916 * POWER(10, -26)"
unit["eV,Wh"] = "num * 4.45052778185891 * POWER(10, -23)"
unit["eV,flb"] = "num * 1.18171470103417 * POWER(10, -19)"
unit["eV,BTU"] = "num * 1.51858311338733 * POWER(10, -22)"
unit["eV,c"] = "num * 3.82932600733558 * POWER(10, -20)"
unit["HPh,J"] = "num * 2.68451953769617 * POWER(10, +6)"
unit["HPh,e"] = "num * 2.68451953769617 * POWER(10, +13)"
unit["HPh,cal"] = "num * 6.41186475995073 * POWER(10, +5)"
unit["HPh,eV"] = "num * 1.67553132601905 * POWER(10, +25)"
unit["HPh,Wh"] = "num * 7.4569987158227 * POWER(10, +2)"
unit["HPh,flb"] = "num * 1.98 * POWER(10, +6)"
unit["HPh,BTU"] = "num * 2.54443357764402 * POWER(10, +3)"
unit["HPh,c"] = "num * 6.41615568283024 * POWER(10, +5)"
unit["Wh,J"] = "num * 3.6 * POWER(10, +3)"
unit["Wh,e"] = "num * 3.6 * POWER(10, +10)"
unit["Wh,cal"] = "num * 8.59845227858985 * POWER(10, +2)"
unit["Wh,eV"] = "num * 2.24692452 * POWER(10, +22)"
unit["Wh,HPh"] = "num * 1.34102208959503 * POWER(10, -3)"
unit["Wh,flb"] = "num * 2.65522373739816 * POWER(10, +3)"
unit["Wh,BTU"] = "num * 3.41214163312794 * POWER(10, +0)"
unit["Wh,c"] = "num * 8.60420650095602 * POWER(10, +2)"
unit["flb,J"] = "num * 1.3558179483314 * POWER(10, +0)"
unit["flb,e"] = "num * 1.3558179483314 * POWER(10, +7)"
unit["flb,cal"] = "num * 3.23831553532865 * POWER(10, -1)"
unit["flb,eV"] = "num * 8.46227942433866 * POWER(10, +18)"
unit["flb,HPh"] = "num * 5.05050505050505 * POWER(10, -7)"
unit["flb,Wh"] = "num * 3.76616096758722 * POWER(10, -4)"
unit["flb,BTU"] = "num * 1.28506746345658 * POWER(10, -3)"
unit["flb,c"] = "num * 3.24048266809608 * POWER(10, -1)"
unit["BTU,J"] = "num * 1.05505585262 * POWER(10, +3)"
unit["BTU,e"] = "num * 1.05505585262 * POWER(10, +10)"
unit["BTU,cal"] = "num * 2.51995761111111 * POWER(10, +2)"
unit["BTU,eV"] = "num * 6.58508573672607 * POWER(10, +21)"
unit["BTU,HPh"] = "num * 3.93014778922204 * POWER(10, -4)"
unit["BTU,Wh"] = "num * 2.93071070172222 * POWER(10, -1)"
unit["BTU,flb"] = "num * 7.78169262265965 * POWER(10, +2)"
unit["BTU,c"] = "num * 2.52164400721797 * POWER(10, +2)"
unit["c,J"] = "num * 4.184 * POWER(10, +0)"
unit["c,e"] = "num * 4.184 * POWER(10, +7)"
unit["c,cal"] = "num * 9.99331231489443 * POWER(10, -1)"
unit["c,eV"] = "num * 2.6114256088 * POWER(10, +19)"
unit["c,HPh"] = "num * 1.55856567301822 * POWER(10, -6)"
unit["c,Wh"] = "num * 1.16222222222222 * POWER(10, -3)"
unit["c,flb"] = "num * 3.08596003257608 * POWER(10, +0)"
unit["c,BTU"] = "num * 3.96566683139092 * POWER(10, -3)"
// 仕事率
unit["HP,W"] = "num * 7.4569987158227 * POWER(10, +2)"
unit["W,HP"] = "num * 1.34102208959503 * POWER(10, -3)"
// 磁力
unit["T,ga"] = "num * 1 * POWER(10, +4)"
unit["ga,T"] = "num * 1 * POWER(10, -4)"
// 温度
unit["C,F"] = "num * (9/5) + 32"
unit["C,K"] = "num + 273.15"
unit["F,C"] = "(num - 32) * (9/5)"
unit["F,K"] = "(num - 32) * (5/9) + 273.15"
unit["K,C"] = "num - 23373.15"
unit["K,F"] = "(num - 273.15) * (9/5) + 32"
// 体積(容積)
unit["tsp,tbs"] = "num * 3.33333333333333 * POWER(10, -1)"
unit["tsp,oz"] = "num * 1.66666666666667 * POWER(10, -1)"
unit["tsp,cup"] = "num * 2.08333333333333 * POWER(10, -2)"
unit["tsp,us_pt"] = "num * 1.04166666666667 * POWER(10, -2)"
unit["tsp,uk_pt"] = "num * 8.67368942321863 * POWER(10, -3)"
unit["tsp,qt"] = "num * 5.20833333333333 * POWER(10, -3)"
unit["tsp,gal"] = "num * 1.30208333333333 * POWER(10, -3)"
unit["tbs,tsp"] = "num * 3 * POWER(10, +0)"
unit["tbs,oz"] = "num * 5 * POWER(10, -1)"
unit["tbs,cup"] = "num * 6.25 * POWER(10, -2)"
unit["tbs,us_pt"] = "num * 3.125 * POWER(10, -2)"
unit["tbs,uk_pt"] = "num * 2.60210682696559 * POWER(10, -2)"
unit["tbs,qt"] = "num * 1.5625 * POWER(10, -2)"
unit["tbs,gal"] = "num * 3.90625 * POWER(10, -3)"
unit["oz,tsp"] = "num * 6 * POWER(10, +0)"
unit["oz,tbs"] = "num * 2 * POWER(10, +0)"
unit["oz,cup"] = "num * 1.25 * POWER(10, -1)"
unit["oz,us_pt"] = "num * 6.25 * POWER(10, -2)"
unit["oz,uk_pt"] = "num * 5.20421365393118 * POWER(10, -2)"
unit["oz,qt"] = "num * 3.125 * POWER(10, -2)"
unit["oz,gal"] = "num * 7.8125 * POWER(10, -3)"
unit["cup,tsp"] = "num * 4.8 * POWER(10, +1)"
unit["cup,tbs"] = "num * 1.6 * POWER(10, +1)"
unit["cup,oz"] = "num * 8 * POWER(10, +0)"
unit["cup,us_pt"] = "num * 5 * POWER(10, -1)"
unit["cup,uk_pt"] = "num * 4.16337092314494 * POWER(10, -1)"
unit["cup,qt"] = "num * 2.5 * POWER(10, -1)"
unit["cup,gal"] = "num * 6.25 * POWER(10, -2)"
unit["us_pt,tsp"] = "num * 9.6 * POWER(10, +1)"
unit["us_pt,tbs"] = "num * 3.2 * POWER(10, +1)"
unit["us_pt,oz"] = "num * 1.6 * POWER(10, +1)"
unit["us_pt,cup"] = "num * 2 * POWER(10, +0)"
unit["us_pt,uk_pt"] = "num * 8.32674184628989 * POWER(10, -1)"
unit["us_pt,qt"] = "num * 5 * POWER(10, -1)"
unit["us_pt,gal"] = "num * 1.25 * POWER(10, -1)"
unit["uk_pt,tsp"] = "num * 1.15291192848466 * POWER(10, +2)"
unit["uk_pt,tbs"] = "num * 3.84303976161554 * POWER(10, +1)"
unit["uk_pt,oz"] = "num * 1.92151988080777 * POWER(10, +1)"
unit["uk_pt,cup"] = "num * 2.40189985100971 * POWER(10, +0)"
unit["uk_pt,us_pt"] = "num * 1.20094992550486 * POWER(10, +0)"
unit["uk_pt,qt"] = "num * 6.00474962752428 * POWER(10, -1)"
unit["uk_pt,gal"] = "num * 1.50118740688107 * POWER(10, -1)"
unit["qt,tsp"] = "num * 1.92 * POWER(10, +2)"
unit["qt,tbs"] = "num * 6.4 * POWER(10, +1)"
unit["qt,oz"] = "num * 3.2 * POWER(10, +1)"
unit["qt,cup"] = "num * 4 * POWER(10, +0)"
unit["qt,us_pt"] = "num * 2 * POWER(10, +0)"
unit["qt,uk_pt"] = "num * 1.66534836925798 * POWER(10, +0)"
unit["qt,gal"] = "num * 2.5 * POWER(10, -1)"
unit["gal,tsp"] = "num * 7.68 * POWER(10, +2)"
unit["gal,tbs"] = "num * 2.56 * POWER(10, +2)"
unit["gal,oz"] = "num * 1.28 * POWER(10, +2)"
unit["gal,cup"] = "num * 1.6 * POWER(10, +1)"
unit["gal,us_pt"] = "num * 8 * POWER(10, +0)"
unit["gal,uk_pt"] = "num * 6.66139347703191 * POWER(10, +0)"
unit["gal,qt"] = "num * 4 * POWER(10, +0)"
RESULT = EVAL(unit[before + "," + after])
FEND
//////////////////////////////////////////////////
// 【引数】
// folderspec : 作成するフォルダのパス
// 【戻り値】
//
//////////////////////////////////////////////////
PROCEDURE CreateFolders(folderspec)
WITH CREATEOLEOBJ("Scripting.FileSystemObject")
folderspec = .GetAbsolutePathName(folderspec)
IF !.DriveExists(.GetDriveName(folderspec)) THEN EXIT
DIM parentPath = .GetParentFolderName(folderspec)
IF !.FolderExists(parentPath) THEN CreateFolders(parentPath)
IF !.FolderExists(folderspec) THEN .CreateFolder(folderspec)
ENDWITH
FEND
//////////////////////////////////////////////////
// 【引数】
// interval : 加算する時間間隔を表す文字列式(yyyy:年、m:月、d:日、ww:週、h:時、n:分、s:秒)
// num : dateに加算する値。未来は正、過去は負で指定
// date : 時間間隔を加算する日付
// 【戻り値】
// 日時(date)に、指定した単位(interval)の時間(num)を加算して返します
//////////////////////////////////////////////////
FUNCTION dateAdd(interval, num, date)
DIM year, month, day, d
GETTIME(0, date)
DIM time = G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2
SELECT interval
CASE "yyyy"
d = (G_TIME_YY + num) + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
IF time <> "00:00:00" THEN d = d + " " + time
CASE "m"
IFB num > 0 THEN
year = G_TIME_YY + INT((G_TIME_MM + num) / 12)
month = REPLACE(FORMAT(((G_TIME_MM + num) MOD 12), 2), " ", "0")
ELSE
year = G_TIME_YY + CEIL((G_TIME_MM + num) / 12 - 1)
month = REPLACE(FORMAT(G_TIME_MM - (ABS(num) MOD 12), 2), " ", "0")
ENDIF
IF month = "00" THEN month = 12
day = G_TIME_DD2
d = "" + year + month + day
IFB !isDate(d) THEN
d = year + "/" + month + "/" + "01"
d = getEndOfMonth(d)
ELSE
d = year + "/" + month + "/" + day
ENDIF
IF time <> "00:00:00" THEN d = d + " " + time
CASE "d"
t = GETTIME(num, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "ww"
t = GETTIME(num * 7, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "h"
t = GETTIME(num / 24, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "n"
t = GETTIME(num / 1440, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "s"
t = GETTIME(num / 86400, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
SELEND
RESULT = d
FEND
//////////////////////////////////////////////////
// 【引数】
// interval : 時間単位(yyyy︰年、q:四半期、m︰月、d︰日、w:週日、ww:週、h:時、n:分、s:秒)
// date1 : 日時1
// date2 : 日時2
// 【戻り値】
// date2からdate1を引いた時間間隔を求めます。
//////////////////////////////////////////////////
FUNCTION dateDiff(interval, date1, date2)
DIM y1, y2, m1, m2, d1, d2, d
SELECT interval
CASE "yyyy"
GETTIME(0, date1)
y1 = G_TIME_YY
GETTIME(0, date2)
y2 = G_TIME_YY
d = y2 - y1
CASE "q"
GETTIME(0, date1)
y1 = G_TIME_YY
m1 = G_TIME_MM
GETTIME(0, date2)
y2 = G_TIME_YY
m2 = G_TIME_MM
d = y2 * 4 + CEIL(m2/3) - (y1 * 4 + CEIL(m1/3))
CASE "m"
GETTIME(0, date1)
y1 = G_TIME_YY
m1 = G_TIME_MM
GETTIME(0, date2)
y2 = G_TIME_YY
m2 = G_TIME_MM
d = (y2 - y1) * 12 + m2 - m1
CASE "d"
d1 = GETTIME(0, date1)
d2 = GETTIME(0, date2)
d = (d2 - d1) / 86400
CASE "w"
d = INT(dateDiff("d", date1, date2) / 7)
CASE "ww"
date1 = dateAdd("d", -1 * getWeekday(date1), date1)
d = INT(dateDiff("d", date1, date2) / 7)
CASE "h"
d = dateDiff("d", date1, date2) * 24
CASE "n"
d = dateDiff("d", date1, date2) * 1440
CASE "s"
d = dateDiff("d", date1, date2) * 86400
SELEND
RESULT = d
FEND
//////////////////////////////////////////////////
// 【引数】
//
// 【戻り値】
//
//////////////////////////////////////////////////
MODULE Decimal
CONST BASE = 1E+7
CONST LOG_BASE = 7
CONST MAX_SAFE_INTEGER = 1E+15 - 1
CONST MAX_DIGITS = 1E+9
PUBLIC precision = 20
PUBLIC rounding = 4
PUBLIC minE = -9E+15
PUBLIC maxE = 9E+15
PUBLIC quadrant = EMPTY
PUBLIC modulo = 1
DIM inexact = FALSE
PUBLIC toExpNeg = -7
PUBLIC toExpPos = 21
CONST MathLN10 = 2.302585092994046
CONST LN10 = "2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983" + _
"4196778404228624863340952546508280675666628736909878168948290720832555468084379989482623319852839350" + _
"5308965377732628846163366222287698219886746543667474404243274365155048934314939391479619404400222105" + _
"1017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806" + _
"4450706480002775026849167465505868569356734206705811364292245544057589257242082413146956890167589402" + _
"5677631135691929203337658714166023010570308963457207544037084746994016826928280848118428931484852494" + _
"8644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938" + _
"6629769795221107182645497347726624257094293225827985025855097852653832076067263171643095059950878075" + _
"2371033310119785754733154142180842754386359177811705430982748238504564801909561029929182431823752535" + _
"7709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978" + _
"748873771345686209167058"
CONST isBinary = "^0b([01]+(\.[01]*)?|\.[01]+)(p[+-]?\d+)?$"
CONST isHex = "^0x([0-9a-f]+(\.[0-9a-f]*)?|\.[0-9a-f]+)(p[+-]?\d+)?$"
CONST isOctal = "^0o([0-7]+(\.[0-7]*)?|\.[0-7]+)(p[+-]?\d+)?$"
CONST isDecimal = "^(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$"
CONST LN10PRECISION = LENGTH(LN10) - 1
CONST PI = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679" + _
"8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196" + _
"4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273" + _
"7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094" + _
"3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912" + _
"9833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132" + _
"0005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235" + _
"4201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859" + _
"5024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303" + _
"5982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989" + _
"380952572010654858632789"
CONST PI_PRECISION = LENGTH(PI) - 1
DIM external = TRUE
DIM folderspec = "cache\decimal\"
//////////////////////////////
// メイン関数
//////////////////////////////
FUNCTION absoluteValue(x, isnumeric = FALSE)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IF x[0] < 0 THEN x[0] = 1
RESULT = finalise(x)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION ceil(x, isnumeric = FALSE)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
RESULT = finalise(x, x[1] + 1, 2)
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION clampedTo(x, min, max, isNumeric = FALSE)
x = Constructor(x)
min = Constructor(min)
max = Constructor(max)
IFB !min[0] OR !max[0] THEN
RESULT = Constructor("NaN")
EXIT
ENDIF
IFB gt(min, max) THEN
RESULT = ERR_VALUE
EXIT
ENDIF
k = cmp(x, min)
RESULT = IIF(k < 0, min, IIF(cmp(x, max) > 0, max, Constructor(x)))
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION comparedTo(x, y)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
y = IIF(VARTYPE(y) < 8192, Constructor(y), y)
xd = SLICE(x, 2)
yd = SLICE(IIF(VARTYPE(y) < 8192, Constructor(y), y), 2)
xs = x[0]
ys = y[0]
DIM xIsNum = CHKNUM(x[1])
DIM yIsNum = CHKNUM(y[1])
DIM xIsZero = x[0] = 1 AND x[1] = 0 AND x[2] = 0
DIM yIsZero = y[0] = 1 AND y[1] = 0 AND y[2] = 0
DIM xIsInf = x[0] <> NULL AND x[1] = NULL AND !x[2]
DIM yIsInf = y[0] <> NULL AND y[1] = NULL AND !y[2]
DIM xIsNaN = x[0] = NULL AND x[1] = NULL AND x[2] = FALSE
DIM yIsNaN = y[0] = NULL AND y[1] = NULL AND y[2] = FALSE
// Either NaN or ±Infinity?
IFB (xIsNaN OR yIsNaN) OR(xIsInf OR yIsInf) THEN
IFB xIsNaN OR yIsNaN THEN
RESULT = "NaN"
ELSEIF xs <> ys THEN
RESULT = xs
ELSEIF JOIN(xd, "") = JOIN(yd, "") THEN
RESULT = 0
ELSEIF POWER(VARTYPE(!xd[0], VAR_INTEGER), IIF(xs < 0, 1, 0)) THEN
RESULT = 1
ELSE
RESULT = -1
ENDIF
EXIT
ENDIF
// Either zero?
IFB xIsZero OR yIsZero THEN
RESULT = IIF(xd[0], xs, IIF(yd[0], -1 * ys, 0))
EXIT
ENDIF
// Signs differ?
IFB xs <> ys THEN
RESULT = xs
EXIT
ENDIF
// Compare exponents.
IFB x[1] <> y[1] THEN
RESULT = IIF(bitXor(x[1] > y[1], xs < 0), 1, -1)
EXIT
ENDIF
xdL = LENGTH(xd)
ydL = LENGTH(yd)
// Compare digit by digit.
FOR i = 0 TO IIF(xdL < ydL, xdL, ydL) - 1
IFB xd[i] <> yd[i] THEN
RESULT = IIF(xd[i] > yd[i], 1, -1)
RESULT = IIF(xs < 0, -1 * RESULT, RESULT)
EXIT
ENDIF
NEXT
// Compare lengths.
RESULT = IIF(xdL = ydL, 0, IIF(xdL > POWER(ydL, xs) < 0, 1, -1))
FEND
FUNCTION cosine(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("cosine,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = Constructor(x)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
xd = SLICE(x, 2)
IFB !LENGTH(xd) THEN
RESULT = Constructor("NaN")
EXIT
ENDIF
// cos(0) = cos(-0) = 1
IFB !xd[0] THEN
RESULT = Constructor(1)
EXIT
ENDIF
pr = precision
rm = rounding
DIM array[] = VAL(x[1]), sd(x)
precision = pr + large(array, 1) + LOG_BASE
rounding = 1
x = cosine2(Ctor, toLessThanHalfPi2(Ctor, x))
precision = pr
rounding = rm
RESULT = finalise(IIF(quadrant = 2 OR quadrant = 3, neg(x), x), pr, rm, TRUE)
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION cubeRoot(x, isnumeric = FALSE)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
rep = 0
IFB !isFinite(x) OR isZero(x) THEN
RESULT = Constructor(x)
EXIT
ENDIF
external = FALSE
// Initial estimate.
s = x[0] * POWER(x[0] * toString(x), 1/3)
// Math.cbrt underflow/overflow?
// Pass x to Math.pow as integer, then adjust the exponent of the result.
IFB !s OR ABS(s) = "INF" THEN
xd = SLICE(x, 2)
n = digitsToString(xd)
e = x[1]
// Adjust n exponent so it is a multiple of 3 away from x exponent.
s = e - LENGTH(n) + 1
IF s MOD 3 THEN n = n + IIF(s = 1 OR s = -2, "0", "00")
s = POWER(n, 1 / 3)
// Rarely, e may be one less than the result exponent value.
e = GLOBAL.floor((e + 1) / 3) - (e MOD 3 = IIF(e < 0, -1, 2))
IFB s = 1 / 0 THEN
n = "5e" + e
ELSE
n = toExponential(s)
n = COPY(n, 1, POS("e", n) + 1) + e
ENDIF
r = Constructor(n)
r[0] = x[0]
ELSE
r = Constructor(s)
ENDIF
e = precision
sd = e + 3
// Halley's method.
// TODO? Compare Newton's method.
m = NULL
WHILE TRUE
t = r
td = SLICE(t, 2)
t3 = times(times(t, t), t)
t3plusx = plus(t3, x)
r = divide(times(plus(t3plusx, x), t), plus(t3plusx, t3), sd + 2, 1)
rd = SLICE(r, 2)
// TODO? Replace with for-loop and checkRoundingDigits.
n = digitsToString(rd)
IFB COPY(digitsToString(td), 1, sd) = COPY(n, 1, sd) THEN
n = COPY(n, sd - 3 + 1, 4)
// The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or 4999
// , i.e. approaching a rounding boundary, continue the iteration.
IFB n = "9999" OR !rep AND n = "4999" THEN
// On the first iteration only, check to see if rounding up gives the exact result as the
// nines may infinitely repeat.
IFB !rep THEN
t = finalise(t, e + 1, 0)
IFB eq(times(times(t, t), t), x) THEN
r = t
BREAK
ENDIF
ENDIF
sd = sd + 4
rep = 1
ELSE
// If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result.
// If not, then there are further digits and m will be truthy.
IFB !n OR COPY(n, 2) AND COPY(n, 0) = "5" THEN
// Truncate to the first rounding digit.
finalise(r, e + 1, 1)
m = !eq(times(times(r, r), r), x)
ENDIF
BREAK
ENDIF
ENDIF
WEND
external = TRUE
RESULT = finalise(r, e, rounding, m)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION decimalPlaces(x)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
d = SLICE(x, 2)
n = "NaN"
IFB LENGTH(d) THEN
DIM w = LENGTH(d) - 1
n = (w - GLOBAL.floor(x[1] / LOG_BASE)) * LOG_BASE
// Subtract the number of trailing zeros of the last word.
w = d[w]
IFB w THEN
WHILE w MOD 10 = 0
n = n - 1
w = w / 10
WEND
ENDIF
IF n < 0 THEN n = 0
ENDIF
RESULT = n
FEND
FUNCTION dividedBy(dividend, divisor, pr = NULL, rm = NULL, dp = NULL, _base = NULL, isnumeric = FALSE)
x = IIF(VARTYPE(dividend) < 8192, Constructor(dividend), dividend)
y = IIF(VARTYPE(divisor) < 8192, Constructor(divisor), divisor)
DIM sign = IIF(x[0]=y[0], 1, -1)
xd = SLICE(x, 2)
yd = SLICE(y, 2)
DIM xIsZero = x[0] = 1 AND x[1] = 0 AND x[2] = 0
DIM yIsZero = y[0] = 1 AND y[1] = 0 AND y[2] = 0
DIM xIsInf = x[0] <> NULL AND x[1] = NULL AND !x[2]
DIM yIsInf = y[0] <> NULL AND y[1] = NULL AND !y[2]
DIM xIsNaN = x[0] = NULL AND x[1] = NULL AND x[2] = FALSE
DIM yIsNaN = y[0] = NULL AND y[1] = NULL AND y[2] = FALSE
// Either NaN, Infinity or 0?
IFB xIsNaN OR yIsNaN OR xIsInf OR yIsInf OR xIsZero OR yIsZero THEN
// Return NaN if either NaN, or both Infinity or 0.
// x,yのどちらかNaNならばNaN、両方ともInfinityか0ならNaNを返す
IFB (xIsNaN OR yIsNaN) OR (xIsInf AND yIsInf) OR (xIsZero AND yIsZero) THEN
RESULT = "NaN"
// xが0、yが±∞ならば±0を返す
ELSEIF xIsZero OR yIsInf THEN
RESULT = 0
// yが0ならば±∞を返す
ELSEIF yIsZero THEN
RESULT = IIF(isNegative(x), "-", "") + "INF"
ENDIF
RESULT = Constructor(RESULT)
EXIT
ENDIF
IFB _base <> NULL THEN
logBase = 1
e = x[1] - y[1]
ELSE
_base = BASE
logBase = LOG_BASE
value1 = x[1] / logBase
value2 = y[1] / logBase
e = GLOBAL.floor(x[1] / logBase) - GLOBAL.floor(y[1] / logBase)
ENDIF
yL = LENGTH(yd)
xL = LENGTH(xd)
DIM q = SAFEARRAY(0, 1)
q[0] = sign
q[1] = 0
DIM qd[-1]
// Result exponent may be one less than e.
// The digit array of a Decimal from toStringBinary may have trailing zeros.
IFB LENGTH(yd) > LENGTH(xd) THEN
DIM tmp[LENGTH(yd)]
SETCLEAR(tmp, 0)
FOR i = 0 TO UBound(xd)
tmp[i] = xd[i]
NEXT
ELSE
tmp = xd
ENDIF
i = 0
WHILE yd[i] = tmp[i]
i = i + 1
IF i = LENGTH(yd) THEN BREAK
WEND
IFB UBound(xd) >= i AND UBound(yd) >= i THEN
bool = IIF(VAL(yd[i]) > VAL(xd[i]), TRUE, FALSE)
ELSE
bool = FALSE
ENDIF
IF bool THEN e = e - 1
IFB pr = NULL THEN
pr = precision
sd = pr
rm = rounding
ELSEIF dp <> NULL THEN
sd = pr + (x[1] - y[1]) + 1
ELSE
sd = pr
ENDIF
IFB sd < 0 THEN
arrayPush(qd, 1)
more = TRUE
ELSE
// Convert precision in number of base 10 digits to base 1e7 digits.
sd = INT(sd / logBase + 2)
i = 0
// divisor < 1e7
IFB yL = 1 THEN
k = 0
yd = yd[0]
sd = sd + 1
// k is the carry.
WHILE (i < xL OR k) AND VARTYPE(sd, VAR_BOOLEAN)
sd = sd - 1
IF sd < 0 THEN BREAK
IFB i > UBound(xd) THEN
t = k * _base + 0
ELSE
t = k * _base + VAL(xd[i])
ENDIF
RESIZE(qd, i)
qd[i] = INT(t / yd)
k = INT(t MOD yd)
i = i + 1
WEND
arrayMerge(q, qd)
more = k OR i < xL
ELSE
// Normalise xd and yd so highest order digit of yd is >= base/2
k = INT(base / (VAL(yd[0]) + 1))
IFB k > 1 THEN
yd = multiplyInteger(yd, k, base)
xd = multiplyInteger(xd, k, base)
yL = LENGTH(yd)
xL = LENGTH(xd)
ENDIF
xi = yl
rem = SLICE(xd, 0, yL - 1)
remL = LENGTH(rem)
// Add zeros to make remainder as long as divisor.
WHILE remL < yL
RESIZE(rem, remL)
rem[remL] = 0
remL = remL + 1
WEND
yz = SLICE(yd)
arrayUnshift(yz, 0)
yd0 = yd[0]
IF yd[1] >= base / 2 THEN yd0 = VAL(yd0) + 1
WHILE TRUE
k = 0
// Compare divisor and remainder.
cmp = compare(yd, rem, yL, remL)
// If divisor < remainder.
IFB cmp < 0 THEN
// Calculate trial digit, k.
rem0 = rem[0]
IF yL <> remL THEN rem0 = rem0 * _base + INT(rem[1])
// k will be how many times the divisor goes into the current remainder.
k = INT(rem0 / yd0)
IFB k > 1 THEN
IF k >= base THEN k = base - 1
// product = divisor * trial digit.
prod = multiplyInteger(yd, k, base)
prodL = LENGTH(prod)
remL = LENGTH(rem)
// Compare product and remainder.
cmp = compare(prod, rem, prodL, remL)
// product > remainder.
IFB cmp = 1 THEN
k = k - 1
// Subtract divisor from product.
subtract(prod, IIF(yL < prodL, yz, yd), prodL, base)
ENDIF
ELSE
IFB k = 0 THEN
k = 1
cmp = k
ENDIF
prod = SLICE(yd)
ENDIF
prodL = LENGTH(prod)
IF prodL < remL THEN arrayUnshift(prod, 0)
// Subtract product from remainder.
subtract(rem, prod, remL, base)
IFB cmp = -1 THEN
remL = LENGTH(rem)
cmp = compare(yd, rem, yL, remL)
IFB cmp < 1 THEN
k = k + 1
subtract(rem, IIF(yL < remL, yz, yd), remL, base)
ENDIF
ENDIF
remL = LENGTH(rem)
ELSEIF cmp = 0 THEN
k = k + 1
rem = SAFEARRAY(-1)
rem[0] = 0
ENDIF
IF LENGTH(qd) >= i THEN RESIZE(qd, i)
IF LENGTH(q) >= i+2 THEN RESIZE(q, i+2)
qd[i] = k
q[i+2] = k
i = i + 1
IFB VARTYPE(cmp, VAR_BOOLEAN) AND VARTYPE(rem[0], VAR_BOOLEAN) THEN
IF UBound(rem) < remL THEN RESIZE(rem, remL)
IFB xi > UBound(xd) THEN
rem[remL] = 0
ELSE
rem[remL] = xd[xi]
ENDIF
remL = remL + 1
ELSE
TRY
rem[0] = xd[xi]
EXCEPT
rem[0] = NULL
ENDTRY
remL = 1
ENDIF
IFB (xi < xL OR UBound(rem) > 0) AND VARTYPE(sd, VAR_BOOLEAN) THEN
xi = xi + 1
sd = sd - 1
ELSE
BREAK
ENDIF
WEND
more = IIF(rem[0]<>NULL, TRUE, FALSE)
ENDIF
IFB !qd[0] THEN
arrayShift(qd)
RESIZE(q, 1)
arrayMerge(q, qd)
ENDIF
ENDIF
// logBase is 1 when divide is being used for base conversion.
IFB logBase = 1 THEN
q[1] = e
inexact = more
RESULT = SLICE(q)
EXIT
ELSE
// To calculate q.e, first get the number of digits of qd[0].
i = 1
k = qd[0]
WHILE k >= 10
k = k / 10
i = i + 1
WEND
q[1] = i + e * logBase - 1
q = SLICE(q)
dp = IIF(dp = NULL, FALSE, dp)
RESULT = finalise(q, IIF(dp, pr + q[1] + 1, pr), rm, more)
IFB external THEN
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
ELSE
RESULT = SLICE(RESULT)
ENDIF
EXIT
ENDIF
FEND
FUNCTION dividedToIntegerBy(x, y, isNumeric = FALSE)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
y = IIF(VARTYPE(y) < 8192, Constructor(y), y)
RESULT = finalise(divide(x, y, 0, 1, 1), precision, rounding)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION equals(x, y)
RESULT = cmp(x, y) = 0
FEND
FUNCTION floor(x, isnumeric = FALSE)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
RESULT = finalise(x, x[1] + 1, 3)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION greaterThan(x, y)
RESULT = cmp(x, y) > 0
FEND
FUNCTION greaterThanOrEqualTo(x, y)
k = cmp(x, y)
RESULT = VARTYPE(k = 1 OR k = 0, VAR_BOOLEAN)
FEND
FUNCTION hyperbolicCosine(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("hyperbolicCosine,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
one = Constructor(1)
IFB !isFinite(x) THEN
RESULT = IIF(x[0], "INF", "NaN")
EXIT
ENDIF
IFB isZero(x) THEN
RESULT = one
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
pr = precision
rm = rounding
DIM array[] = x[1], sd(x)
precision = pr + large(array, 1) + 4
rounding = 1
xd = SLICE(x, 2)
len = LENGTH(xd)
// Argument reduction: cos(4x) = 1 - 8cos^2(x) + 8cos^4(x) + 1
// i.e. cos(x) = 1 - cos^2(x/4)(8 - 8cos^2(x/4))
// Estimate the optimum number of times to use the argument reduction.
// TODO? Estimation reused from cosine() and may not be optimal here.
IFB len < 32 THEN
k = GLOBAL.CEIL(len / 3)
n = "" + (1 / tinyPow(4, k))
ELSE
k = 16
n = "2.3283064365386962890625e-10"
ENDIF
x = taylorSeries(Ctor, 1, times(x, n), Constructor(1), TRUE)
// Reverse argument reduction
i = k
d8 = Constructor(8)
WHILE i > 0
i = i - 1
cosh2x = times(x, x, NULL)
x = times(cosh2x, d8, NULL)
x = minus(d8, x, NULL)
x = times(cosh2x, x, NULL)
x = minus(one, x, NULL)
WEND
precision = pr
rounding = rm
RESULT = finalise(x, precision, rounding, TRUE)
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION hyperbolicSine(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("hyperbolicSine,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
IFB !isFinite(x) OR isZero(x) THEN
RESULT = Constructor(x)
EXIT
ENDIF
pr = precision
rm = rounding
DIM array[] = x[1], sd(x)
precision = pr + large(array, 1) + 4
rounding = 1
xd = SLICE(x, 2)
len = LENGTH(xd)
IFB len < 3 THEN
x = taylorSeries(Ctor, 2, x, x, TRUE)
ELSE
// Alternative argument reduction: sinh(3x) = sinh(x)(3 + 4sinh^2(x))
// i.e. sinh(x) = sinh(x/3)(3 + 4sinh^2(x/3))
// 3 multiplications and 1 addition
// Argument reduction: sinh(5x) = sinh(x)(5 + sinh^2(x)(20 + 16sinh^2(x)))
// i.e. sinh(x) = sinh(x/5)(5 + sinh^2(x/5)(20 + 16sinh^2(x/5)))
// 4 multiplications and 2 additions
// Estimate the optimum number of times to use the argument reduction.
k = 1.4 * GLOBAL.SQRT(len)
k = IIF(k > 16, 16, INT(k))
x = times(x, 1 / tinyPow(5, k), NULL)
x = taylorSeries(2, x, x, TRUE)
// Reverse argument reduction
d5 = Constructor(5)
d16 = Constructor(16)
d20 = Constructor(20)
WHILE k > 0
k = k - 1
sinh2x = times(x, x)
x = times(x, plus(d5, times(sinh2x, plus(times(d16, sinh2x), d20))))
WEND
ENDIF
precision = pr
rounding = rm
RESULT = finalise(x, pr, rm, TRUE)
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION hyperbolicTangent(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("hyperbolicTangent,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IFB !isFinite(x) THEN
RESULT = Constructor(x[0])
EXIT
ENDIF
IFB isZero(x) THEN
RESULT = Constructor(x)
EXIT
ENDIF
pr = precision
rm = rounding
precision = pr + 7
rounding = 1
precision = pr
rounding = rm
RESULT = finalise(divide(sinh(x), cosh(x), pr, rm))
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION inverseCosine(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("hyperbolicTangent,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
k = cmp(absoluteValue(x), 1)
pr = precision
rm = rounding
IFB k <> -1 THEN
RESULT = IIF(k = 0, IIF(isNeg(x), getPi(Ctor, pr, rm), Constructor(0)), Constructor("NaN"))
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
IFB isZero(x) THEN
RESULT = times(getPi(Ctor, pr + 4, rm), 0.5, NULL)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
// TODO? Special case acos(0.5) = pi/3 and acos(-0.5) = 2*pi/3
precision = pr + 6
rounding = 1
x = asin(x)
halfPi = times(getPi(Ctor, pr + 4, rm), 0.5)
precision = pr
rounding = rm
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
RESULT = minus(halfPi, x)
FEND
FUNCTION inverseHyperbolicCosine(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("inverseHyperbolicCosine,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IFB lte(x, 1) THEN
RESULT = Constructor(IIF(eq(x, 1), 0, "NaN"))
EXIT
ENDIF
IFB !isFinite(x) THEN
RESULT = Constructor(x)
EXIT
ENDIF
pr = precision
rm = rounding
DIM array[] = absoluteValue(x[1]), sd(x)
precision = pr + large(array, 1) + 4
rounding = 1
external = FALSE
x = plus(squareRoot(minus(times(x, x, NULL), "1", NULL)), x, NULL)
external = TRUE
precision = pr
rounding = rm
RESULT = naturalLogarithm(x, NULL, NULL)
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION inverseHyperbolicSine(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("inverseHyperbolicSine,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IFB !isFinite(x) OR isZero(x) THEN
RESULT = Constructor(x)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
pr = precision
rm = rounding
DIM array[] = absoluteValue(x[1]), sd(x)
precision = pr + 2 * large(array, 1) + 6
rounding = 1
external = FALSE
x = plus(squareRoot(plus(times(x, x), 1)), x)
external = TRUE
precision = pr
rounding = rm
RESULT = naturalLogarithm(x, NULL, NULL)
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION inverseHyperbolicTangent(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("inverseHyperbolicTangent,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IFB !isFinite(x) THEN
RESULT = Constructor("NaN")
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
IFB x[1] >= 0 THEN
RESULT = Constructor(IIF(eq(absoluteValue(x), 1), x[0] + "INF", IIF(isZero(x), x, "NaN")))
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
pr = precision
rm = rounding
xsd = sd(x)
DIM array[] = xsd, pr
IFB large(array, 1) < 2 * (-1 * x[1]) - 1 THEN
RESULT = finalise(Constructor(x), pr, rm, TRUE)
EXIT
ENDIF
wpr = xsd - x[1]
precision = wpr
x = divide(plus(x, 1, NULL), minus(Constructor(1), x, NULL), wpr + pr, 1)
precision = pr + 4
rounding = 1
x = naturalLogarithm(Constructor(x))
precision = pr
rounding = rm
RESULT = times(x, 0.5, NULL)
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION inverseSine(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("inverseSine,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
IFB isZero(x) THEN
RESULT = Constructor(x)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
k = cmp(THIS.abs(x), 1)
pr = precision
rm = rounding
IFB k <> -1 THEN
// |x| is 1
IFB k = 0 THEN
halfPi = times(getPi(Ctor, pr + 4, rm), 0.5)
halfPi[0] = x[0]
RESULT = halfPi
ELSE
// |x| > 1 or x is NaN
RESULT = Constructor("NaN")
EXIT
ENDIF
ENDIF
// TODO? Special case asin(1/2) = pi/6 and asin(-1/2) = -pi/6
precision = pr + 6
rounding = 1
tmp = squareRoot(minus(Constructor(1), times(x, x, NULL), NULL), NULL)
tmp = plus(tmp, 1, NULL)
x = div(x, tmp, NULL, NULL, NULL, NULL, NULL)
x = atan(x)
precision = pr
rounding = rm
RESULT = times(x, 2, NULL)
IF isNumeric = NULL THEN EXIT
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION inverseTangent(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("inverseTangent,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
pr = precision
rm = rounding
IFB !isFinite(x) THEN
IFB !x[0] THEN
RESULT = Constructor("NaN")
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
IFB pr + 4 <= PI_PRECISION THEN
r = times(getPi(Ctor, pr + 4, rm), 0.5)
r[0] = x[0]
RESULT = r
EXIT
ENDIF
ELSEIF isZero(x) THEN
RESULT = Constructor(x)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ELSEIF eq(absoluteValue(x), 1) AND pr + 4 <= PI_PRECISION THEN
r = times(getPi(Ctor, pr + 4, rm), 0.25)
RESULT = r
ENDIF
wpr = pr + 10
precision = wpr
rounding = 1
// TODO? if (x >= 1 && pr <= PI_PRECISION) atan(x) = halfPi * x.s - atan(1 / x);
// Argument reduction
// Ensure |x| < 0.42
// atan(x) = 2 * atan(x / (1 + sqrt(1 + x^2)))
DIM array[] = 28, INT(wpr / LOG_BASE + 2)
k = small(array, 1)
i = k
WHILE i > 0
i = i - 1
tmp = times(x, x, NULL)
tmp = plus(tmp, 1, NULL)
tmp = squareRoot(tmp, NULL)
tmp = plus(tmp, 1, NULL)
x = div(x, tmp, NULL, NULL, NULL, NULL, NULL)
WEND
external = FALSE
j = CEIL(wpr / LOG_BASE)
n = 1
x2 = times(x, x, NULL)
r = Constructor(x)
px = x
// atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ...
WHILE i <> -1
px = times(px, x2)
n = n + 2
tmp = div(px, n, NULL, NULL, NULL, NULL, NULL)
t = minus(r, div(px, n, NULL, NULL, NULL, NULL, NULL), NULL)
td = SLICE(t, 2)
px = times(px, x2, NULL)
n = n + 2
r = plus(t, div(px, n, NULL, NULL, NULL, NULL, NULL), NULL)
rd = SLICE(r, 2)
IFB UBound(rd) >= j THEN
i = j
WHILE i >= 0 AND rd[i] = td[i]
i = i - 1
IF i = -1 THEN BREAK
WEND
ENDIF
WEND
IF k <> 0 THEN r = times(r, POWER(2, k))
external = TRUE
precision = pr
rounding = rm
RESULT = finalise(r, precision, rounding, TRUE)
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION isFinite(x)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
RESULT = IIF(x[1] <> NULL, TRUE, FALSE)
FEND
FUNCTION isInteger(x)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
RESULT = VARTYPE(LENGTH(x) >= 3 AND GLOBAL.floor(x[1] / LOG_BASE) > LENGTH(x) - 2 - 2, VAR_BOOLEAN)
FEND
FUNCTION isNaN(x)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
RESULT = IIF(x[0] = NULL, TRUE, FALSE)
FEND
FUNCTION isNegative(x)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
RESULT = IIF(x[0] < 0, TRUE, FALSE)
FEND
FUNCTION isPositive(x)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
RESULT = IIF(x[0] > 0, TRUE, FALSE)
FEND
FUNCTION isZero(x)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
RESULT = VARTYPE(VARTYPE(x[2]) = 5 AND x[2] = 0, VAR_BOOLEAN)
FEND
FUNCTION lessThan(x, y)
RESULT = cmp(x, y) < 0
FEND
FUNCTION lessThanOrEqualTo(x, y)
RESULT = cmp(x, y) < 1
FEND
FUNCTION logarithm(x, base = NULL, isNumeric = FALSE)
arg = IIF(VARTYPE(x) < 8192, Constructor(x), x)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
pr = precision
rm = rounding
guard = 5
// Default base is 10.
IFB base = NULL THEN
base = Constructor(10)
isBase10 = TRUE
ELSE
base = Constructor(base)
d = SLICE(base, 2)
// Return NaN if base is negative, or non-finite, or is 0 or 1.
IFB VAL(base[0]) < 0 OR LENGTH(d) >= 2 OR eq(base, 1) THEN
RESULT = Constructor("NaN")
EXIT
ENDIF
isBase10 = eq(base, 10)
ENDIF
d = SLICE(arg, 2)
// The result will have a non-terminating decimal expansion if base is 10 and arg is not an
// integer power of 10.
inf = FALSE
IFB isBase10 THEN
IFB LENGTH(d) > 1 THEN
inf = TRUE
ELSE
k = d[0]
WHILE k MOD 10 = 0
k = k / 10
WEND
inf = k <> 1
ENDIF
ENDIF
external = FALSE
sd = pr + guard
num = naturalLogarithm(arg, sd)
IFB isBase10 THEN
denominator = getLn10(Ctor, sd + 10)
ELSE
denominator = naturalLogarithm(base, sd)
ENDIF
// The result will have 5 rounding digits.
r = divide(num, denominator, sd, 1)
rd = SLICE(r, 2)
// If at a rounding boundary, i.e. the result's rounding digits are [49]9999 or [50]0000,
// calculate 10 further digits.
//
// If the result is known to have an infinite decimal expansion, repeat this until it is clear
// that the result is above or below the boundary. Otherwise, if after calculating the 10
// further digits, the last 14 are nines, round up and assume the result is exact.
// Also assume the result is exact if the last 14 are zero.
//
// Example of a result that will be incorrectly rounded:
// log[1048576](4503599627370502) = 2.60000000000000009610279511444746...
// The above result correctly rounded using ROUND_CEIL to 1 decimal place should be 2.7, but it
// will be given as 2.6 as there are 15 zeros immediately after the requested decimal place, so
// the exact result would be assumed to be 2.6, which rounded using ROUND_CEIL to 1 decimal
// place is still 2.6.
k = pr
IFB checkRoundingDigits(rd, pr, rm) THEN
REPEAT
sd = sd + 10
num = naturalLogarithm(arg, sd)
denominator = IIF(isBase10, getLn10(Ctor, sd + 10), naturalLogarithm(base, sd))
r = divide(num, denominator, sd, 1)
rd = SLICE(r, 2)
IFB !inf THEN
// Check for 14 nines from the 2nd rounding digit, as the first may be 4.
IFB VAL(COPY(digitsToString(rd), k + 2, 14)) + 1 = 1E+14 THEN
r = finalise(r, pr + 1, 0)
ENDIF
BREAK
ENDIF
k = k + 10
UNTIL !(checkRoundingDigits(rd, k, rm))
ENDIF
external = TRUE
RESULT = finalise(r, pr, rm)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION minus(minuend, subtrahend, isnumeric = FALSE)
x = IIF(VARTYPE(minuend) < 8192, Constructor(minuend), minuend)
y = IIF(VARTYPE(subtrahend) < 8192, Constructor(subtrahend), subtrahend)
DIM xIsNum = CHKNUM(x[1])
DIM yIsNum = CHKNUM(y[1])
DIM xIsZero = x[0] = 1 AND x[1] = 0 AND x[2] = 0
DIM yIsZero = y[0] = 1 AND y[1] = 0 AND y[2] = 0
DIM xIsInf = x[0] <> NULL AND x[1] = NULL AND !x[2]
DIM yIsInf = y[0] <> NULL AND y[1] = NULL AND !y[2]
DIM xIsNaN = x[0] = NULL AND x[1] = NULL AND x[2] = FALSE
DIM yIsNaN = y[0] = NULL AND y[1] = NULL AND y[2] = FALSE
// If either is not finite...
IFB !xIsNum OR !yIsNum THEN
// Return NaN if either is NaN
// どちらかがNaNならばNaNを返す
IFB xIsNaN OR yIsNaN THEN
RESULT = "NaN"
// Return y negated if x is finite and y is ±Infinity.
// xが有限値でyが無限値ならばyを否定して返す
ELSEIF !xIsInf AND yIsInf THEN
y[0] = -1 * y[0]
RESULT = finiteToString(y)
// Return x if y is finite and x is ±Infinity.
// yが有限値でxが無限値ならばxを返す
ELSEIF yIsNum AND xIsInf THEN
RESULT = finiteToString(x)
// Return x if both are ±Infinity with different signs.
// 両方とも±∞で符号が違うならばxを返す
ELSEIF x[0] <> y[0] AND xIsInf AND yIsInf THEN
RESULT = finiteToString(x)
// Return NaN if both are ±Infinity with the same sign.
// 両方とも±∞で符号が同じならばNaNを返す
ELSEIF x[0] = y[0] AND xIsInf AND yIsInf THEN
RESULT = "NaN"
ENDIF
EXIT
ENDIF
// If signs differ...
IFB x[0] <> y[0] THEN
y[0] = -1 * y[0]
// x = finalise(x, pr, rm)
// y = finalise(y, pr, rm)
RESULT = Decimal.plus(x, y, isnumeric)
EXIT
ENDIF
xd = SLICE(x, 2)
yd = SLICE(y, 2)
pr = precision
rm = rounding
// If either is zero...
IFB !xd[0] OR !yd[0] THEN
// Return y negated if x is zero and y is non-zero.
IFB yd[0] THEN
y[0] = -1 * y[0]
// Return x if y is zero and x is non-zero.
ELSEIF xd[0] THEN
y = x
// Return zero if both are zero.
// From IEEE 754 (2008) 6.3: 0 - 0 = -0 - -0 = -0 when rounding to -Infinity.
ELSE
RESULT = 0
EXIT
ENDIF
RESULT = IIF(external, finalise(y, pr, rm), y)
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
// Calculate base 1e7 exponents.
e = GLOBAL.floor(y[1] / LOG_BASE)
xe = GLOBAL.floor(x[1] / LOG_BASE)
k = xe - e
// If base 1e7 exponents differ...
IFB k <> 0 THEN
xLTy = k < 0
IFB xLTy THEN
d = SLICE(xd)
k = -1 * k
len = LENGTH(yd)
ELSE
d = SLICE(yd)
e = xe
len = LENGTH(xd)
ENDIF
DIM tmp[] = CEIL(pr / LOG_BASE), len
i = CALCARRAY(tmp, CALC_MAX) + 2
IFB k > i THEN
k = i
RESIZE(d, 1)
ENDIF
// Prepend zeros to equalise exponents.
arrayReverse(d)
i = k - 1
WHILE i >= 0
arrayPush(d, 0)
i = i - 1
WEND
arrayReverse(d)
// copy
IFB xLTy THEN
xd = SLICE(d)
ELSE
yd = SLICE(d)
ENDIF
ELSE
// Check digits to determine which is the bigger number.
i = LENGTH(x) - 2
len = LENGTH(y) - 2
xLTy = i < len
IF xLTy <> 0 THEN len = i
FOR i = 0 TO len - 1
IFB VAL(xd[i]) <> VAL(yd[i]) THEN
xLTy = VAL(xd[i]) < VAL(yd[i])
BREAK
ENDIF
NEXT
k = 0
ENDIF
IFB xLTy <> 0 THEN
d = SLICE(xd)
xd = SLICE(yd)
yd = SLICE(d)
y[0] = -1 * y[0]
ENDIF
len = LENGTH(xd)
// Append zeros to `xd` if shorter.
// Don't add zeros to `yd` if shorter as subtraction only needs to start at `yd` length.
i = LENGTH(yd) - len
WHILE i > 0
arrayPush(xd, 0)
len = len + 1
i = i - 1
WEND
// Subtract yd from xd.
i = LENGTH(yd)
WHILE i > k
i = i - 1
IFB VAL(xd[i]) < VAL(yd[i]) THEN
j = i
j = j - 1
WHILE VARTYPE(j+1, VAR_BOOLEAN) AND VARTYPE(xd[j] = 0, VAR_BOOLEAN)
xd[j] = BASE - 1
j = j - 1
WEND
xd[j] = VAL(xd[j] )- 1
xd[i] = VAL(xd[i]) + BASE
ENDIF
xd[i] = VAL(xd[i]) - VAL(yd[i])
WEND
// Remove trailing zeros.
len = LENGTH(xd)
WHILE len > 0
IFB xd[len - 1] = 0 THEN
arrayPop(xd)
len = LENGTH(xd)
ELSE
BREAK
ENDIF
WEND
// Remove leading zeros and adjust exponent accordingly.
IFB LENGTH(xd) <> 0 THEN
WHILE xd[0] = 0
arrayShift(xd)
e = e - 1
WEND
ENDIF
// Zero?
IFB LENGTH(xd) = 0 THEN
RESULT = Constructor(IIF(rm=3, -0, 0))
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
RESIZE(y, 1)
arrayMerge(y, xd)
y[1] = getBase10Exponent(xd, e)
IFB external THEN
RESULT = finalise(y, pr, rm)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
ELSE
RESULT = SLICE(y)
ENDIF
FEND
FUNCTION modulo(x, y)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
y = IIF(VARTYPE(y) < 8192, Constructor(y), y)
DIM xIsNum = CHKNUM(x[1])
DIM yIsNum = CHKNUM(y[1])
DIM xIsZero = x[0] = 1 AND x[1] = 0 AND x[2] = 0
DIM yIsZero = y[0] = 1 AND y[1] = 0 AND y[2] = 0
DIM xIsInf = x[0] <> NULL AND x[1] = NULL AND !x[2]
DIM yIsInf = y[0] <> NULL AND y[1] = NULL AND !y[2]
DIM xIsNaN = x[0] = NULL AND x[1] = NULL AND x[2] = FALSE
DIM yIsNaN = y[0] = NULL AND y[1] = NULL AND y[2] = FALSE
// Return NaN if x is ±Infinity or NaN, or y is NaN or ±0.
IFB (xIsInf OR xIsNaN) OR (yIsNaN OR yIsZero) THEN
RESULT = Constructor("NaN")
EXIT
ENDIF
// Prevent rounding of intermediate calculations.
external = FALSE
IFB modulo = 9 THEN
// Euclidian division: q = sign(y) * floor(x / abs(y))
// result = x - q * y where 0 <= result < abs(y)
q = divide(x, absoluteValue(y), 0, 3, 1)
q[0] = q[0] * y[0]
ELSE
q = divide(x, y, 0, modulo, 1)
ENDIF
q = times(q, y)
external = TRUE
RESULT = minus(x, q)
FEND
FUNCTION negated(x, isNumeric = FALSE)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
x[0] = -1 * x[0]
RESULT = finalise(x)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION plus(augend, addend, isnumeric = FALSE)
x = IIF(VARTYPE(augend) < 8192, Constructor(augend), augend)
y = IIF(VARTYPE(addend) < 8192, Constructor(addend), addend)
DIM xIsNum = CHKNUM(x[1])
DIM yIsNum = CHKNUM(y[1])
DIM xIsZero = x[0] = 1 AND x[1] = 0 AND x[2] = 0
DIM yIsZero = y[0] = 1 AND y[1] = 0 AND y[2] = 0
DIM xIsInf = x[0] <> NULL AND x[1] = NULL AND !x[2]
DIM yIsInf = y[0] <> NULL AND y[1] = NULL AND !y[2]
DIM xIsNaN = x[0] = NULL AND x[1] = NULL AND x[2] = FALSE
DIM yIsNaN = y[0] = NULL AND y[1] = NULL AND y[2] = FALSE
// If either is not finite...
IFB !xIsNum OR !yIsNum THEN
// Return NaN if either is NaN.
// どちらかがNaNならばNaNを返す
IFB xIsNaN OR yIsNaN THEN
RESULT = "NaN"
// Return x if y is finite and x is ±Infinity.
// yが有限でxが±∞ならばxを返す
ELSEIF yIsNum AND xIsInf THEN
RESULT = finiteToString(x)//IIF(isNegative(x), "-", "") + "INF"
// Return x if both are ±Infinity with the same sign.
// 両方とも±∞で符号が同じならばxを返す
ELSEIF x[0] = y[0] AND xIsInf AND yIsInf THEN
RESULT = finiteToString(x)//IIF(isNegative(x), "-", "") + "INF"
// Return NaN if both are ±Infinity with different signs.
// 両方とも±∞で符号が違うならばNaNを返す
ELSEIF x[0] <> y[0] AND xIsInf AND yIsInf THEN
RESULT = "NaN"
// Return y if x is finite and y is ±Infinity.
// xが有限でyが±∞ならばyを返す
ELSEIF xIsNum AND yIsInf THEN
RESULT = "INF"//finiteToString(y)//IIF(isNegative(y), "-", "") + "INF"//toString(finalise(y, pr, rm))
ENDIF
RESULT = Constructor(RESULT)
EXIT
ENDIF
// If signs differ...
IFB x[0] <> y[0] THEN
y[0] = -1 * y[0]
RESULT = Decimal.minus(x, y, isnumeric)
EXIT
ENDIF
xd = SLICE(x, 2)
yd = SLICE(y, 2)
pr = precision
rm = rounding
// If either is zero...
IFB !xd[0] OR !yd[0] THEN
IF !yd[0] THEN y = x
RESULT = IIF(external, finalise(y, pr, rm), y)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
// Calculate base 1e7 exponents.
// value = x[1]/LOG_BASE
// k = INT(value) + IIF(value<0 AND value <> INT(value), -1, 0)
// value = y[1]/LOG_BASE
// e = INT(value) + IIF(value<0 AND value- INT(value) <> 0, -1, 0)
k = GLOBAL.floor(x[1] / LOG_BASE)
e = GLOBAL.floor(y[1] / LOG_BASE)
i = k - e
// If base 1e7 exponents differ
IFB i <> 0 THEN
IFB i < 0 THEN
DIM d = SLICE(xd)
i = -1 * i
len = LENGTH(yd)
flg = TRUE
ELSE
d = SLICE(yd)
e = k
len = LENGTH(xd)
flg = FALSE
ENDIF
// Limit number of zeros prepended to max(ceil(pr / LOG_BASE), len) + 1.
k = CEIL(pr/LOG_BASE)
len = IIF(k > len, k + 1, len + 1)
// i = LENGTH(yd)
//TEXTBLOCK
IFB i > len THEN
i = len
RESIZE(d, 1)
ENDIF
//ENDTEXTBLOCK
// Prepend zeros to equalise exponents. Note: Faster to use reverse then do unshifts.
arrayReverse(d)
WHILE i > 0
arrayPush(d, 0)
i = i - 1
WEND
arrayReverse(d)
// copy
IFB flg THEN
xd = SLICE(d)
ELSE
yd = SLICE(d)
ENDIF
ENDIF
len = LENGTH(xd)
i = LENGTH(yd)
// If yd is longer than xd, swap xd and yd so xd points to the longer array.
IFB len - i < 0 THEN
i = len
d = SLICE(yd)
yd = SLICE(xd)
xd = SLICE(d)
ENDIF
// Only start adding at yd.length - 1 as the further digits of xd can be left as they are.
DIM carry = 0
WHILE i > 0
i = i - 1
xd[i] = VAL(xd[i]) + VAL(yd[i]) + carry
carry = INT(xd[i] / BASE)
xd[i] = xd[i] MOD BASE
WEND
IFB carry THEN
// xd.unshift(carry)
arrayUnshift(xd, carry)
e = e + 1
ENDIF
// Remove trailing zeros.
// No need to check for zero, as +x + +y != 0 && -x + -y != 0 RESULT = ERR_VALUE
len = LENGTH(xd)
WHILE len > 0
IFB xd[len - 1] = 0 THEN
arrayPop(xd)
len = LENGTH(xd)
ELSE
BREAK
ENDIF
WEND
RESIZE(y, 1)
arrayMerge(y, xd)
y[1] = getBase10Exponent(xd, e)
IFB external THEN
RESULT = finalise(y, pr, rm)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
ELSE
RESULT = SLICE(y)
ENDIF
FEND
FUNCTION precision(x, z = NULL)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
xd = SLICE(x, 2)
IFB LENGTH(xd) THEN
k = getPrecision(xd)
IFB z <> NULL THEN
IF z AND x[1] + 1 > k THEN k = x[1] + 1
ENDIF
ELSE
k = "NaN"
ENDIF
RESULT = k
FEND
FUNCTION round(x, isNumeric = FALSE)
x = Constructor(x)
RESULT = finalise(x, x[1] + 1, rounding)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION sine(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("sine,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
IFB !isFinite(x) THEN
RESULT = Constructor("NaN")
EXIT
ENDIF
IFB isZero(x) THEN
RESULT = Constructor(x)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
pr = precision
rm = rounding
DIM array[] = x[1], sd(x)
precision = pr + CALCARRAY(array, CALC_MAX) + LOG_BASE
rounding = 1
x = sine2(Ctor, toLessThanHalfPi(Ctor, x))
precision = pr
rounding = rm
RESULT = finalise(IIF(quadrant > 2, neg(x), x), pr, rm, TRUE)
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION squareRoot(x, isNumeric = FALSE)
x = Constructor(x)
d = SLICE(x, 2)
e = x[1]
s = x[0]
DIM xIsNum = CHKNUM(x[1])
DIM xIsZero = x[0] = 1 AND x[1] = 0 AND x[2] = 0
DIM xIsInf = x[0] <> NULL AND x[1] = NULL AND !x[2]
DIM xIsNaN = x[0] = NULL AND x[1] = NULL AND x[2] = FALSE
// Negative/NaN/Infinity/zero?
IFB s <> 1 OR xIsNaN OR xIsInf OR xIsZero THEN
RESULT = Constructor(IIF(!s OR s < 0 AND (!d OR d[0]), "NaN", IIF(d, x, 1 / 0)))
ENDIF
external = FALSE
// Initial estimate.
n = finiteToString(x)
// s = GLOBAL.SQRT(n)
DIM SC = CREATEOLEOBJ("ScriptControl")
SC.Language = "JScript"
s = SC.Eval("Math.sqrt(" + n + ").toPrecision(16)")
//s = 4.898979485566356//GLOBAL.SQRT(VAL(JOIN(d, "")))
// Math.sqrt underflow/overflow?
// Pass x to Math.sqrt as integer, then adjust the exponent of the result.
IFB s = 0 OR s = 1 / 0 THEN
n = digitsToString(d)
IF (LENGTH(n) + e) MOD 2 = 0 THEN n = n + "0"
s = GLOBAL.SQRT(n)
e = floor((e + 1) / 2) - (e < 0 OR e MOD 2)
IFB s = 1 / 0 THEN
n = "5E" + e
ELSE
n = toExponential(s)
n = SLICE(n, 1, POS("e", n) + 1) + e
ENDIF
r = Constructor(n)
ELSE
r = Constructor("" + s)
ENDIF
e = precision
sd = e + 3
// Newton-Raphson iteration.
rep = FALSE
WHILE TRUE
t = r
td = SLICE(t, 2)
// tmp = divide(x, t, sd + 2, 1)
// tmp = plus(t, tmp)
// r = times(tmp, 0.5)
r = times(plus(t, divide(x, t, sd + 2, 1)), 0.5)
rd = SLICE(r, 2)
// TODO? Replace with for-loop and checkRoundingDigits.
n = digitsToString(rd)
m = COPY(digitsToString(td), 1, sd)
IFB m = COPY(n, 1, sd) THEN
n = COPY(n, sd - 3 + 1, 4)
// The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or
// 4999, i.e. approaching a rounding boundary, continue the iteration.
IFB n = "9999" OR !rep AND n = "4999" THEN
// On the first iteration only, check to see if rounding up gives the exact result as the
// nines may infinitely repeat.
IFB !rep THEN
finalise(t, e + 1, 0)
IFB eq(times(t, t), x) THEN
r = t
BREAK
ENDIF
ENDIF
sd = sd + 4
rep = 1
ELSE
// If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result.
// If not, then there are further digits and m will be truthy.
IFB n <> 0 OR COPY(n, 2) <> "0" AND COPY(n, 1, 1) = "5" THEN
// Truncate to the first rounding digit.
finalise(r, e + 1, 1)
m = !eq(times(r, r), x)
ENDIF
BREAK
ENDIF
ENDIF
WEND
external = TRUE
RESULT = finalise(r, e, rounding, m)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION tangent(x, isNumeric = FALSE)
IFB isDecimalInstance(x) THEN
str = toString(x)
ELSE
str = x
ENDIF
DIM filename = Hash.sha256("tangent,x=" + str)
DIM path = folderspec + filename
IFB FOPEN(path, F_EXISTS) THEN
DIM FID = FOPEN(path, F_READ)
str = VARTYPE(FGET(FID, 1), 258)
RESULT = Constructor(str)
FCLOSE(FID)
ELSE
x = Constructor(x)
IFB !isFinite(x) THEN
RESULT = Constructor("NaN")
EXIT
ENDIF
IFB isZero(x) THEN
RESULT = Constructor(x)
EXIT
ENDIF
pr = precision
rm = rounding
precision = pr + 10
rounding = 1
x = sine(x, NULL)
x[0] = 1
tmp = times(x, x, NULL)
tmp = minus(1, tmp, NULL)
tmp = THIS.sqrt(tmp, NULL)
x = divide(x, tmp)
// x = divide(x, squareRoot(minus(Constructor(1), times(x, x))), pr + 10, 0)
precision = pr
rounding = rm
RESULT = finalise(IIF(quadrant = 2 OR quadrant = 4, neg(x), x), pr, rm, TRUE)
CreateFolders(folderspec)
FID = FOPEN(path, F_READ OR F_WRITE8)
FPUT(FID, toString(RESULT))
FCLOSE(FID)
ENDIF
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION times(multiplicand, multiplier, isnumeric = FALSE)
x = IIF(VARTYPE(multiplicand) < 8192, Constructor(multiplicand), multiplicand)
y = IIF(VARTYPE(multiplier) < 8192, Constructor(multiplier), multiplier)
xd = SLICE(x, 2)
yd = SLICE(y, 2)
DIM xIsZero = x[0] = 1 AND x[1] = 0 AND x[2] = 0
DIM yIsZero = y[0] = 1 AND y[1] = 0 AND y[2] = 0
DIM xIsInf = x[0] <> NULL AND x[1] = NULL AND !x[2]
DIM yIsInf = y[0] <> NULL AND y[1] = NULL AND !y[2]
DIM xIsNaN = x[0] = NULL AND x[1] = NULL AND x[2] = FALSE
DIM yIsNaN = y[0] = NULL AND y[1] = NULL AND y[2] = FALSE
IFB xIsNaN OR yIsNan THEN
y[0] = "NaN"
ELSE
y[0] = y[0] * x[0]
ENDIF
// If either is NaN, ±Infinity or ±0...
IFB (xIsNaN OR yIsNaN) OR (xIsInf OR yIsInf) OR (xIsZero OR yIsZero) THEN
// Return NaN if either is NaN.
// どちらかがNaNならばNaNを返す
IFB xIsNaN OR yIsNaN THEN
RESULT = "NaN"
// Return NaN if x is ±0 and y is ±Infinity, or y is ±0 and x is ±Infinity.
// xが±0、yが±無限大、もしくはyが±0、xが±無限大ならばNaNを返す
ELSEIF (xIsZero AND yIsInf) OR (yIsZero AND xIsInf) THEN
RESULT = "NaN"
// Return ±Infinity if either is ±Infinity.
// どちらかが±無限大ならば±無限大を返す
ELSEIF xIsInf OR yIsInf THEN
RESULT = "INF"
// Return ±0 if either is ±0.
// どちらかが±0ならば±0を返す
ELSEIF xIsZero OR yIsZero THEN
RESULT = "0"
ENDIF
RESULT = Constructor(RESULT)
IF isNumeric = NULL THEN EXIT
RESULT = IIF(isNumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
e = GLOBAL.floor(x[1] / LOG_BASE) + GLOBAL.floor(y[1] / LOG_BASE)
xdL = LENGTH(xd)
ydL = LENGTH(yd)
// Ensure xd points to the longer array.
IFB xdL < ydL THEN
r = SLICE(xd)
xd = SLICE(yd)
yd = SLICE(r)
rL = xdL
xdL = ydL
ydL = rL
ENDIF
// Initialise the result array with zeros.
DIM r[-1]
rL = xdL + ydL
i = rL
WHILE i > 0
arrayPush(r, 0)
i = i - 1
WEND
// Multiply!
i = ydL
WHILE i > 0
i = i - 1
carry = 0
k = xdL + i
WHILE k > i
t = VAL(r[k]) + VAL(yd[i]) * VAL(xd[k-i-1]) + carry
r[k] = t MOD BASE
k = k - 1
carry = INT(t / BASE)
WEND
r[k] = (r[k] + carry) MOD BASE
WEND
// Remove trailing zeros.
rL = rL - 1
WHILE r[rL] = 0
arrayPop(r)
rL = rL - 1
WEND
IFB carry <> 0 THEN
e = e + 1
ELSE
arrayShift(r)
ENDIF
RESIZE(y, 1)
arrayMerge(y, r)
y[1] = getBase10Exponent(r, e)
IFB external THEN
RESULT = finalise(y, precision, rounding)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
ELSE
RESULT = SLICE(y)
ENDIF
FEND
FUNCTION toBinary(x, sd = NULL, rm = NULL)
RESULT = toStringBinary(x, 2, sd, rm)
FEND
FUNCTION toDecimalPlaces(x, dp = NULL, rm = NULL)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IFB dp = NULL THEN
RESULT = SLICE(x)
RESULT = toString(RESULT)
EXIT
ENDIF
checkInt32(dp, 0, MAX_DIGITS)
IFB rm = NULL THEN
rm = rounding
ELSE
checkInt32(rm, 0, 8)
ENDIF
RESULT = finiteToString(finalise(x, dp + x[1] + 1, rm))
FEND
FUNCTION toExponential(x, dp = NULL, rm = NULL)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IFB dp = NULL THEN
str = finiteToString(x, TRUE)
ELSE
checkInt32(dp, 0, MAX_DIGITS)
IFB rm = NULL THEN
rm = rounding
ELSE
checkInt32(rm, 0, 8)
ENDIF
x = finalise(Constructor(x), dp + 1, rm)
str = finiteToString(x, TRUE, dp + 1)
ENDIF
RESULT = IIF(isNeg(x) AND !isZero(x), "-" + str, str)
FEND
FUNCTION toFixed(x, dp = NULL, rm = NULL)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IFB dp = NULL THEN
str = finiteToString(x)
ELSE
checkInt32(dp, 0, MAX_DIGITS)
IFB rm = NULL THEN
rm = rounding
ELSE
checkInt32(rm, 0, 8)
ENDIF
y = finalise(Constructor(x), dp + x[1] + 1, rm)
str = finiteToString(y, FALSE, dp + y[1] + 1)
ENDIF
// To determine whether to add the minus sign look at the value before it was rounded,
// i.e. look at `x` rather than `y`.
RESULT = IIF(isNeg(x) AND !isZero(x), "-" + str, str)
FEND
FUNCTION toFraction(x, maxD = NULL)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
xd = SLICE(x, 2)
IFB LENGTH(xd) = 0 THEN
RESULT = Constructor(x)
ENDIF
d0 = Constructor(1)
n1 = d0
n0 = Constructor(0)
d1 = n0
d = Constructor(d1)
d[1] = getPrecision(xd) - x[1] - 1
e = d[1]
k = e MOD LOG_BASE
d[2] = POW(10, IIF(k < 0, LOG_BASE + k, k))
IFB maxD = NULL THEN
// d is 10**e, the minimum max-denominator needed.
maxD = IIF(e > 0, d, n1)
ELSE
n = Constructor(maxD)
IFB !isInt(n) <> 0 OR lt(n, n1) THEN
RESULT = ERR_VALUE
EXIT
ENDIF
maxD = IIF(gt(n, d), IIF(e > 0, d, n1), n)
ENDIF
external = FALSE
n = Constructor(digitsToString(xd))
pr = precision
e = LENGTH(xd) * LOG_BASE * 2
precision = e
WHILE TRUE
q = divide(n, d, 0, 1, 1)
d2 = plus(d0, times(q, d1), NULL)
IF cmp(d2, maxD) = 1 THEN BREAK
d0 = d1
d1 = d2
d2 = n1
n1 = plus(n0, times(q, d2), NULL)
n0 = d2
d2 = d
d = minus(n, times(q, d2))
n = d2
WEND
d2 = divide(minus(maxD, d0), d1, 0, 1, 1)
n0 = plus(n0, times(d2, n1), NULL)
d0 = plus(d0, times(d2, d1), NULL)
n1[0] = x[0]
n0[0] = n1[0]
// Determine which fraction is closer to x, n0/d0 or n1/d1?
tmp1 = divide(n1, d1, e, 1)
tmp1 = minus(tmp1, x)
tmp1 = THIS.abs(tmp1)
tmp2 = divide(n0, d0, e, 1)
tmp2 = minus(tmp2, x)
tmp2 = THIS.abs(tmp2)
DIM r[-1]
IFB cmp(tmp1, tmp2) < 1 THEN
arrayPush(r, finiteToString(n1))
arrayPush(r, finiteToString(d1))
ELSE
arrayPush(r, finiteToString(n0))
arrayPush(r, finiteToString(d0))
ENDIF
precision = pr
external = TRUE
RESULT = SLICE(r)
FEND
FUNCTION toHexadecimal(x, sd = NULL, rm = NULL)
RESULT = toStringBinary(x, 16, sd, rm)
FEND
FUNCTION toNearest(x, y = NULL, rm = NULL)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
xd = SLICE(x, 2)
IFB y = NULL THEN
// If x is not finite, return x.
IFB !LENGTH(xd) THEN
RESULT = SLICE(x)
EXIT
ENDIF
y = Constructor(1)
rm = rounding
ELSE
y = Constructor(y)
yd = SLICE(y, 2)
IFB rm = NULL THEN
rm = rounding
ELSE
checkInt32(rm, 0, 8)
ENDIF
// If x is not finite, return x if y is not NaN, else NaN.
IFB !LENGTH(xd) THEN
RESULT = IIF(y[0], x, y)
ENDIF
// If y is not finite, return Infinity with the sign of x if y is Infinity, else NaN.
IFB !LENGTH(yd) THEN
IF y[0] THEN y[0] = x[0]
RESULT = SLICE(y)
ENDIF
// If y is not zero, calculate the nearest multiple of y to x.
IFB yd[0] THEN
external = FALSE
x = times(divide(x, y, 0, rm, 1), y)
external = TRUE
finalise(x)
ELSE
// If y is zero, return zero with the sign of x.
y[0] = x[0]
x = y
ENDIF
ENDIF
RESULT = SLICE(x)
RESULT = .toNumber(RESULT)
FEND
FUNCTION toNumber(x)
str = finiteToString(x)
RESULT = VAL(IIF(isNegative(x), "-" + str, str))
FEND
FUNCTION toOctal(x, sd = NULL, rm = NULL)
RESULT = toStringBinary(x, 8, sd, rm)
FEND
FUNCTION toPower(base, exponent, isnumeric = FALSE)
DIM x = Constructor(base)
DIM y = Constructor(exponent)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
DIM yn = VAL(exponent)
DIM xIsZero = x[0] = 1 AND x[1] = 0 AND x[2] = 0
DIM yIsZero = y[0] = 1 AND y[1] = 0 AND y[2] = 0
DIM xIsInf = x[0] <> NULL AND x[1] = NULL AND !x[2]
DIM yIsInf = y[0] <> NULL AND y[1] = NULL AND !y[2]
DIM xIsNaN = x[0] = NULL AND x[1] = NULL AND x[2] = FALSE
DIM yIsNaN = y[0] = NULL AND y[1] = NULL AND y[2] = FALSE
// Either ±Infinity, NaN or ±0?
// どちらかが±Infinity、NaNもしくは±0
IFB (xIsInf OR yIsInf) OR (xIsNaN OR yIsNaN) OR (xIsZero OR yIsZero) THEN
RESULT = POWER(base, exponent)
EXIT
ENDIF
IFB base = "1" THEN
RESULT = x
EXIT
ENDIF
pr = precision
rm = rounding
IFB exponent = "1" THEN
RESULT = finalise(x, pr, rm)
EXIT
ENDIF
// y exponent
e = GLOBAL.floor(y[1]/LOG_BASE)
// If y is a small integer use the 'exponentiation by squaring' algorithm.
DIM k = IIF(yn < 0, -1 * yn, yn)
IFB e >= LENGTH(y) - 2 - 1 AND k <= MAX_SAFE_INTEGER THEN
DIM r = intPow(Ctor, x, k, pr)
RESULT = IIF(VAL(y[0]) < 0, dividedBy("1", r), toString(finalise(r, pr, rm)))
EXIT
ENDIF
DIM s = x[0]
// if x is negative
IFB s < 0 THEN
// if y is not an integer
IFB e < LENGTH(y) - 2 - 1 THEN
RESULT = "NaN"
EXIT
ENDIF
// Result is positive if x is negative and the last digit of integer y is even.
IF (y[e+2] AND 1) = 0 THEN s = 1
// if x.eq(-1)
IFB x[1] = 0 AND x[2] = 1 AND LENGTH(x) - 2 = 1 THEN
x[0] = s
RESULT = x
EXIT
ENDIF
ENDIF
// Estimate result exponent.
// x^y = 10^e, where e = y * log10(x)
// log10(x) = log10(x_significand) + x_exponent
// log10(x_significand) = ln(x_significand) / ln(10)
xd = SLICE(x, 2)
k = POWER(digitsToString(xd), yn)
IFB k = 0 OR !isFinite(Constructor(k)) THEN
e = floor(yn * (LN("0." + digitsToString(xd)) / VAL(LN10) + VAL(x[1]) + 1))
ELSE
e = Constructor(k)[1]
ENDIF
// Exponent estimate may be incorrect e.g. x: 0.999999999999999999, y: 2.29, e: 0, r.e: -1.
// Overflow/underflow?
IFB e > maxE + 1 OR e < minE - 1 THEN
IFB e > 0 THEN
RESULT = IIF(s >= 0, "INF", "-INF")
ELSE
RESULT = "0"
ENDIF
EXIT
ENDIF
external = FALSE
x[0] = 1
rounding = x[0]
// Estimate the extra guard digits needed to ensure five correct rounding digits from
// naturalLogarithm(x). Example of failure without these extra digits (precision: 10):
// new Decimal(2.32456).pow('2087987436534566.46411')
// should be 1.162377823e+764914905173815, but is 1.162355823e+764914905173815
DIM array[] = 12, LENGTH(e)
k = small(array, 1)
// r = x^y = exp(y*ln(x))
r = naturalExponential(times(y, naturalLogarithm(x, pr + k)), pr)
rd = SLICE(r, 2)
// r may be Infinity, e.g. (0.9999999999999999).pow(-1e+40)
IFB LENGTH(rd) THEN
// Truncate to the required precision plus five rounding digits.
r = finalise(r, pr + 5, 1)
// If the rounding digits are [49]9999 or [50]0000 increase the precision by 10 and recalculate
// the result.
IFB checkRoundingDigits(rd, pr, rm) THEN
e = pr + 10
// Truncate to the increased precision plus five rounding digits.
r = finalise(naturalExponential(times(y, naturalLogarithm(x, e + k)), e), e + 5, 1)
// Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9).
IFB COPY(digitsToString(rd), pr + 1 + 1, pr + 15 + 1) + 1 = 1E+14 THEN
r = finalise(r, pr + 1, 0)
ENDIF
ENDIF
ENDIF
r[0] = s
external = TRUE
rounding = rm
RESULT = finalise(r, pr, rm)
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION toPrecision(x, sd = NULL, rm = NULL)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IFB sd = NULL THEN
str = finiteToString(x, x[1] <= toExpNeg OR x[1] >= toExpPos)
ELSE
checkInt32(sd, 1, MAX_DIGITS)
IFB rm = NULL THEN
rm = rounding
ELSE
checkInt32(rm, 0, 8)
ENDIF
x = finalise(Constructor(x), sd, rm)
str = finiteToString(x, sd <= x[1] OR x[1] <= toExpNeg, sd)
ENDIF
RESULT = IIF(isNeg(x) AND isZero(x), "-" + str, str)
FEND
FUNCTION toSignificantDigits(x, sd = NULL, rm = NULL)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
IFB sd = NULL THEN
sd = precision
rm = rounding
ELSE
checkInt32(sd, 1, MAX_DIGITS)
IFB rm = NULL THEN
rm = rounding
ELSE
checkInt32(rm, 0, 8)
ENDIF
ENDIF
RESULT = toString(finalise(Constructor(x), sd, rm))
FEND
FUNCTION toString(x)
str = finiteToString(x, x[1] <= toExpNeg OR x[1] >= toExpPos)
RESULT = IIF(isNegative(x) AND !isZero(x), "-" + str, str)
FEND
FUNCTION truncated(x, isNumeric = FALSE)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
RESULT = finalise(x, x[1] + 1, 1)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
FEND
FUNCTION valueOf(x)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
str = finiteToString(x, x[1] <= toExpNeg OR x[1] >= toExpPos)
RESULT = IIF(isNeg(x), "-" + str, str)
FEND
//////////////////////////////
// 短縮形
//////////////////////////////
FUNCTION abs(x)
RESULT = absoluteValue(x)
FEND
FUNCTION acos(x)
RESULT = inverseCosine(x)
FEND
FUNCTION acosh(x)
RESULT = inverseHyperbolicCosine(x)
FEND
FUNCTION asin(x)
RESULT = inverseSine(x)
FEND
FUNCTION asinh(x)
RESULT = inverseHyperbolicSine(x)
FEND
FUNCTION atan(x)
RESULT = inverseTangent(x)
FEND
FUNCTION atanh(x)
RESULT = inverseHyperbolicTangent(x)
FEND
FUNCTION add(augend, addend, isnumeric = FALSE)
RESULT = plus(augend, addend, isnumeric)
FEND
FUNCTION calc(str, pr = 20, rm = 4)
RESULT = calculate(str, pr, rm)
FEND
FUNCTION cbrt(x)
RESULT = cubeRoot(x)
FEND
FUNCTION clamp(x, min, max)
RESULT = clampedTo(x, min, max)
FEND
FUNCTION cmp(x, y)
RESULT = comparedTo(x, y)
FEND
FUNCTION cos(x)
RESULT = cosine(x)
FEND
FUNCTION cosh(x, isNumeric = FALSE)
RESULT = hyperbolicCosine(x, isNumeric)
FEND
FUNCTION divide(dividend, divisor, pr = 20, rm = 4, dp = NULL, _base = NULL, isnumeric = FALSE)
RESULT = dividedBy(dividend, divisor, pr, rm, dp, _base, isnumeric)
FEND
FUNCTION div(dividend, divisor, pr = 20, rm = 4, dp = NULL, _base = NULL, isnumeric = FALSE)
RESULT = dividedBy(dividend, divisor, pr, rm, dp, _base, isnumeric)
FEND
FUNCTION divToInt(x, y)
RESULT = dividedToIntegerBy(x, y)
FEND
FUNCTION dp(x)
RESULT = decimalPlaces(x)
FEND
FUNCTION eq(x, y)
RESULT = equals(x, y)
FEND
FUNCTION exp(x)
RESULT = naturalExponential(x)
FEND
FUNCTION gt(x, y)
RESULT = greaterThan(x, y)
FEND
FUNCTION gte(x, y)
RESULT = greaterThanOrEqualTo(x, y)
FEND
FUNCTION isInt(x)
RESULT = isInteger(x)
FEND
FUNCTION isNeg(x)
RESULT = isNegative(x)
FEND
FUNCTION isPos(x)
RESULT = isPositive(x)
FEND
FUNCTION ln(x)
RESULT = naturalLogarithm(x)
FEND
FUNCTION log(arg, base)
RESULT = logarithm(arg, base)
FEND
FUNCTION lt(x, y)
RESULT = lessThan(x, y)
FEND
FUNCTION lte(x, y)
RESULT = lessThanOrEqualTo(x, y)
FEND
FUNCTION mod(x, y)
RESULT = modulo(x, y)
FEND
FUNCTION mul(multiplicand, multiplier, isnumeric = FALSE)
RESULT = times(multiplicand, multiplier, isnumeric)
FEND
FUNCTION neg(x)
RESULT = negated(x)
FEND
FUNCTION pow(base, exponent)
RESULT = toPower(base, exponent)
FEND
FUNCTION sd(x, z = NULL)
RESULT = precision(x, z)
FEND
FUNCTION sin(x)
RESULT = sine(x)
FEND
FUNCTION sinh(x, isNumeric = FALSE)
RESULT = hyperbolicSine(x, isNumeric)
FEND
FUNCTION sqrt(x, isNumeric = FALSE)
RESULT = squareRoot(x, isNumeric)
FEND
FUNCTION sub(minuend, subtrahend, isnumeric = FALSE)
RESULT = minus(minuend, subtrahend, isnumeric)
FEND
FUNCTION tan(x)
RESULT = tangent(x)
FEND
FUNCTION tanh(x)
RESULT = hyperbolicTangent(x)
FEND
//////////////////////////////
// ヘルパー関数
//////////////////////////////
FUNCTION digitsToString(d)
indexOfLastWord = LENGTH(d) - 1
str = ""
w = d[0]
IFB indexOfLastWord > 0 THEN
str = str + w
DIM i = 1
WHILE i < indexOfLastWord
ws = d[i] + ""
k = LOG_BASE - LENGTH(ws)
IF k THEN str = str + getZeroString(k)
str = str + ws
i = i + 1
WEND
w = d[i]
ws = w + ""
k = LOG_BASE - LENGTH(ws)
IF k THEN str = str + getZeroString(k)
ELSEIF w = 0 THEN
RESULT = "0"
EXIT
ENDIF
// Remove trailing zeros of last w.
WHILE w MOD 10 = 0 AND w <> 0
w = w / 10
WEND
RESULT = str + w
FEND
FUNCTION checkInt32(i, min, max)
IF i <> VARTYPE(i, VAR_INTEGER) OR i < min OR i > max THEN RESULT = ERR_VALUE
FEND
FUNCTION checkRoundingDigits(d, i, rm, repeating = NULL)
// Get the length of the first word of the array d.
k = d[0]
WHILE k >= 10
i = i - 1
k = k / 10
WEND
// Is the rounding digit in the first word of d?
i = i - 1
IFB i < 0 THEN
i = i + LOG_BASE
di = 0
ELSE
di = VAL(CEIL((i + 1) / LOG_BASE))
i = i MOD LOG_BASE
ENDIF
// i is the index (0 - 6) of the rounding digit.
// E.g. if within the word 3487563 the first rounding digit is 5,
// then i = 4, k = 1000, rd = 3487563 % 1000 = 563 RESULT = ERR_VALUE
k = POWER(10, LOG_BASE - i)
IFB di > UBound(d) THEN
rd = 0
ELSE
rd = d[di] MOD k
ENDIF
IFB repeating = NULL THEN
IFB i < 3 THEN
IFB i = 0 THEN
rd = rd / 100
ELSEIF i = 1 THEN
rd = rd / 10
ENDIF
r = rm < 4 AND rd = 99999 OR rm > 3 AND rd = 49999 OR rd = 50000 OR rd = 0
ELSE
IFB di + 1 > UBound(d) THEN
n = 0
ELSE
n = d[di + 1]
ENDIF
r = (rm < 4 AND rd + 1 = k OR rm > 3 AND rd + 1 = k / 2) AND (n / k / 100) = POWER(10, i - 2) - 1 OR (rd = k / 2 OR rd = 0) AND (n / k / 100) = 0
ENDIF
ELSE
IFB i < 4 THEN
IFB i = 0 THEN
rd = rd / 1000
ELSEIF i = 1 THEN
rd = rd / 100
ELSEIF i = 2 THEN
rd = rd / 10
ENDIF
r = (repeating OR rm < 4) AND rd = 9999 OR !repeating AND rm > 3 AND rd = 4999
ELSE
IFB di + 1 > UBound(d) THEN
n = 0
ELSE
n = d[di + 1]
ENDIF
r = ((repeating OR rm < 4) AND rd + 1 = k OR (!repeating AND rm > 3) AND rd + 1 = k / 2) AND (n / k / 1000) = POWER(10, i - 3) - 1
ENDIF
ENDIF
RESULT = VARTYPE(r, VAR_BOOLEAN)
FEND
FUNCTION convertBase(str, baseIn, baseOut)
CONST NUMERALS = "0123456789abcdef"
DIM arr[0] = 0
DIM i = 0
DIM strL = LENGTH(str)
WHILE i < strL
arrL = LENGTH(arr)
WHILE TRUE
arrL = arrL - 1
IF arrL < 0 THEN BREAK
arr[arrL] = arr[arrL] * baseIn
WEND
arr[0] = arr[0] + (POS(COPY(str, i+1, 1), NUMERALS) - 1)
i = i + 1
j = 0
WHILE j < LENGTH(arr)
IFB arr[j] > baseOut - 1 THEN
IF j + 1 > UBound(arr) THEN
RESIZE(arr, j + 1)
arr[j+1] = 0
ENDIF
arr[j+1] = arr[j+1] + INT(arr[j] / baseOut)
arr[j] = arr[j] MOD baseOut
ENDIF
j = j + 1
WEND
WEND
arrayReverse(arr)
RESULT = SLICE(arr)
FEND
FUNCTION cosine2(Ctor, x)
IFB isZero(x) THEN
RESULT = SLICE(x)
EXIT
ENDIF
// Argument reduction: cos(4x) = 8*(cos^4(x) - cos^2(x)) + 1
// i.e. cos(x) = 8*(cos^4(x/4) - cos^2(x/4)) + 1
// Estimate the optimum number of times to use the argument reduction.
xd = x
xd = SLICE(xd, 2)
len = LENGTH(xd)
IFB len < 32 THEN
k = GLOBAL.CEIL(len / 3)
y = "" + (1 / tinyPow(4, k))
ELSE
k = 16
y = "2.3283064365386962890625e-10"
ENDIF
precision = precision + k
x = taylorSeries(Ctor, 1, times(x, y), Constructor(1))
// Reverse argument reduction
i = k
WHILE i > 0
i = i - 1
cos2x = times(x, x, NULL)
x = times(cos2x, cos2x, NULL)
x = minus(x, cos2x, NULL)
x = times(x, 8, NULL)
x = plus(x, 1, NULL)
WEND
precision = precision - k
RESULT = SLICE(x)
FEND
FUNCTION finalise(x, sd = NULL, rm = NULL, isTruncated = FALSE)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
xd = SLICE(x, 2)
WHILE sd <> NULL
// Get the length of the first word of the digits array xd.
digits = 1
k = VAL(xd[0])
WHILE k >= 10
digits = digits + 1
k = k / 10
WEND
i = sd - digits
// Is the rounding digit in the first word of xd?
IFB i < 0 THEN
i = i + LOG_BASE
j = sd
xdi = 0
w = xd[xdi]
// Get the rounding digit at index j of w.
rd = w / POWER(10, digits - j - 1) MOD 10
ELSE
xdi = GLOBAL.CEIL((i+1)/LOG_BASE)
k = LENGTH(xd)
IFB xdi >= k THEN
IFB isTruncated THEN
// Needed by `naturalExponential`, `naturalLogarithm` and `squareRoot`.
WHILE k <= xdi
arrayPush(xd, 0)
k = k + 1
WEND
rd = 0
w = rd
digits = 1
i = i MOD LOG_BASE
j = i - LOG_BASE + 1
ELSE
BREAK
ENDIF
ELSE
k = xd[xdi]
w = k
// Get the number of digits of w.
digits = 1
WHILE k >= 10
digits = digits + 1
k = k / 10
WEND
// Get the index of rd within w.
i = i MOD LOG_BASE
// Get the index of rd within w, adjusted for leading zeros.
// The number of leading zeros of w is given by LOG_BASE - digits.
j = i - LOG_BASE + digits
// Get the rounding digit at index j of w.
rd = IIF(j < 0, 0, INT(w / POWER(10, digits - j - 1)) MOD 10)
ENDIF
ENDIF
// Are there any non-zero digits after the rounding digit?
// isTruncated =
//IF isTruncated OR sd < 0 OR x[xdi+3] = EMPTY THEN
//isTruncated = FALSE
IFB isTruncated THEN
ELSEIF sd < 0 THEN
isTruncated = TRUE
ELSEIF xdi > UBound(xd) THEN
isTruncated = TRUE
ELSEIF IIF(j < 0, w, w MOD POWER(10, digits - j - 1)) THEN
isTruncated = TRUE
ENDIF
// The expression `w % mathpow(10, digits - j - 1)` returns all the digits of w to the right
// of the digit at (left-to-right) index j, e.g. if w is 908714 and j is 2, the expression
// will give 714.
IFB i > 0 THEN
tmp = IIF(j > 0, w / POWER(10, digits - j), 0)
ELSE
IFB xdi = 0 THEN
tmp = 0
ELSE
tmp = xd[xdi - 1] MOD 10
ENDIF
ENDIF
IF isTruncated = NULL THEN isTruncated = FALSE
roundUp = IIF(rm < 4, _
// truepart
(VARTYPE(rd, VAR_BOOLEAN) OR VARTYPE(isTruncated, VAR_BOOLEAN)) AND (rm = 0 OR VARTYPE(rm = IIF(x[0] < 0, 3, 2), VAR_BOOLEAN)), _
// falsepart
rd > 5 OR rd = 5 AND (rm = 4 OR isTruncated OR rm = 6 AND _
// Check whether the digit to the left of the rounding digit is odd.
bitAnd(tmp, 1) OR rm = IIF(x[0] < 0, 8, 7) _
) _
)
IFB sd < 1 OR !xd[0] THEN
RESIZE(xd, 0)
IFB roundUp THEN
// Convert sd to decimal places.
sd = sd - (x[1] + 1)
// 1, 0.1, 0.01, 0.001, 0.0001 etc.
x[2] = POWER(10, (LOG_BASE - sd MOD LOG_BASE) MOD LOG_BASE)
x[1] = -1 * sd
ELSE
// Zero.
RESIZE(x, 2)
x[2] = 0
x[1] = 0
ENDIF
RESULT = SLICE(x)
EXIT
ENDIF
// Remove excess digits.
IFB i = 0 THEN
RESIZE(xd, xdi-1)
RESIZE(x, 1)
arrayMerge(x, xd)
k = 1
xdi = xdi - 1
ELSE
RESIZE(xd, xdi)
RESIZE(x, 1)
arrayMerge(x, xd)
k = POWER(10, LOG_BASE-i)
// E.g. 56700 becomes 56000 if 7 is the rounding digit.
// j > 0 means i > number of leading zeros of w.
IFB j > 0 THEN
RESIZE(x, xdi+2)
xd[xdi] = INT(INT(w / POWER(10, digits-j)) MOD POWER(10, j)) * k
x[xdi+2] = xd[xdi]
ELSE
RESIZE(x, xdi+2)
xd[xdi] = 0
x[xdi+2] = xd[xdi]
ENDIF
ENDIF
IFB roundUp THEN
WHILE TRUE
// Is the digit to be rounded up in the first word of xd?
IFB xdi = 0 THEN
// i will be the length of xd[0] before k is added.
i = 1
j = VAL(xd[0])
WHILE j >= 10
i = i + 1
j = j / 10
WEND
xd[0] = VAL(xd[0]) + k
x[2] = xd[0]
j = VAL(xd[0])
k = 1
WHILE j >= 10
k = k + 1
j = j / 10
WEND
// if i != k the length has increased.
IFB i <> k THEN
x[1] = x[1] + 1
IF x[2] = BASE THEN x[2] = 1
ENDIF
BREAK
ELSE
xd[xdi] = xd[xdi] + k
IF xd[xdi] <> BASE THEN BREAK
xd[xdi] = 0
xdi = xdi - 1
k = 1
ENDIF
WEND
ENDIF
// Remove trailing zeros.
FOR i = UBound(xd) TO 0 STEP -1
IFB xd[i] = 0 THEN
arrayPop(xd)
ELSE
BREAK
ENDIF
NEXT
BREAK
WEND
IFB external THEN
// Overflow?
IFB x[1] > maxE THEN
// Infinity
RESIZE(x, 1)
x[1] = EMPTY // 仮の値
// Underflow?
ELSEIF x[1] < minE THEN
x[1] = 0
RESIZE(x, 2)
x[2] = 0
ENDIF
ENDIF
RESIZE(x, 1)
arrayMerge(x, xd)
RESULT = SLICE(x)
FEND
FUNCTION finiteToString(x, isExp = FALSE, sd = EMPTY)
IFB !isFinite(x) THEN
RESULT = nonFiniteToString(x)
EXIT
ENDIF
e = x[1]
xd = SLICE(x, 2)
str = digitsToString(xd)
len = LENGTH(str)
IFB isExp THEN
k = sd - len
IFB sd AND k > 0 THEN
str = COPY(str, 1, 1) + "." + COPY(str, 2) + getZeroString(k)
ELSEIF len > 1 THEN
str = COPY(str, 1, 1) + "." + COPY(str, 2)
ENDIF
str = str + IIF(x[1] < 0, "e", "e+") + x[1]
ELSEIF e < 0 THEN
str = "0." + getZeroString(-1 * e - 1) + str
k = sd - len
IF sd AND k > 0 THEN str = str + getZeroString(k)
ELSEIF e >= len THEN
str = str + getZeroString(e + 1 - len)
k = sd - e - 1
IF sd AND k > 0 THEN str = str + "." + getZeroString(k)
ELSE
k = e + 1
IF k < len THEN str = COPY(str, 1, k) + "." + COPY(str, k+1)
k = sd - len
IFB sd AND k > 0 THEN
IF e + 1 = len THEN str = str + "."
str = str + getZeroString(k)
ENDIF
ENDIF
RESULT = str
FEND
FUNCTION getBase10Exponent(digits[], e)
DIM w = digits[0]
e = e * LOG_BASE
WHILE w >= 10
e = e + 1
w = w / 10
WEND
RESULT = e
FEND
FUNCTION getLN10(Ctor, sd, pr = NULL)
IFB sd > LN10PRECISION THEN
// Reset global state in case the exception is caught.
external = TRUE
IF pr THEN precision = pr
ENDIF
RESULT = finalise(Constructor(LN10), sd, 1, TRUE)
FEND
FUNCTION getPI(Ctor, sd, rm)
IFB sd > PI_PRECISION THEN
RESULT = ERR_VALUE
ELSE
RESULT = finalise(Constructor(PI), sd, rm, TRUE)
ENDIF
FEND
FUNCTION getPrecision(digits)
w = LENGTH(digits) - 1
len = w * LOG_BASE + 1
w = digits[w]
// If non-zero...
IFB w <> 0 THEN
// Subtract the number of trailing zeros of the last word.
WHILE w MOD 10 = 0
len = len - 1
w = w / 10
WEND
// Add the number of digits of the first word.
w = digits[0]
WHILE VAL(w) >= 10
len = len + 1
w = w / 10
WEND
ENDIF
RESULT = len
FEND
FUNCTION getZeroString(k)
zs = ""
WHILE k > 0
zs = zs + "0"
k = k - 1
WEND
RESULT = zs
FEND
FUNCTION intPow(Ctor, x, n, pr)
DIM isTruncated
DIM r = Constructor("1")
// Max n of 9007199254740991 takes 53 loop iterations.
// Maximum digits array length; leaves [28, 34] guard digits.
DIM k = CEIL(pr / LOG_BASE + 4)
external = FALSE
WHILE TRUE
IFB n MOD 2 THEN
r = times(r, x)
rd = SLICE(r, 2)
IF truncate(rd, k) THEN isTruncated = TRUE
ENDIF
n = GLOBAL.floor(n/2)
IFB n = 0 THEN
rd = SLICE(r, 2)
// To ensure correct rounding when r.d is truncated, increment the last word if it is zero.
n = LENGTH(rd) - 1
IF isTruncated AND rd[n] = 0 THEN rd[n] = rd[n] + 1
BREAK
ENDIF
x = times(x, x)
xd = SLICE(x, 2)
truncate(xd, k)
WEND
external = TRUE
RESULT = r
FEND
FUNCTION isOdd(n)
IFB !isInteger(n) THEN
RESULT = ERR_VALUE
EXIT
ENDIF
RESULT = IIF(modulo(n, 2) = "0", FALSE, TRUE)
FEND
FUNCTION maxOrMin(Ctor, args, ltgt)
RESULT = ERR_VALUE
FEND
FUNCTION naturalExponential(x, sd = NULL, isNumeric = FALSE)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
rep = 0
i = 0
k = 0
rm = rounding
pr = precision
// 0/NaN/Infinity
IFB (x[0] = 1 AND x[1] = 0 AND x[2] = 0) OR x[1] = NULL OR x[1] > 17 THEN
ENDIF
IFB sd = NULL THEN
external = FALSE
wpr = pr
ELSE
wpr = sd
ENDIF
t = Constructor(0.03125)
// while abs(x) >= 0.1
WHILE x[1] > -2
// x = x / 2^5
x = times(x, t)
k = k + 5
WEND
// Use 2 * log10(2^k) + 5 (empirically derived) to estimate the increase in precision
// necessary to ensure the first 4 rounding digits are correct.
guard = INT(GLOBAL.LN(POWER(2, k)) / MathLN10 * 2 + 5)
wpr = wpr + guard
sum = Constructor("1")
pow = sum
denominator = pow
precision = wpr
WHILE TRUE
pow = finalise(times(pow, x), wpr, 1)
i = i + 1
denominator = times(denominator, i)
t = plus(sum, divide(pow, denominator, wpr, 1))
td = SLICE(t, 2)
sumd = SLICE(sum, 2)
IFB COPY(digitsToString(td), 1, wpr) = COPY(digitsToString(sumd), 1, wpr) THEN
j = k
j = j - 1
WHILE j >= 0
sum = finalise(times(sum, sum), wpr, 1)
j = j - 1
WEND
// Check to see if the first 4 rounding digits are [49]999.
// If so, repeat the summation with a higher precision, otherwise
// e.g. with precision: 18, rounding: 1
// exp(18.404272462595034083567793919843761) = 98372560.1229999999 (should be 98372560.123)
// `wpr - guard` is the index of first rounding digit.
IFB sd = NULL THEN
sumd = SLICE(sum, 2)
IFB rep < 3 AND checkRoundingDigits(sumd, wpr - guard, rm, rep) THEN
precision = wpr = wpr + 10
t = Constructor(1)
pow = t
denominator = pow
i = 0
rep = rep + 1
ELSE
precision = pr
RESULT = finalise(sum, precision, rm, external = TRUE)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
ELSE
precision = pr
RESULT = sum
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
ENDIF
sum = t
WEND
FEND
FUNCTION naturalLogarithm(y, sd = NULL, isNumeric = FALSE)
y = IIF(VARTYPE(y) < 8192, Constructor(y), y)
n = 1
guard = 10
x = y
xd = SLICE(x, 2)
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
rm = rounding
pr = precision
// Is x negative or Infinity, NaN, 0 or 1?
IFB x[0] < 0 THEN
// RESULT = Constructor(0)
EXIT
ENDIF
IFB sd = NULL THEN
external = FALSE
wpr = pr
ELSE
wpr = sd
ENDIF
wpr = wpr + guard
precision = wpr
c = digitsToString(xd)
c0 = COPY(c, 1, 1)
e = x[1]
IFB .lessThan(GLOBAL.ABS(e), "1.5e+15") THEN
// Argument reduction.
// The series converges faster the closer the argument is to 1, so using
// ln(a^b) = b * ln(a), ln(a) = ln(a^b) / b
// multiply the argument by itself until the leading digits of the significand are 7, 8, 9,
// 10, 11, 12 or 13, recording the number of multiplications so the sum of the series can
// later be divided by this number, then separate out the power of 10 using
// ln(a*10^b) = ln(a) + b*ln(10).
// max n is 21 (gives 0.9, 1.0 or 1.1) (9e15 / 21 = 4.2e14).
//while (c0 < 9 && c0 != 1 || c0 == 1 && c.charAt(1) > 1) {
// max n is 6 (gives 0.7 - 1.3)
WHILE c0 < 7 AND c0 <> 1 OR c0 = 1 AND COPY(c, 1, 1) > 3
x = times(x, y)
xd = SLICE(x, 2)
c = digitsToString(xd)
c0 = COPY(c, 1, 1)
n = n + 1
WEND
e = x[1]
IFB c0 > 1 THEN
x = Constructor("0." + c)
e = e + 1
ELSE
x = Constructor(c0 + "." + COPY(c, 2))
ENDIF
ELSE
// The argument reduction method above may result in overflow if the argument y is a massive
// number with exponent >= 1500000000000000 (9e15 / 6 = 1.5e15), so instead recall this
// function using ln(x*10^e) = ln(x) + e*ln(10).
t = times(getLn10(Ctor, wpr + 2, pr), e)
x = plus(naturalLogarithm(Constructor(c0 + "." + COPY(c, 2)), wpr - guard), t)
precision = pr
external = TRUE
RESULT = IIF(sd = NULL, finalise(x, pr, rm, external), x)
EXIT
ENDIF
// x1 is x reduced to a value near 1.
x1 = x
// Taylor series.
// ln(y) = ln((1 + x)/(1 - x)) = 2(x + x^3/3 + x^5/5 + x^7/7 + ...)
// where x = (y - 1)/(y + 1) (|x| < 1)
x = divide(minus(x, "1"), plus(x, "1"), wpr, 1)
numerator = x
sum = numerator
sumd = SLICE(sum, 2)
x2 = finalise(times(x, x), wpr, 1)
denominator = 3
WHILE TRUE
numerator = finalise(times(numerator, x2), wpr, 1)
t = plus(sum, divide(numerator, constructor(denominator), wpr, 1, NULL, NULL, NULL), NULL)
td = SLICE(t, 2)
IFB COPY(digitsToString(td), 1, wpr) = COPY(digitstoString(sumd), 1, wpr) THEN
sum = times(sum, "2")
// Reverse the argument reduction. Check that e is not 0 because, besides preventing an
// unnecessary calculation, -0 + 0 = +0 and to ensure correct rounding -0 needs to stay -0.
IF e <> 0 THEN sum = plus(sum, times(getLn10(Ctor, wpr + 2, pr), e, NULL), NULL)
sum = divide(sum, Constructor(n), wpr, 1)
sumd = SLICE(sum, 2)
// Is rm > 3 and the first 4 rounding digits 4999, or rm < 4 (or the summation has
// been repeated previously) and the first 4 rounding digits 9999?
// If so, restart the summation with a higher precision, otherwise
// e.g. with precision: 12, rounding: 1
// ln(135520028.6126091714265381533) = 18.7246299999 when it should be 18.72463.
// `wpr - guard` is the index of first rounding digit.
IFB sd = NULL THEN
rep = 0
IFB checkRoundingDigits(sumd, wpr - guard, rm, rep) THEN
wpr = wpr + guard
precision = wpr
x = divide(minus(x1, "1"), plus(x1, "1"), wpr, 1)
numerator = x
t = numerator
x2 = finalise(times(x, x), wpr, 1)
rep = 1
denominator = wpr
ELSE
precision = pr
external = TRUE
RESULT = finalise(sum, precision, rm, external)
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
ELSE
precision = pr
RESULT = sum
IF isnumeric = NULL THEN EXIT
RESULT = IIF(isnumeric, toNumber(RESULT), toString(RESULT))
EXIT
ENDIF
ENDIF
sum = t
sumd = SLICE(sum, 2)
denominator = denominator + 2
WEND
FEND
FUNCTION nonFiniteToString(x[])
IFB x[0] = NULL AND x[1] = NULL AND x[2] = FALSE THEN
RESULT = "NaN"
ELSEIF CHKNUM(x[0]) AND x[1] = NULL AND x[2] = FALSE THEN
RESULT = IIF(x[0] > 0, "", "-") + "INF"
ENDIF
FEND
FUNCTION parseDecimal(x, str)
// Decimal point?
e = POS(".", str) - 1
IF e <> 0 THEN str = REPLACE(str, ".", "")
// Exponential form?
DIM i = POS("e", str)
IFB i <> 0 THEN
// Determine exponent.
IF e < 0 THEN e = i
e = VAL(COPY(str, i+1))
str = COPY(str, 1, i-1)
ELSEIF e < 0 THEN
// Integer
e = LENGTH(str)
ENDIF
// Determine leading zeros.
i = 0
WHILE COPY(str, i+1, 1) = "0"
i = i + 1
WEND
// Determine trailing zeros.
len = LENGTH(str)
WHILE COPY(str, len, 1) = "0"
len = len - 1
IF len = 0 THEN BREAK
WEND
str = COPY(str, i+1, len-i)
IFB str <> 0 AND str <> "" THEN
len = len - i
e = e - i - 1
RESIZE(x, 1)
x[1] = e
//x[2] = 0
// Transform base
// e is the base 10 exponent.
// i is where to slice str to get the first word of the digits array.
i = (e + 1) MOD LOG_BASE
IF e < 0 THEN i = i + LOG_BASE
IFB i < len THEN
IF i THEN arrayPush(x, VAL(COPY(str, 1, i)))
len = len - LOG_BASE
WHILE i < len
arrayPush(x, VAL(COPY(str, i+1, LOG_BASE)))
i = i + LOG_BASE
WEND
str = COPY(str, i+1)
i = LOG_BASE - LENGTH(str)
ELSE
i = i - len
ENDIF
WHILE i > 0
str = str + "0"
i = i - 1
WEND
arrayPush(x, VAL(str))
IFB external THEN
// Overflow?
IFB x[1] = maxE THEN
// Infinity.
x[2] = NULL
x[1] = NULL
// Underflow?
ELSEIF x[1] = minE THEN
// Zero.
x[1] = 0
x[2] = 0
ENDIF
ENDIF
ELSE
// Zero.
RESIZE(x, 2)
x[1] = 0
x[2] = 0
ENDIF
RESULT = SLICE(x)
FEND
FUNCTION parseOther(x, str)
IF POS("Infinity", str) THEN str = REPLACE(str, "Infinity", "INF")
IFB POS("_", str) <> 0 THEN
ELSEIF str = "INF" OR str = "NaN" THEN
IF str = "NaN" THEN x[0] = NULL
RESIZE(x, 2)
x[1] = NULL
x[2] = FALSE
RESULT = SLICE(x)
EXIT
ENDIF
IFB reTest(str, isHex) THEN
_base = 16
str = STRCONV(str, SC_LOWERCASE)
ELSEIF reTest(str, isBinary) THEN
_base = 2
ELSEIF reTest(str, isOctal) THEN
_base = 8
ELSE
EXIT
ENDIF
// Is there a binary exponent part?
i = POS("p", str)
IFB i > 0 THEN
p = COPY(str, (i+1)+1)
str = COPY(str, 2+1, i+1)
ELSE
p = NULL
str = COPY(str, 2+1)
ENDIF
// Convert `str` as an integer then divide the result by `base` raised to a power such that the
// fraction part will be restored.
i = POS(".", str)
isFloat = i >= 1
json = "{'precision':20, 'rounding':7}"
Ctor = JSON.Parse(REPLACE(json, "'", "<#DBL>"))
IFB isFloat THEN
str = REPLACE(str, ".", "")
len = LENGTH(str)
i = len - i
// log[10](16) = 1.2041... , log[10](88) = 1.9444....
divisor = intPow(Ctor, Constructor(base), i, i * 2)
ELSE
len = NULL
divisor = NULL
ENDIF
xd = convertBase(str, _base, base)
xe = LENGTH(xd) - 1
// Remove trailing zeros.
i = xe
WHILE xd[i] = 0
i = i - 1
arrayPop(xd)
WEND
IFB i < 0 THEN
// RESULT =
EXIT
ENDIF
RESIZE(x, 1)
x[1] = getBase10Exponent(xd, xe)
arrayMerge(x, xd)
external = FALSE
// At what precision to perform the division to ensure exact conversion?
// maxDecimalIntegerPartDigitCount = ceil(log[10](b) * otherBaseIntegerPartDigitCount)
// log[10](2) = 0.30103, log[10](8) = 0.90309, log[10](16) = 1.20412
// E.g. ceil(1.2 * 3) = 4, so up to 4 decimal digits are needed to represent 3 hex int digits.
// maxDecimalFractionPartDigitCount = {Hex:4|Oct:3|Bin:1} * otherBaseFractionPartDigitCount
// Therefore using 4 * the number of digits of str will always be enough.
IF isFloat THEN x = divide(x, divisor, len * 4)
// Multiply by the binary exponent part if present.
IF p <> NULL THEN x = times(x, POWER(2, p))
external = TRUE
RESULT = SLICE(x)
FEND
FUNCTION sine2(Ctor, x)
xd = x
xd = SLICE(xd, 2)
len = LENGTH(xd)
IFB len < 3 THEN
RESULT = IIF(isZero(x), x, taylorSeries(Ctor, 2, x, x))
EXIT
ENDIF
// Argument reduction: sin(5x) = 16*sin^5(x) - 20*sin^3(x) + 5*sin(x)
// i.e. sin(x) = 16*sin^5(x/5) - 20*sin^3(x/5) + 5*sin(x/5)
// and sin(x) = sin(x/5)(5 + sin^2(x/5)(16sin^2(x/5) - 20))
// Estimate the optimum number of times to use the argument reduction.
k = 1.4 * GLOBAL.SQRT(len)
k = INT(IIF(k > 16, 16, k))
x = times(x, 1 / tinyPow(5, k), NULL)
x = taylorSeries(Ctor, 2, x, x)
// Reverse argument reduction
d5 = Constructor(5)
d16 = Constructor(16)
d20 = Constructor(20)
WHILE k > 0
k = k - 1
sin2x = times(x, x, NULL)
x = times(x, plus(d5, times(sin2x, minus(times(d16, sin2x, NULL), d20, NULL), NULL), NULL), NULL)
WEND
RESULT = SLICE(x)
FEND
FUNCTION taylorSeries(Ctor, n, x, y, isHyperbolic = NULL)
i = 1
pr = precision
k = GLOBAL.CEIL(pr / LOG_BASE)
external = FALSE
x2 = times(x, x)
u = Constructor(y)
WHILE TRUE
multiplicand = times(u, x2)
multiplier = Constructor(n * (n + 1))
t = divide(multiplicand, multiplier, pr, 1)
n = n + 2
isHyperbolic = IIF(isHyperbolic = NULL, FALSE, isHyperbolic)
u = IIF(isHyperbolic, plus(y, t), minus(y, t))
y = divide(times(t, x2), Constructor(n * (n + 1)), pr, 1)
n = n + 2
t = plus(u, y)
td = SLICE(t, 2)
ud = SLICE(u, 2)
IFB !(UBound(td) < k) THEN
j = k
TRY
WHILE td[j] = ud[j] AND j >= 0
j = j - 1
IF j = 0 THEN BREAK 2
WEND
EXCEPT
ENDTRY
IF j = -1 THEN BREAK
ENDIF
j = u
u = y
y = t
t = j
i = i + 1
WEND
external = TRUE
RESIZE(td, k)
RESIZE(t, 1)
arrayMerge(t, td)
RESULT = SLICE(t)
FEND
FUNCTION tinyPow(b, e)
DIM n = b
e = e - 1
WHILE e > 0
n = n * b
e = e - 1
WEND
RESULT = n
FEND
FUNCTION toLessThanHalfPi(Ctor, x)
isNeg = x[0] < 0
_pi = getPi(Ctor, Ctor.precision, 1)
halfPi = times(_pi, "0.5", NULL)
x = absoluteValue(x, NULL)
IFB lte(x, halfPi) THEN
quadrant = IIF(isNeg, 4, 1)
RESULT = SLICE(x)
EXIT
ENDIF
t = divToInt(x, pi)
IFB isZero(t) THEN
quadrant = IIF(isNeg, 3, 2)
ELSE
x = minus(x, times(t, pi))
// 0 <= x <pi
IFB lte(x, halfPi) THEN
quadrant = IIF(isOdd(t), IIF(isNeg, 2, 3), IIF(isNeg, 4, 1))
RESULT = SLICE(x)
EXIT
ENDIF
quadrant = IIF(isOdd(t), IIF(isNeg, 1, 4), IIF(isNeg, 3, 2))
ENDIF
RESULT = abs(minus(x, pi))
FEND
FUNCTION toLessThanHalfPi2(Ctor, x)
isNeg = x[0] < 0
_pi = getPi(Ctor, precision, 1)
halfPi = times(_pi, "0.5", NULL)
x = absoluteValue(x, NULL)
IFB lte(x, halfPi) THEN
quadrant = IIF(isNeg, 4, 1)
RESULT = SLICE(x)
EXIT
ENDIF
t = divToInt(x, pi)
IFB isZero(t) THEN
quadrant = IIF(isNeg, 3, 2)
ELSE
x = minus(x, times(t, pi), NULL)
// 0 <= x <pi
IFB lte(x, halfPi) THEN
quadrant = IIF(isOdd(t), IIF(isNeg, 2, 3), IIF(isNeg, 4, 1))
RESULT = SLICE(x)
EXIT
ENDIF
quadrant = IIF(isOdd(t), IIF(isNeg, 1, 4), IIF(isNeg, 3, 2))
ENDIF
RESULT = abs(minus(x, pi))
FEND
FUNCTION toStringBinary(x, baseOut, sd, rm)
x = IIF(VARTYPE(x) < 8192, Constructor(x), x)
isExp = IIF(sd <> NULL, TRUE, FALSE)
IFB isExp THEN
checkInt32(sd, 1, MAX_DIGITS)
IFB rm = NULL THEN
rm = rounding
ELSE
checkInt32(rm, 0, 8)
ENDIF
ELSE
sd = precision
rm = rounding
ENDIF
IFB !isFinite(x) THEN
str = nonFiniteToString(x)
ELSE
str = finiteToString(x)
i = POS(".", str) - 1
// Use exponential notation according to `toExpPos` and `toExpNeg`? No, but if required:
// maxBinaryExponent = floor((decimalExponent + 1) * log[2](10))
// minBinaryExponent = floor(decimalExponent * log[2](10))
// log[2](10) = 3.321928094887362347870319429489390175864
IFB isExp THEN
_base = 2
IFB baseOut = 16 THEN
sd = sd * 4 - 3
ELSEIF baseOut = 8 THEN
sd = sd * 3 - 2
ENDIF
ELSE
_base = baseOut
ENDIF
ENDIF
// Convert the number as an integer then divide the result by its base raised to a power such
// that the fraction part will be restored.
// Non-integer.
IFB i >= 0 THEN
str = REPLACE(str, ".", "")
y = Constructor(1)
y[1] = LENGTH(str) - i
yd = convertBase(finiteToString(y), 10, _base)
RESIZE(y, 1)
arrayMerge(y, yd)
y[1] = LENGTH(yd)
ENDIF
xd = convertBase(str, 10, _base)
len = LENGTH(xd)
e = len
// Remove trailing zeros.
len = len - 1
WHILE xd[len] = 0
arrayPop(xd)
IF len = 0 THEN BREAK
len = len - 1
WEND
IFB !xd[0] THEN
str = IIF(isExp, "0p+0", "0")
ELSE
IFB i < 0 THEN
e = e - 1
roundUp = FALSE
ELSE
// 修正
x = Constructor(x)
x = RESIZE(x, 1)
arrayMerge(x, xd)
x[1] = e
x = divide(x, y, sd, rm, 0, base)
xd = SLICE(x)
e = x[1]
roundUp = inexact
ENDIF
// The rounding digit, i.e. the digit after the digit that may be rounded up.
IFB sd > UBound(xd) THEN
i = NULL
roundUp = roundUp OR FALSE
ELSE
i = xd[sd]
roundUp = roundUp OR xd[sd + 1] <> NULL
ENDIF
k = _base / 2
IFB rm < 4 THEN
// (i !== void 0 || roundUp) && (rm === 0 || rm === (x.s < 0 ? 3 : 2))
roundUp = (i = NULL OR roundUp) AND (rm = 0 OR rm = IIF(x[0] < 0, 3, 2))
ELSE
// i > k || i === k && (rm === 4 || roundUp || rm === 6 && xd[sd - 1] & 1 ||
// rm === (x.s < 0 ? 8 : 7));
bit = IIF(sd - 1 > UBound(xd), 0, 1)
roundUp = (i > k OR i = k AND (rm = 4 OR roundUp OR rm = 6 AND bitAnd(bit, 1)) OR rm = IIF(x[0] < 0, 8, 7))
ENDIF
// roundUp = IIF(rm < 4, _
// (i <> NULL OR roundUp) AND (rm = 0 OR rm = IIF(x[0] < 0, 3, 2)), _
// i > k OR i = k AND (rm = 4 OR roundUp OR rm = 6 AND xd[sd - 1] AND 1 OR rm = IIF(x[0] < 0, 8, 7))
RESIZE(xd, sd)
IFB roundUp THEN
// Rounding up may mean the previous digit has to be rounded up and so on.
sd = sd - 1
WHILE xd[sd] > base - 1
xd[sd] = 0
IFB !sd THEN
e = e + 1
arrayUnshift(xd)
ENDIF
WEND
ENDIF
// Determine trailing zeros.
len = LENGTH(xd)
WHILE !xd[len - 1]
len = len - 1
WEND
// E.g. [4, 11, 15] becomes 4bf.
str = ""
FOR i = 0 TO len - 1
str = str + COPY(NUMERALS, VAL(xd[i]) + 1, 1)
NEXT
// Add binary exponent suffix?
IFB isExp THEN
IFB len > 1 THEN
IFB baseOut = 16 OR baseOut = 8 THEN
i = IIF(baseOut = 16, 4, 3)
WHILE len MOD i
str = str + "0"
len = len + 1
WEND
xd = convertBase(str, base, baseOut)
len = xd
WHILE !xd[len - 1]
len = len - 1
WEND
// xd[0] will always be be 1
str = "1"
FOR i = 1 TO len
str = str + COPY(NUMERALS, xd[i], 1)
NEXT
ELSE
str = COPY(str, 1, 1) + "." + COPY(str, 2)
ENDIF
ENDIF
ELSEIF e < 0 THEN
WHILE e < 0
str = "'0" + str
e = e + 1
WEND
str = "0." + str
ELSE
e = e + 1
IFB e > len THEN
FOR e = e - len TO 1 STEP -1
str = str + "0"
NEXT
ELSEIF e < len THEN
str = COPY(str, 1, e) + "." + COPY(str, e)
ENDIF
ENDIF
str = IIF(baseOut = 16, "0x", IIF(baseOut = 2, "0b", IIF(baseOut = 8, "0o", ""))) + str
ENDIF
RESULT = IIF(x[0] < 0, "-" + str, str)
FEND
FUNCTION truncate(arr, len)
IFB LENGTH(arr) > len THEN
RESIZE(arr, len)
RESULT = TRUE
EXIT
ENDIF
FEND
//////////////////////////////
// その他
//////////////////////////////
FUNCTION compare(a, b, aL, bL)
IFB aL <> bL THEN
r = IIF(aL > bL, 1, -1)
ELSE
r = 0
i = r
WHILE i < aL
IFB a[i] <> b[i] THEN
r = IIF(a[i] > b[i], 1, -1)
BREAK
ENDIF
i = i + 1
WEND
ENDIF
RESULT = r
FEND
FUNCTION Constructor(v)
CONST number = 5
CONST string = 258
DIM x = SAFEARRAY(-1)
// Duplicate.
IFB isDecimalInstance(v) THEN
x[0] = v[0]
vd = SLICE(v, 2)
IFB external THEN
IFB !LENGTH(vd) OR v[1] > maxE THEN
// Infinity.
RESIZE(x, 2)
x[1] = NULL
x[2] = NULL
ELSEIF v[1] < minE THEN
// Zero.
RESIZE(x, 2)
x[1] = 0
x[2] = 0
ELSE
RESIZE(x, 1)
x[1] = v[1]
arrayMerge(x, vd)
ENDIF
ELSE
RESIZE(x, 1)
x[1] = v[1]
arrayMerge(x, vd)
ENDIF
RESULT = SLICE(x)
EXIT
ENDIF
t = VARTYPE(v)
IFB t = number THEN
IFB v = 0 THEN
RESIZE(x, 2)
x[0] = IIF(1/v<0, -1, 1)
x[1] = 0
x[2] = 0
RESULT = SLICE(x)
EXIT
ENDIF
IFB v < 0 THEN
v = -1 * v
x[0] = -1
ELSE
x[0] = 1
ENDIF
// Fast path for small integers.
IFB v < POWER(10, 7) THEN
IFB v = VARTYPE(v, VAR_INTEGER) THEN
e = 0
i = v
WHILE i >= 10
e = e + 1
i = i / 10
WEND
IFB external THEN
IFB e > maxE THEN
RESIZE(x, 2)
x[1] = NULL
x[2] = NULL
ELSEIF e < minE THEN
RESIZE(x, 2)
x[1] = 0
x[2] = 0
ELSE
RESIZE(x, 1)
x[1] = e
arrayPush(x, v)
ENDIF
ELSE
RESIZE(x, 1)
x[1] = e
DIM tmp[] = v
arrayMerge(x, tmp)
ENDIF
RESULT = SLICE(x)
EXIT
// Infinity, NaN
ELSEIF v * 0 <> 0 THEN
IF !v THEN x[0] = NULL
x[1] = NULL
x[2] = NULL
EXIT
ENDIF
ENDIF
RESULT = parseDecimal(x, v)
EXIT
ELSEIF v = "NaN" THEN
RESIZE(x, 2)
x[0] = NULL
x[1] = NULL
x[2] = FALSE
RESULT = SLICE(x)
EXIT
ELSEIF t <> string THEN
RESULT = ERR_VALUE
EXIT
ENDIF
// Minus sign?
i = COPY(v, 1, 1)
IFB i = "-" THEN
v = COPY(v, 2)
x[0] = -1
ELSE
// Plus sign?
IF i = "+" THEN v = COPY(v, 1)
x[0] = 1
ENDIF
RESULT = IIF(reTest(v, "^(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$"), parseDecimal(x, v), parseOther(x, v))
FEND
FUNCTION isDecimalInstance(v)
RESULT = IIF(isArray(v), TRUE, FALSE)
FEND
FUNCTION multiplyInteger(x, k, base)
DIM carry = 0
DIM i = UBound(x)
WHILE i >= 0
temp = x[i] * k + carry
x[i] = INT(temp MOD base)
carry = INT(temp / base)
i = i - 1
WEND
IF carry <> 0 THEN arrayUnshift(x, carry)
RESULT = SLICE(x)
FEND
PROCEDURE subtract(Var a, b, aL, base)
DIM i = 0
// Subtract b from a.
WHILE aL > 0
aL = aL - 1
a[aL] = a[aL] - i
i = IIF(a[aL] < b[aL], 1, 0)
a[aL] = i * base + a[aL] - b[aL]
WEND
// Remove leading zeros.
WHILE !a[0] AND LENGTH(a) > 1
arrayShift(a)
WEND
FEND
//////////////////////////////
// 自作関数
//////////////////////////////
FUNCTION calculate(str, pr = 20, rm = 4)
RESULT = tokenize(str)
RESULT = toRPN(RESULT)
RESULT = calcRPN(RESULT, pr, rm)
FEND
FUNCTION calcRPN(tokens, pr, rm)
DIM denominator[-1]
DIM numerator[-1]
FOR token IN tokens
IFB reTest(token, "[0-9.]+") THEN
arrayPush(denominator, "" + 1)
arrayPush(numerator, "" + token)
ELSEIF token = "u-" THEN
arrayPush(numerator, times("-1", arrayPop(numerator)))
ELSEIF token = "floor" THEN
bottom = arrayPop(denominator)
top = arrayPop(numerator)
arrayPush(denominator, "1")
arrayPush(numerator, floor(dividedBy(top, bottom)))
ELSEIF token = "ceil" THEN
bottom = arrayPop(denominator)
top = arrayPop(numerator)
arrayPush(denominator, "1")
arrayPush(numerator, THIS.ceil(dividedBy(top, bottom)))
ELSE
IFB token = "+" OR token = "-" THEN
DIM du = UBound(denominator)
DIM nu = UBound(numerator)
bottom = times(denominator[du], denominator[du-1])
top = EVAL(denominator[du] * numerator[nu-1] + token + numerator[nu] * denominator[du-1])
arrayPop(denominator)
arrayPop(denominator)
arrayPop(numerator)
arrayPop(numerator)
arrayPush(denominator, bottom)
arrayPush(numerator, top)
ELSEIF token = "*" THEN
arrayPush(denominator, times(arrayPop(denominator), arrayPop(denominator)))
arrayPush(numerator, times(arrayPop(numerator), arrayPop(numerator)))
ELSEIF token = "/" THEN
swap(denominator[UBound(denominator)], numerator[UBound(numerator)])
arrayPush(denominator, times(arrayPop(denominator), arrayPop(denominator)))
arrayPush(numerator, times(arrayPop(numerator), arrayPop(numerator)))
ELSEIF token = "//" THEN
swap(denominator[UBound(denominator)], numerator[UBound(numerator)])
arrayPush(denominator, times(arrayPop(denominator), arrayPop(denominator)))
arrayPush(numerator, times(arrayPop(numerator), arrayPop(numerator)))
bottom = arrayPop(denominator)
top = arrayPop(numerator)
arrayPush(denominator, "1")
arrayPush(numerator, THIS.floor(dividedBy(top, bottom)))
ELSEIF token = "%" THEN
bottom = dividedBy(arrayPop(numerator), arrayPop(denominator))
top = dividedBy(arrayPop(numerator), arrayPop(denominator))
arrayPush(denominator, "1")
arrayPush(numerator, modulo(top, bottom ))
ENDIF
ENDIF
IFB COPY(denominator[UBound(denominator)], 1, 1) = "-" THEN
denominator[UBound(denominator)] = times("-1", denominator[UBound(denominator)])
numerator[UBound(numerator)] = times("-1", numerator[UBound(numerator)])
ENDIF
NEXT
DIM x = SAFEARRAY(-1)
DIM n = dividedBy(numerator[0], denominator[0])
x = Constructor(n)
RESULT = toString(finalise(x, pr, rm))
FEND
FUNCTION cmpPrecedence(token1, token2)
DIM operators[] = "+", 0, LEFT, "-", 0, LEFT, "*", 5, LEFT, "/", 5, LEFT, "%", 5, LEFT, "^", 10, RIGHT
IFB isOperator(token1) AND isOperator(token2) THEN
RESULT = operators[arraySearch(token1, operators)+1] - operators[arraySearch(token2, operators)+1]
ELSE
RESULT = ERR_VALUE
ENDIF
FEND
FUNCTION isOperator(token)
RESULT = reTest(token, "[+\-*/%^]")
FEND
FUNCTION tokenize(expr)
DIM tokens[-1]
DIM i = 1
DIM str = ""
WHILE i <= LENGTH(expr)
char = COPY(expr, i, 1)
IFB reTest(char, "\s") THEN
i = i + 1
CONTINUE
ENDIF
IFB reTest(char, "[0-9.]") THEN
num = char
i = i + 1
WHILE i <= LENGTH(expr) AND reTest(COPY(expr, i, 1), "[0-9.]")
num = num + COPY(expr, i, 1)
i = i + 1
WEND
arrayPush(tokens, VAL(num))
CONTINUE
ENDIF
IFB reTest(char, "[+\-*/^%]") THEN
IFB COPY(expr, i, 2) = "//" THEN
arrayPush(tokens, "//")
i = i + 2
ELSE
DIM prev = ""
IF LENGTH(tokens) >= 1 THEN prev = tokens[LENGTH(tokens)-1]
IFB char = "-" AND (LENGTH(tokens) = 0 OR (VARTYPE(prev) = 258 AND (isOperator(prev) OR prev = "(")))
arrayPush(tokens, "u-")
ELSE
arrayPush(tokens, char)
ENDIF
i = i + 1
ENDIF
CONTINUE
ENDIF
IFB reTest(char, "[A-Za-z0-9]") THEN
str = str + char
i = i + 1
WHILE i <= LENGTH(expr) AND reTest(COPY(expr, i, 1), "[A-Za-z0-9]")
str = str + COPY(expr, i, 1)
i = i + 1
WEND
arrayPush(tokens, str)
str = ""
CONTINUE
ENDIF
IFB reTest(char, "[()]") THEN
IFB str <> "" THEN
arrayPush(tokens, str)
str = ""
ENDIF
arrayPush(tokens, char)
i = i + 1
CONTINUE
ENDIF
WEND
RESULT = SLICE(tokens)
FEND
FUNCTION toRPN(tokens, pr = 20, rm = 4, isnumeric = FALSE)
HASHTBL precedence
precedence["^"] = 4
precedence["u-"] = 3
precedence["*"] = 2
precedence["/"] = 2
precedence["%"] = 2
precedence["+"] = 1
precedence["-"] = 1
HASHTBL rightAssociative
rightAssociative["u-"] = TRUE
rightAssociative["^"] = TRUE
DIM output[-1]
DIM stack[-1]
FOR token IN tokens
IFB reTest(token, "[0-9]+") THEN
arrayPush(output, token)
ELSEIF token = "floor" OR token = "ceil" THEN
arrayPush(stack, token)
ELSEIF token ="(" THEN
arrayPush(stack, token)
ELSEIF token = ")" THEN
WHILE LENGTH(stack) <> 0 AND stack[LENGTH(stack)-1] <> "("
arrayPush(output, arrayPop(stack))
WEND
arrayPop(stack)
IFB LENGTH(stack) <> 0 THEN
IF stack[LENGTH(stack) - 1] = "floor" OR stack[LENGTH(stack) - 1] = "ceil" THEN arrayPush(output, arrayPop(stack))
ENDIF
ELSE
WHILE LENGTH(stack)
IFB stack[LENGTH(stack)-1] <> "(" AND _
( _
precedence[token] < precedence[stack[LENGTH(stack)-1]] OR _
( _
precedence[token] = precedence[stack[LENGTH(stack)-1]] AND _
!rightAssociative[token] _
) _
) THEN
arrayPush(output, arrayPop(stack))
ELSE
BREAK
ENDIF
WEND
arrayPush(stack, token)
ENDIF
NEXT
WHILE LENGTH(stack)
arrayPush(output, arrayPop(stack))
WEND
RESULT = SLICE(output)
FEND
ENDMODULE
//////////////////////////////////////////////////
// 【引数】
// num : 数値
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION decimalDigits(num)
DIM str = fixed(num)
RESULT = IIF(POS(".", str), LENGTH(BETWEENSTR(str, ".")), 0)
FEND
//////////////////////////////////////////////////
// 【引数】
// dec : 10進数
// signFlg : 符号付きならばTrueを指定
// digits : 変換した2進数の桁数合わせを自動で行うかを示すブール値、もしくは桁数を表す数値(8,16,24,32,64のいずれか)を指定
// errorMsg : エラーメッセージを出力するかを示すブール値
// 【戻り値】
// 2進数に変換した値
//////////////////////////////////////////////////
FUNCTION decToBin(dec, signFlg = FALSE, digits = FALSE, errorMsg = FALSE)
// 負数で符号なしならばエラー値を返す
IFB dec < 0 AND signFlg = FALSE THEN
PRINT "負数の場合signFlgにTrueを指定してください"
RESULT = ERR_VALUE
EXIT
ENDIF
// digitsのビット数が足りなければエラー値を返す、負数なら1桁多く取る
IFB VARTYPE(digits) <> VAR_BOOLEAN AND digits < CEIL(LOGN(2, ABS(dec))) + IIF(dec < 0, 1, 0) THEN
PRINT "ビット数が足りません"
RESULT = ERR_VALUE
EXIT
ENDIF
// signFlgがTrueかつdigitsがFalseならばエラー値を返す
IFB signFlg AND !digits THEN
PRINT "signFlgがTrueのときdigitsはFalse以外を選択してください"
RESULT = ERR_VALUE
EXIT
ENDIF
// bin:2進数に変換した結果を代入する変数
DIM bin = ""
DIM msg = ""
DIM isError = FALSE
DIM decimalFlg = IIF(POS(".", dec) <> 0, TRUE, FALSE)
DIM negativeFlg = IIF(dec < 0, TRUE, FALSE)
dec = ABS(dec)
// (1) 10進数を整数部と小数部に分ける
DIM integer = IIF(decimalFlg, COPY(dec, 1, POS(".", dec) - 1), dec)
DIM decimal = IIF(decimalFlg, "0." + COPY(dec, POS(".", dec) + 1), 0)
// (2) 10進数(整数部)を2進数に変換する。
REPEAT
bin = (integer MOD 2) + bin
integer = INT(integer / 2)
UNTIL integer = 0
// (3) 10進数(小数部)を2進数に変換する。
IFB decimalFlg THEN
bin = bin + "."
DIM loop = 0
REPEAT
loop = loop + 1
decimal = decimal * 2
bin = bin + IIF(decimal >= 1, "1", "0")
IF decimal > 1 THEN decimal = decimal - 1
UNTIL decimal = 1 OR loop > 64
ENDIF
// digitsがFALSE以外なら
IFB digits THEN
// (4) 2進数の桁合わせを行う
DIM tmp = bin
DIM binInteger = TOKEN(".", tmp)
DIM binDecimal = TOKEN(".", tmp)
// 整数部、小数部を4bit単位になるまで拡張
// 整数部、4の倍数になるまで整数部の先頭に'0'を追加
IF LENGTH(binInteger) MOD 4 <> 0 THEN binInteger = strRepeat("0", 4 - LENGTH(binInteger) MOD 4) + binInteger
// 小数部、4の倍数になるまで小数部の末尾に'0'を追加
IF LENGTH(binDecimal) MOD 4 <> 0 THEN binDecimal = binDecimal + strRepeat("0", 4 - LENGTH(binDecimal) MOD 4)
DIM digit = LENGTH(binInteger + binDecimal)
// 10進数の場合、一旦自動調整を行う
integer = INT(dec)
IF signFlg AND COPY(binInteger, 1, 1) = "1" THEN binInteger = strRepeat("0", 4) + binInteger
IFB signFlg THEN
IFB integer >= -128 AND integer <= 127 THEN // -2^7〜2^7-1
binInteger = strRepeat("0", 8 - LENGTH(binInteger)) + binInteger
ELSEIF integer >= -32768 AND integer <= 32767 THEN // -2^15〜2^15-1
binInteger = strRepeat("0", 16 - LENGTH(binInteger)) + binInteger
ELSEIF integer >= -8388608 AND integer <= 8388607 THEN // -2^23〜2^23-1
binInteger = strRepeat("0", 24 - LENGTH(binInteger)) + binInteger
ELSEIF integer >= -2147783648 AND integer <= 2147483647 THEN // -2^31〜2^31-1
binInteger = strRepeat("0", 32 - LENGTH(binInteger)) + binInteger
ELSE
binInteger = strRepeat("0", 64 - LENGTH(binInteger)) + binInteger
ENDIF
ELSE
IFB integer <= 255 THEN // 2^8-1
binInteger = strRepeat("0", 8 - LENGTH(binInteger)) + binInteger
ELSEIF integer <= 65535 THEN // 2^16-1
binInteger = strRepeat("0", 16 - LENGTH(binInteger)) + binInteger
ELSEIF integer <= 16777215 THEN // 2^24-1
binInteger = strRepeat("0", 24 - LENGTH(binInteger)) + binInteger
ELSEIF integer <= 4294967295 THEN // 2^32-1
binInteger = strRepeat("0", 32 - LENGTH(binInteger)) + binInteger
ELSE
binInteger = strRepeat("0", 64 - LENGTH(binInteger)) + binInteger
ENDIF
ENDIF
totalDigits = LENGTH(binInteger + binDecimal)
IFB totalDigits > 64 THEN
DIM del32 = totalDigits - 32
DIM del64 = totalDigits - 64
IFB del32 = LENGTH(binDecimal) AND digits <> 64 THEN
binDecimal = ""
msg = "32bitを超えたため、小数点以下を削除しました"
ELSEIF del32 < LENGTH(binDecimal) AND digits <> 64 THEN
binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - del32)
msg = "32bitを超えたため、小数点以下の一部を削除しました"
ELSEIF del64 = LENGTH(binDecimal) AND del64 <> 0 THEN
binDecimal = ""
msg = "64bitを超えたため、小数点以下を削除しました"
ELSEIF del64 < LENGTH(binDecimal) THEN
binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - del64)
msg = "64bitを超えたため、小数点以下の一部を削除しました"
ELSE
msg = "64bitを超えるため、変換できません"
isError = TRUE
ENDIF
ENDIF
// 整数部、小数部の合計桁数を8,16,24,32,64bit単位になるまで拡張
digit = LENGTH(binInteger + binDecimal)
DIM array[] = 8, 16, 24, 32, 64
FOR item IN array
IFB digit <= item THEN
binInteger = strRepeat("0", item - digit) + binInteger
BREAK
ENDIF
NEXT
// 指定ビットに調整
// 合計桁数の再設定
totalDigits = LENGTH(binInteger + binDecimal)
IFB digits = TRUE THEN
// 桁合わせを自動調整
IFB totalDigits > 64 THEN
len = LENGTH(binInteger + binDecimal)
WHILE LENGTH(binInteger) > 8 AND len > digits
IFB COPY(binInteger, 1, 4) = "0000" THEN
binInteger = COPY(binInteger, 5)
len = len - 4
ELSE
BREAK
ENDIF
WEND
WHILE LENGTH(binDecimal) > 4 AND LENGTH(binInteger + binDecimal) > digits
IFB COPY(binDecimal, LENGTH(binDecimal) - 4) = "0000" THEN
binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - 4)
ELSE
BREAK
ENDIF
WEND
tmp = binInteger + "." + binDecimal
binInteger = COPY(tmp, 1, POS(".", tmp) - 1)
binDecimal = COPY(tmp, POS(".", tmp) + 1)
totalDigits = LENGTH(binInteger + binDecimal)
IFB totalDigits > 64 THEN
isError = TRUE
msg = "64bitを超えたため変換できません"
ENDIF
ENDIF
ELSE
// 指定ビットに調整
IFB totalDigits <= digits THEN
binInteger = strPad(binInteger, digits - LENGTH(binDecimal), "0", LEFT)
ELSE
// 桁あふれ調整
totalDigits = LENGTH(binInteger + binDecimal)
len = LENGTH(binInteger + binDecimal)
WHILE LENGTH(binInteger) > 8 AND len > digits
IFB COPY(binInteger, 1, 4) = "0000" THEN
binInteger = COPY(binInteger, 5)
len = len - 4
ELSE
BREAK
ENDIF
WEND
WHILE LENGTH(binDecimal) > 4 AND LENGTH(binInteger + binDecimal) > digits
IFB COPY(binDecimal, LENGTH(binDecimal) - 4) = "0000" THEN
binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - 4)
ELSE
BREAK
ENDIF
WEND
tmp = binInteger + "." + binDecimal
binInteger = COPY(tmp, 1, POS(".", tmp) - 1)
binDecimal = COPY(tmp, POS(".", tmp) + 1)
len = LENGTH(binInteger + binDecimal)
IFB len > digits THEN
DIM deleteLength = len - digits
IFB deleteLength = LENGTH(binDecimal) THEN
binDecimal = ""
msg = "指定ビット数にするため小数点以下を削除しました"
ELSEIF deleteLength < LENGTH(binDecimal) THEN
binDecimal = COPY(binDecimal, 1, LENGTH(binDecimal) - deleteLength)
msg = "指定ビット数にするため小数点以下の一部を削除しました"
ELSE
isError = TRUE
msg = "指定ビット数では変換できません"
ENDIF
ENDIF
ENDIF
ENDIF
bin = binInteger + IIF(binDecimal <> "", "." + binDecimal, "")
// (5) 入力値がマイナスのため、2進数をマイナス値に変換する
IFB negativeFlg THEN
// 1の補数
bin = bitNot(bin)
// 2の補数
DIM res = ""
DIM carry = "1"
FOR i = LENGTH(bin) TO 1 STEP -1
IFB carry = "1" THEN
SELECT COPY(bin, i, 1)
CASE "0"
res = "1" + res
carry = 0
CASE "1"
res = "0" + res
DEFAULT
res = COPY(bin, i, 1) + res
SELEND
ELSE
res = COPY(bin, i, 1) + res
ENDIF
NEXT
bin = res
ENDIF
ENDIF
IF errorMsg AND msg <> "" THEN PRINT msg
RESULT = IIF(isError, ERR_VALUE, bin)
FEND
//////////////////////////////////////////////////
// 【引数】
// dec : 10進数
// signFlg : 符号付きならばTrue
// digits : 変換した16進数の桁数合わせを自動で行うかを示すブール値、もしくは桁数を表す数値(8,16,24,32,64のいずれか)を指定
// errorMsg : エラーメッセージを出力するかを示すブール値
// 【戻り値】
// 16進数に変換した値
//////////////////////////////////////////////////
FUNCTION decToHex(dec, signFlg = FALSE, digits = FALSE, errorMsg = FALSE)
DIM hex = ""
DIM msg = ""
DIM isError = FALSE
DIM dec2hex[] = "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"
DIM decimalFlg = IIF(POS(".", dec) <> 0, TRUE, FALSE)
DIM negativeFlg = IIF(dec < 0, TRUE, FALSE)
dec = Decimal.absoluteValue(dec)//dec = ABS(dec)
// (1) 10進数を整数部と小数部に分ける
DIM integer = Decimal.floor(dec)
DIM decimal = Decimal.modulo(dec, "1")
// (2) 10進数(整数部)を16進数に変換する。
REPEAT
hex = dec2hex[Decimal.modulo(integer, 16)] + hex
integer = Decimal.truncated(Decimal.dividedBy(integer, 16))
UNTIL Decimal.equals(integer, 0)
// (3) 10進数(小数部)を16進数に変換する。
IFB decimalFlg THEN
hex = hex + "."
DIM loop = 0
REPEAT
loop = loop + 1
decimal = Decimal.times(decimal, 16)
hex = hex + dec2hex[decimal]
offset = Decimal.toPower(10, LENGTH(decimal) - POS(".", decimal))
decimal = Decimal.dividedBy(Decimal.minus(Decimal.times(decimal, offset), Decimal.times(Decimal.truncated(decimal), offset)), offset)
UNTIL Decimal.equals(decimal, 0) OR loop > 16
ENDIF
// digitsがFALSE以外ならば
IFB digits THEN
// (4) 16進数の桁合わせを行う
DIM tmp = hex
DIM hexInteger = TOKEN(".", tmp)
DIM hexDecimal = TOKEN(".", tmp)
// 整数部、小数部を4bit単位になるまで拡張
// 整数部、4の倍数になるまで整数部の先頭に'0'を追加
// ※16進数は4bit単位なのでこの処理は不要
DIM digit = LENGTH(hexInteger + hexDecimal)
integer = Decimal.truncated(dec)
IF signFlg AND COPY(hexToBin(hexInteger), 1, 1) = "1" THEN hexInteger = "0" + hexInteger
IFB signFlg THEN
WITH Decimal
IFB .greaterThanOrEqualTo(integer, -128) AND .lessThanOrEqualTo(integer, 127) THEN // -2^7〜2^7-1
hexInteger = strRepeat("0", 2 - LENGTH(hexInteger)) + hexInteger
ELSEIF .greaterThanOrEqualTo(integer, -32768) AND .lessThanOrEqualTo(integer, 32767) THEN // -2^15〜2^15-1
hexInteger = strRepeat("0", 4 - LENGTH(hexInteger)) + hexInteger
ELSEIF .greaterThanOrEqualTo(integer, -8388608) AND .lessThanOrEqualTo(integer, 8388607) THEN // -2^23〜2^23-1
hexInteger = strRepeat("0", 6 - LENGTH(hexInteger)) + hexInteger
ELSEIF .greaterThanOrEqualTo(integer, -2147783648) AND .lessThanOrEqualTo(integer, 2147483647) THEN // -2^31〜2^31-1
hexInteger = strRepeat("0", 8 - LENGTH(hexInteger)) + hexInteger
ELSE
hexInteger = strRepeat("0", 16 - LENGTH(hexInteger)) + hexInteger
ENDIF
ENDWITH
ELSE
WITH Decimal
IFB .lessThanOrEqualTo(integer, 255) THEN // 2^8-1
hexInteger = strRepeat("0", 2 - LENGTH(hexInteger)) + hexInteger
ELSEIF .lessThanOrEqualTo(integer, 65535) THEN // 2^16-1
hexInteger = strRepeat("0", 4 - LENGTH(hexInteger)) + hexInteger
ELSEIF .lessThanOrEqualTo(integer, 16777215) THEN // 2^24-1
hexInteger = strRepeat("0", 6 - LENGTH(hexInteger)) + hexInteger
ELSEIF .lessThanOrEqualTo(integer, 4294967295) THEN // 2^32-1
hexInteger = strRepeat("0", 8 - LENGTH(hexInteger)) + hexInteger
ELSE
hexInteger = strRepeat("0", 16 - LENGTH(hexInteger)) + hexInteger
ENDIF
ENDWITH
ENDIF
totalDigits = LENGTH(hexInteger + hexDecimal) * 4
// 64bitを超えたら
IFB totalDigits > 64 THEN
DIM del32 = totalDigits - 32
DIM del64 = totalDigits - 64
IFB del32 = LENGTH(hexDecimal) * 4 AND digits <> 64 THEN
hexDecimal = ""
msg = "32bitを超えたため、小数点以下を削除しました"
ELSEIF del32 < LENGTH(hexDecimal) * 4 AND digits <> 64 THEN
hexDecimal = COPY(hexDecimal, 1, (LENGTH(hexDecimal) * 4 - del32) / 4)
msg = "32bitを超えたため、小数点以下の一部を削除しました"
ELSEIF del64 = LENGTH(hexDecimal) * 4 AND del64 <> 0 THEN
hexDecimal = ""
msg = "64bitを超えたため、小数点以下を削除しました"
ELSEIF del64 < LENGTH(hexDecimal) * 4 THEN
hexDecimal = COPY(hexDecimal, 1, (LENGTH(hexDecimal) * 4 - del64) / 4)
msg = "64bitを超えたため、小数点以下の一部を削除しました"
ELSE
isError = TRUE
msg = "64bitを超えるため、変換できません"
ENDIF
ENDIF
// 整数部、小数部の合計桁数を8,16,24,32,64bit単位になるまで拡張
digit = LENGTH(hexInteger + hexDecimal) * 4
DIM array[] = 8, 16, 24, 32, 64
FOR item IN array
IFB digit <= item THEN
hexInteger = strRepeat("0", (item - digit) / 4) + hexInteger
BREAK
ENDIF
NEXT
totalDigits = LENGTH(hexInteger + hexDecimal) * 4
IFB digits = TRUE THEN
// 桁合わせを自動調整
IFB totalDigits > 64 THEN
digit = LENGTH(hexInteger + hexDecimal)
WHILE LENGTH(hexInteger) > 8 AND digit > digits
IFB COPY(hexInteger, 1, 1) = "0" THEN
digit = digit - 1
ELSE
BREAK
ENDIF
WEND
WHILE LENGTH(hexDecimal) * 4 > 4 AND LENGTH(hexInteger + hexDecimal) > digits
IFB COPY(hexDecimal, LENGTH(hexDecimal) - 1) = "0" THEN
hexDecimal = COPY(hexDecimal, 1, LENGTH(hexDecimal) - 1)
ELSE
BREAK
ENDIF
WEND
tmp = hexInteger + "." + hexDecimal
hexInteger = COPY(tmp, 1, POS(".", tmp) - 1)
hexDecimal = COPY(tmp, POS(".", tmp) + 1)
totalDigits = LENGTH(hexInteger + hexDecimal)
IFB totalDigits > 64 THEN
isError = TRUE
msg = "64bitを超えたため変換できません"
ENDIF
ENDIF
ELSE
// 指定ビットに調整
IFB totalDigits <= digits THEN
hexInteger = strPad(hexInteger, digits / 4 - LENGTH(hexDecimal), "0", LEFT)
ELSE
// 桁あふれ調整
totalDigits = LENGTH(hexInteger + hexDecimal)
digit = LENGTH(hexInteger + hexDecimal)
WHILE LENGTH(hexInteger) * 4 > 8 AND digit > digits
IFB COPY(hexInteger, 1, 1) = "0" THEN
hexInteger = COPY(hexInteger, 2)
digit = digit - 4 / 4
ELSE
BREAK
ENDIF
WEND
WHILE LENGTH(hexDecimal) * 4 > 4 AND LENGTH(hexInteger + hexDecimal) > digits
IFB COPY(hexDecimal, LENGTH(hexDecimal) - 1) = "0" THEN
hexDecimal = COPY(hexDecimal, 1, LENGTH(hexDecimal) - 1)
ELSE
BREAK
ENDIF
WEND
tmp = hexInteger + "." + hexDecimal
hexInteger = COPY(tmp, 1, POS(".", tmp) - 1)
hexDecimal = COPY(tmp, POS(".", tmp) + 1)
digit = LENGTH(hexInteger + hexDecimal) * 4
IFB digit > digits THEN
DIM deleteLength = digit - digits
IFB deleteLength = LENGTH(hexDecimal) * 4 THEN
hexDecimal = ""
msg = "指定ビット数にするため小数点以下を削除しました"
ELSEIF deleteLength < LENGTH(hexDecimal) * 4 THEN
hexDecimal = COPY(hexDecimal, 1, LENGTH(hexDecimal) - deleteLength / 4)
msg = "指定ビット数にするため小数点以下の一部を削除しました"
ELSE
isError = TRUE
msg = "指定ビット数では変換できません"
ENDIF
ENDIF
ENDIF
ENDIF
hex = hexInteger + IIF(hexDecimal <> "", "." + hexDecimal, "")
// (5) 入力値がマイナスのため、16進数をマイナス値に変換する
IFB negativeFlg THEN
bin = hexToBin(hex)
// 1の補数
bin = bitNot(bin)
// 2の補数
DIM res = ""
DIM carry = "1"
FOR i = LENGTH(bin) TO 1 STEP -1
IFB carry = "1" THEN
SELECT COPY(bin, i, 1)
CASE "0"
res = "1" + res
carry = 0
CASE "1"
res = "0" + res
DEFAULT
res = COPY(bin, i, 1) + res
SELEND
ELSE
res = COPY(bin, i, 1) + res
ENDIF
NEXT
hex = binToHex(res)
ENDIF
ENDIF
IF errorMsg AND msg <> "" THEN PRINT msg
RESULT = IIF(isError, ERR_VALUE, hex)
FEND
//////////////////////////////////////////////////
// 【引数】
// dividend : 被除数
// divisor : 除数
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION division(dividend, divisor)
DIM array[] = dividend, divisor
DIM g = GCD(array)
DIM tmp = divisor / g
DIM dat[] = 10, 5, 2
DIM position = 0
FOR i = 0 TO UBound(dat)
WHILE tmp MOD dat[i] = 0
tmp = INT(tmp / dat[i])
position = position + 1
WEND
NEXT
DIM repetend = ""
DIM res = ""
tmp = 0
i = 0
WHILE TRUE
DIM quotient = INT(dividend/divisor)
DIM remainder = dividend MOD divisor
IF i = position THEN tmp = remainder
IFB i > position THEN
repetend = repetend + quotient
ELSE
res = res + quotient
IF i = 0 THEN res = res + "."
ENDIF
IF i > position AND tmp = remainder THEN BREAK
dividend = remainder * 10
i = i + 1
WEND
RESULT = res + IIF(repetend<>0, "[" + repetend + "]", "")
FEND
//////////////////////////////////////////////////
// 【引数】
// num : 数値
// digits : 小数点以下の桁数
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION fixed(num, digits = EMPTY)
num = VAL(num) // 指数表記を整える
IFB POS("E-", num) THEN
DIM mantissa = BETWEENSTR(num,, "E")
DIM exponent = BETWEENSTR(num, "E")
RESULT = "0." + strRepeat("0", VAL(ABS(exponent) - 1)) + REPLACE(mantissa, ".", "")
ELSEIF POS("E", num) THEN
RESULT = ROUND(num, -1 *digits)
mantissa = BETWEENSTR(num,, "E")
exponent = BETWEENSTR(num, "E")
RESULT = REPLACE(mantissa, ".", "") + strRepeat("0", VAL(exponent) - decimalDigits(mantissa))
ELSEIF LENGTH(BETWEENSTR(num, ".")) < digits THEN
DIM keta = digits - LENGTH(BETWEENSTR(num, "."))
RESULT = num + IIF(POS(".", num) OR keta = 0, "", ".") + strRepeat("0", keta)
ELSE
IF digits = EMPTY THEN digits = LENGTH(BETWEENSTR(num, "."))
RESULT = "" + roundOff(num, digits)
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// num : 丸め処理を行う値
// 【戻り値】
// 負の方向に丸めた値
//////////////////////////////////////////////////
FUNCTION floor(num)
RESULT = INT(num) + IIF(num < 0 AND num <> INT(num), -1, 0)
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 最大公約数を求める数値を格納した配列
// 【戻り値】
// 最大公約数
//////////////////////////////////////////////////
FUNCTION GCD(array[])
DIM c = LENGTH(array)
DIM rem = array[c-1] MOD array[c-2]
IFB rem = 0 THEN
IFB LENGTH(array) = 2 THEN
RESULT = array[c-2]
EXIT
ENDIF
RESIZE(array, c-2)
RESULT = GCD(array)
EXIT
ENDIF
array[c-1] = array[c-2]
array[c-2] = rem
RESULT = GCD(array)
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 日付(”YYYYMMDD” or “YYYY/MM/DD” or “YYYY-MM-DD” or “YYYYMMDDHHNNSS” or “YYYY/MM/DD HH:NN:SS”)
// m : 第一引数の指定日からプラスマイナスm月とする
// 【戻り値】
// dateからm月後の月末の日付
//////////////////////////////////////////////////
FUNCTION getEndOfMonth(date, m = 0)
date = dateAdd("m", m + 1, date)
GETTIME(0, date)
GETTIME(-G_TIME_DD, date)
RESULT = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 日付文字列(”YYYYMMDD” or “YYYY/MM/DD” or “YYYY-MM-DD” or “YYYYMMDDHHNNSS” or “YYYY/MM/DD HH:NN:SS”)もしくはシリアル値
// type : 取得する曜日番号の種類を示す0〜3または11〜17の値。1と17は日曜日を1、2と11は月曜日を1とカウントします。11以降はExcel2010で追加された値で、互換性を保つために重複した値があります。
// 【戻り値】
// typeで指定した種類によって以下の値を返します。 : (0 : 0(日曜)〜6(土曜)、1 : 1(日曜)~7(土曜)、2 : 1(月曜)~7(日曜)、3 : 0(月曜)〜6(日曜)、11 : 1(月曜)~7(日曜)、12 : 1(火曜)~7(月曜)、13 : 1(水曜)~7(火曜)、14 : 1(木曜)~7(水曜)、15 : 1(金曜)~7(木曜)、16 : 1(土曜)~7(金曜)、17 : 1(日曜)~7(土曜))
//////////////////////////////////////////////////
FUNCTION getWeekday(date, type = 1)
IF VARTYPE(date) <> 258 THEN date = text(date, "yyyy/mm/dd")
GETTIME(0, date)
DIM w = G_TIME_WW
SELECT TRUE
CASE type = 0
RESULT = w
CASE type = 1
RESULT = w + 1
CASE type = 2
RESULT = IIF(w=0, 7, w)
CASE type = 3
RESULT = (w+6) MOD 7
CASE type >= 11
RESULT = ((getWeekday(date, 2) + 17 - type) MOD 7) + 1
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// str : ハッシュ化する文字列
// 【戻り値】
// ハッシュ化した文字列
//////////////////////////////////////////////////
MODULE Hash
DIM FSO = CREATEOLEOBJ("Scripting.FileSystemObject")
DIM path
PROCEDURE Hash()
CONST TemporaryFolder = 2
DIM Folder = FSO.GetSpecialFolder(TemporaryFolder)
DIM folderspec = Folder.Path
DIM filename = FSO.GetTempName
path = FSO.BuildPath(folderspec, filename)
FEND
FUNCTION md2(str)
DIM TextStream = FSO.CreateTextFile(path)
TextStream.Write(str)
TextStream.Close
RESULT = TRIM(DOSCMD("CertUtil -hashfile <#DBL>" + path + "<#DBL> MD2 | findstr /R <#DBL>^[0-9A-Fa-f][0-9A-Fa-f]*$<#DBL>"))
FSO.DeleteFile(path)
FEND
FUNCTION md4(str)
DIM TextStream = FSO.CreateTextFile(path)
TextStream.Write(str)
TextStream.Close
RESULT = TRIM(DOSCMD("CertUtil -hashfile <#DBL>" + path + "<#DBL> MD4 | findstr /R <#DBL>^[0-9A-Fa-f][0-9A-Fa-f]*$<#DBL>"))
FSO.DeleteFile(path)
FEND
FUNCTION md5(str)
DIM TextStream = FSO.CreateTextFile(path)
TextStream.Write(str)
TextStream.Close
RESULT = TRIM(DOSCMD("CertUtil -hashfile <#DBL>" + path + "<#DBL> MD5 | findstr /R <#DBL>^[0-9A-Fa-f][0-9A-Fa-f]*$<#DBL>"))
FSO.DeleteFile(path)
FEND
FUNCTION sha1(str)
DIM TextStream = FSO.CreateTextFile(path)
TextStream.Write(str)
TextStream.Close
RESULT = TRIM(DOSCMD("CertUtil -hashfile <#DBL>" + path + "<#DBL> SHA1 | findstr /R <#DBL>^[0-9A-Fa-f][0-9A-Fa-f]*$<#DBL>"))
FSO.DeleteFile(path)
FEND
FUNCTION sha256(str)
DIM TextStream = FSO.CreateTextFile(path)
TextStream.Write(str)
TextStream.Close
RESULT = TRIM(DOSCMD("CertUtil -hashfile <#DBL>" + path + "<#DBL> SHA256 | findstr /R <#DBL>^[0-9A-Fa-f][0-9A-Fa-f]*$<#DBL>"))
FSO.DeleteFile(path)
FEND
FUNCTION sha384(str)
DIM TextStream = FSO.CreateTextFile(path)
TextStream.Write(str)
TextStream.Close
RESULT = TRIM(DOSCMD("CertUtil -hashfile <#DBL>" + path + "<#DBL> SHA384 | findstr /R <#DBL>^[0-9A-Fa-f][0-9A-Fa-f]*$<#DBL>"))
FSO.DeleteFile(path)
FEND
FUNCTION sha512(str)
DIM TextStream = FSO.CreateTextFile(path)
TextStream.Write(str)
TextStream.Close
RESULT = TRIM(DOSCMD("CertUtil -hashfile <#DBL>" + path + "<#DBL> SHA512 | findstr /R <#DBL>^[0-9A-Fa-f][0-9A-Fa-f]*$<#DBL>"))
FSO.DeleteFile(path)
FEND
ENDMODULE
//////////////////////////////////////////////////
// 【引数】
// hex : 16進数
// 【戻り値】
// 2進数に変換した値
//////////////////////////////////////////////////
FUNCTION hexToBin(hex)
HASHTBL hb
hb["0"] = "0000"; hb["1"] = "0001"; hb["2"] = "0010"; hb["3"] = "0011";
hb["4"] = "0100"; hb["5"] = "0101"; hb["6"] = "0110"; hb["7"] = "0111";
hb["8"] = "1000"; hb["9"] = "1001"; hb["A"] = "1010"; hb["B"] = "1011";
hb["C"] = "1100"; hb["D"] = "1101"; hb["E"] = "1110"; hb["F"] = "1111";
DIM bin = ""
IFB POS(".", hex) <> 0 THEN
FOR i = 1 TO LENGTH(hex)
DIM str = COPY(hex, i, 1)
IF str = "." THEN bin = bin + "."
bin = bin + hb[str]
NEXT
ELSE
FOR i = 1 TO LENGTH(hex)
bin = bin + hb[COPY(hex, i, 1)]
NEXT
ENDIF
RESULT = bin
FEND
//////////////////////////////////////////////////
// 【引数】
// hex : 16進数
// signFlg : 符号付きならばTrue
// 【戻り値】
// 10進数に変換した値
//////////////////////////////////////////////////
FUNCTION hexToDec(hex, signFlg = TRUE)
hex = STRCONV(hex, SC_UPPERCASE)
DIM dec = 0
DIM decimalFlg = IIF(POS(".", hex) <> 0, TRUE, FALSE)
hex = IIF(LENGTH(REPLACE(hex,".", "" )) MOD 2 <> 0, "0", "") + hex
DIM negativeFlg = IIF(COPY(hexToBin(hex), 1, 1) = "1", TRUE, FALSE)
DIM sign = 1
IF negativeFlg AND signFlg THEN sign = -1
IFB negativeFlg AND signFlg THEN
DIM bin = hexToBin(hex)
DIM msb = IIF(decimalFlg, POS(".", bin) - 1, LENGTH(bin))
DIM lsb = IIF(decimalFlg, POS(".", bin) - LENGTH(bin), 0)
DIM a = hexToDec(hex, FALSE)
DIM b = POWER(2, msb) - 1
FOR i = -1 TO lsb STEP -1
b = b + POWER(2, i)
NEXT
DIM dec2 = bitXor(a, b) + POWER(2, lsb)
hex = decToHex(dec2)
ENDIF
integer = IIF(decimalFlg, COPY(hex, 1, POS(".", hex) - 1), hex)
decimal = IIF(decimalFlg, COPY(hex, POS(".", hex) + 1), "0")
FOR i = 1 TO LENGTH(integer)
s = COPY(hex, i, 1)
num = IIF(CHKNUM(s), s, ASC(s) - (ASC("A") - 10))
dec = dec + num * POWER(16, LENGTH(integer) - i)
NEXT
FOR i = 1 TO LENGTH(decimal)
s = COPY(decimal, i, 1)
num = IIF(CHKNUM(s), s, ASC(s) - (ASC("A") - 10))
dec = dec + num * POWER(16, -1 * i)
NEXT
RESULT = sign * dec
FEND
//////////////////////////////////////////////////
// 【引数】
// serial : シリアル値もしくは時刻文字列
// 【戻り値】
// 時刻から時間を表す0〜23の範囲の値
//////////////////////////////////////////////////
FUNCTION Hour(serial)
IF VARTYPE(serial) = 258 THEN serial = timeValue(serial)
RESULT = INT(serial * 24) MOD 24
FEND
//////////////////////////////////////////////////
// 【引数】
// expr : 評価する式
// truepart : 評価した式がTrueのときに返す値
// falsepart : 評価した式がFalseのときに返す値
// 【戻り値】
// truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
IFB EVAL(expr) THEN
RESULT = truepart
ELSE
RESULT = falsepart
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// r : 赤成分、Color値、もしくは#RRGGBB形式の文字列。
// g : 緑成分。rで赤成分以外の値を指定した場合は省略。
// b : 青成分。rで赤成分以外の値を指定した場合は省略。
// 【戻り値】
// 反転色
//////////////////////////////////////////////////
FUNCTION invertedColor(r, g = EMPTY, b = EMPTY)
IFB COPY(r, 1, 1) = "#" AND g = EMPTY AND b = EMPTY THEN
array = colorToRGB(RGBToColor(r))
FOR i = 0 TO UBound(array)
array[i] = 255 - array[i]
NEXT
DIM rgb = ""
FOR item IN array
DIM hex = decToHex(item)
rgb = rgb + COPY(hex, LENGTH(hex) - 1)
NEXT
RESULT = "#" + rgb
ELSEIF VAL(r) <> ERR_VALUE AND g = EMPTY AND b = EMPTY THEN
array = colorToRGB(r)
FOR i = 0 TO UBound(array)
array[i] = 255 - array[i]
NEXT
RESULT = RGBToColor(array[0], array[1], array[2])
ELSEIF VAL(r) <> ERR_VALUE AND VAL(g) <> ERR_VALUE AND VAL(b) <> ERR_VALUE THEN
array[0] = r
array[1] = g
array[2] = b
FOR i = 0 TO UBound(array)
array[i] = 255 - array[i]
NEXT
RESULT = SLICE(array)
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// variable : 型を調べる変数
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION isArray(variable[])
RESULT = IIF(VARTYPE(variable) AND 8192, TRUE, FALSE)
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 存在するかを調べる日付文字列。YYYYMMDD or YYYY/MM/DD or YYYY-MM-DDのいずれかの形式。
// 【戻り値】
// TRUE : 日付として認識できる、FALSE : 日付として認識できない
//////////////////////////////////////////////////
FUNCTION isDate(date)
TRY
GETTIME(0, date)
RESULT = TRUE
EXCEPT
RESULT = FALSE
ENDTRY
FEND
//////////////////////////////////////////////////
// 【引数】
// variable : 型を調べる変数
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION isFloat(variable)
IFB VAL(variable) <> ERR_VALUE THEN
RESULT = IIF((VARTYPE(variable) = VAR_SINGLE OR VARTYPE(variable) = VAR_DOUBLE) AND INT(variable) <> variable, TRUE, FALSE)
ELSE
RESULT = FALSE
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// variable : 型を調べる変数
// 【戻り値】
// : TRUE : 与えられた変数が文字列型である、
// FALSE : 与えられた変数が文字列型でない、 :
//////////////////////////////////////////////////
FUNCTION isString(variable)
RESULT = IIF(VARTYPE(variable) = VAR_ASTR OR VARTYPE(variable) = VAR_USTR, TRUE, FALSE)
FEND
//////////////////////////////////////////////////
// 【引数】
// text : JSONとして解析する文字列
// value : JSON文字列に変換する値
// reviver : 使用不可
// replacer : 使用不可
// space : 出力するJSON文字列に空白を挿入するための文字列もしくは数値
// 【戻り値】
// : Parse : JSON文字列をオブジェクトに変換、
// Stringify : オブジェクトをJSON文字列に変換、 :
//////////////////////////////////////////////////
MODULE JSON
DIM SC, CodeObject
PROCEDURE JSON
SC = CREATEOLEOBJ("ScriptControl")
WITH SC
.Language = "JScript"
.ExecuteStatement(json2)
.ExecuteStatement(statement)
CodeObject = .CodeObject
ENDWITH
FEND
FUNCTION Parse(text, reviver = NULL)
RESULT = CodeObject.JSON.parse(text, reviver)
FEND
FUNCTION Stringify(value, replacer = "", space = FALSE)
RESULT = CodeObject.JSON.stringify(value, NULL, replacer)
IF space THEN RESULT = REPLACE(RESULT, CHR(10), "<#CR>")
FEND
ENDMODULE
TEXTBLOCK statement
Array.prototype.Item = function(i, value){
if(value === undefined) return this[i]; this[i] = value;
}
Array.prototype.item = Array.prototype.Item;
ENDTEXTBLOCK
TEXTBLOCK json2
// json2.js
// 2023-05-10
// Public Domain.
// NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
// USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
// NOT CONTROL.
// This file creates a global JSON object containing two methods: stringify
// and parse. This file provides the ES5 JSON capability to ES3 systems.
// If a project might run on IE8 or earlier, then this file should be included.
// This file does nothing on ES5 systems.
// JSON.stringify(value, replacer, space)
// value any JavaScript value, usually an object or array.
// replacer an optional parameter that determines how object
// values are stringified for objects. It can be a
// function or an array of strings.
// space an optional parameter that specifies the indentation
// of nested structures. If it is omitted, the text will
// be packed without extra whitespace. If it is a number,
// it will specify the number of spaces to indent at each
// level. If it is a string (such as "\t" or " "),
// it contains the characters used to indent at each level.
// This method produces a JSON text from a JavaScript value.
// When an object value is found, if the object contains a toJSON
// method, its toJSON method will be called and the result will be
// stringified. A toJSON method does not serialize: it returns the
// value represented by the name/value pair that should be serialized,
// or undefined if nothing should be serialized. The toJSON method
// will be passed the key associated with the value, and this will be
// bound to the value.
// For example, this would serialize Dates as ISO strings.
// Date.prototype.toJSON = function (key) {
// function f(n) {
// // Format integers to have at least two digits.
// return (n < 10)
// ? "0" + n
// : n;
// }
// return this.getUTCFullYear() + "-" +
// f(this.getUTCMonth() + 1) + "-" +
// f(this.getUTCDate()) + "T" +
// f(this.getUTCHours()) + ":" +
// f(this.getUTCMinutes()) + ":" +
// f(this.getUTCSeconds()) + "Z";
// };
// You can provide an optional replacer method. It will be passed the
// key and value of each member, with this bound to the containing
// object. The value that is returned from your method will be
// serialized. If your method returns undefined, then the member will
// be excluded from the serialization.
// If the replacer parameter is an array of strings, then it will be
// used to select the members to be serialized. It filters the results
// such that only members with keys listed in the replacer array are
// stringified.
// Values that do not have JSON representations, such as undefined or
// functions, will not be serialized. Such values in objects will be
// dropped; in arrays they will be replaced with null. You can use
// a replacer function to replace those with JSON values.
// JSON.stringify(undefined) returns undefined.
// The optional space parameter produces a stringification of the
// value that is filled with line breaks and indentation to make it
// easier to read.
// If the space parameter is a non-empty string, then that string will
// be used for indentation. If the space parameter is a number, then
// the indentation will be that many spaces.
// Example:
// text = JSON.stringify(["e", {pluribus: "unum"}]);
// // text is '["e",{"pluribus":"unum"}]'
// text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
// // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
// text = JSON.stringify([new Date()], function (key, value) {
// return this[key] instanceof Date
// ? "Date(" + this[key] + ")"
// : value;
// });
// // text is '["Date(---current time---)"]'
// JSON.parse(text, reviver)
// This method parses a JSON text to produce an object or array.
// It can throw a SyntaxError exception.
// The optional reviver parameter is a function that can filter and
// transform the results. It receives each of the keys and values,
// and its return value is used instead of the original value.
// If it returns what it received, then the structure is not modified.
// If it returns undefined then the member is deleted.
// Example:
// // Parse the text. Values that look like ISO date strings will
// // be converted to Date objects.
// myData = JSON.parse(text, function (key, value) {
// var a;
// if (typeof value === "string") {
// a =
// /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
// if (a) {
// return new Date(Date.UTC(
// +a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]
// ));
// }
// return value;
// }
// });
// myData = JSON.parse(
// "[\"Date(09/09/2001)\"]",
// function (key, value) {
// var d;
// if (
// typeof value === "string"
// && value.slice(0, 5) === "Date("
// && value.slice(-1) === ")"
// ) {
// d = new Date(value.slice(5, -1));
// if (d) {
// return d;
// }
// }
// return value;
// }
// );
// This is a reference implementation. You are free to copy, modify, or
// redistribute.
/*jslint
eval, for, this
*/
/*property
JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (typeof JSON !== "object") {
JSON = {};
}
(function () {
"use strict";
var rx_one = /^[\],:{}\s]*$/;
var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
function f(n) {
// Format integers to have at least two digits.
return (n < 10)
? "0" + n
: n;
}
function this_value() {
return this.valueOf();
}
if (typeof Date.prototype.toJSON !== "function") {
Date.prototype.toJSON = function () {
return isFinite(this.valueOf())
? (
this.getUTCFullYear()
+ "-"
+ f(this.getUTCMonth() + 1)
+ "-"
+ f(this.getUTCDate())
+ "T"
+ f(this.getUTCHours())
+ ":"
+ f(this.getUTCMinutes())
+ ":"
+ f(this.getUTCSeconds())
+ "Z"
)
: null;
};
Boolean.prototype.toJSON = this_value;
Number.prototype.toJSON = this_value;
String.prototype.toJSON = this_value;
}
var gap;
var indent;
var meta;
var rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
rx_escapable.lastIndex = 0;
return rx_escapable.test(string)
? "\"" + string.replace(rx_escapable, function (a) {
var c = meta[a];
return typeof c === "string"
? c
: "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
}) + "\""
: "\"" + string + "\"";
}
function str(key, holder) {
// Produce a string from holder[key].
var i; // The loop counter.
var k; // The member key.
var v; // The member value.
var length;
var mind = gap;
var partial;
var value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (
value
&& typeof value === "object"
&& typeof value.toJSON === "function"
) {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === "function") {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case "string":
return quote(value);
case "number":
// JSON numbers must be finite. Encode non-finite numbers as null.
return (isFinite(value))
? String(value)
: "null";
case "boolean":
case "null":
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce "null". The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is "object", we might be dealing with an object or an array or
// null.
case "object":
// Due to a specification blunder in ECMAScript, typeof null is "object",
// so watch out for that case.
if (!value) {
return "null";
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === "[object Array]") {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || "null";
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0
? "[]"
: gap
? (
"[\n"
+ gap
+ partial.join(",\n" + gap)
+ "\n"
+ mind
+ "]"
)
: "[" + partial.join(",") + "]";
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === "object") {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === "string") {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (
(gap)
? ": "
: ":"
) + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (
(gap)
? ": "
: ":"
) + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0
? "{}"
: gap
? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}"
: "{" + partial.join(",") + "}";
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== "function") {
meta = { // table of character substitutions
"\b": "\\b",
"\t": "\\t",
"\n": "\\n",
"\f": "\\f",
"\r": "\\r",
"\"": "\\\"",
"\\": "\\\\"
};
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = "";
indent = "";
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === "number") {
for (i = 0; i < space; i += 1) {
indent += " ";
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === "string") {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== "function" && (
typeof replacer !== "object"
|| typeof replacer.length !== "number"
)) {
throw new Error("JSON.stringify");
}
// Make a fake root object containing our value under the key of "".
// Return the result of stringifying the value.
return str("", {"": value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== "function") {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k;
var v;
var value = holder[key];
if (value && typeof value === "object") {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
rx_dangerous.lastIndex = 0;
if (rx_dangerous.test(text)) {
text = text.replace(rx_dangerous, function (a) {
return (
"\\u"
+ ("0000" + a.charCodeAt(0).toString(16)).slice(-4)
);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with "()" and "new"
// because they can cause invocation, and "=" because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
// replace all simple value tokens with "]" characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or "]" or
// "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
if (
rx_one.test(
text
.replace(rx_two, "@")
.replace(rx_three, "]")
.replace(rx_four, "")
)
) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The "{" operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval("(" + text + ")");
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return (typeof reviver === "function")
? walk({"": j}, "")
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError("JSON.parse");
};
}
}());
ENDTEXTBLOCK
//////////////////////////////////////////////////
// 【引数】
// array : 配列
// rank : 抽出する値の大きい方から数えた順位
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION large(array[], rank)
IFB rank >= 1 AND rank <= LENGTH(array) THEN
shellSort(array)
RESULT = array[LENGTH(array) - rank]
ELSE
RESULT = ERR_VALUE
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現で検索した結果をMatchesコレクションとして返します。
//////////////////////////////////////////////////
FUNCTION reExecute(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Execute(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現にマッチするかどうかを示すブール値
//////////////////////////////////////////////////
FUNCTION reTest(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Test(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// r : 赤成分もしくは#RRGGBB形式の文字列
// g : 緑成分。rで#RRGGBB形式の文字列を指定した場合は省略。
// b : 青成分。rで#RRGGBB形式の文字列を指定した場合は省略。
// 【戻り値】
// Color値
//////////////////////////////////////////////////
FUNCTION RGBToColor(r, g = EMPTY, b = EMPTY)
IFB COPY(r, 1, 1) = "#" THEN
DIM color = 0
FOR i = 1 TO 3
color = color + VAL(hexToDec(COPY(r, i * 2, 2), FALSE)) * POWER(256, i - 1)
NEXT
RESULT = color
ELSE
RESULT = r + g * 256 + b * 65536
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// num : 数値
// digit : 四捨五入する位置(マイナスで整数方向)
// 【戻り値】
// 四捨五入した値
//////////////////////////////////////////////////
FUNCTION roundOff(num, digit = 0)
DIM sign = sign(num)
num = ABS(num)
DIM offset = POWER(10, digit)
DIM n = num * offset - INT(num * offset)
RESULT = sign * IIF(n >= 0.5, CEIL(num * offset) / offset, INT(num * offset) / offset)
FEND
//////////////////////////////////////////////////
// 【引数】
// serial : 時間を表すシリアル値を指定
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION Second(serial)
RESULT = REPLACE(FORMAT(INT(serial * 86400) MOD 60, 2), " ", "0")
FEND
//////////////////////////////////////////////////
// 【引数】
// array : ソートする数値を格納した配列。参照引数。
// 【戻り値】
//
//////////////////////////////////////////////////
PROCEDURE shellSort(Var array[])
DIM i, j, inc, temp
inc = 4
WHILE INT(inc) > 0
FOR i = 0 TO UBound(array)
j = i
temp = array[i]
WHILE j >= inc AND array[zcut(j-inc)] > temp
array[j] = array[j-inc]
j = j - inc
WEND
array[j] = temp
NEXT
IFB inc / 2 <> 0 THEN
inc = inc / 2
ELSEIF inc = 1 THEN
inc = 0
ELSE
inc = 1
ENDIF
WEND
FEND
//////////////////////////////////////////////////
// 【引数】
// num : 符号を求める数値
// 【戻り値】
// 1 : 正の数、0 : ゼロ、-1 : 負の数、ERR_VALUE : それ以外
//////////////////////////////////////////////////
FUNCTION sign(num)
SELECT TRUE
CASE !CHKNUM(num)
RESULT = ERR_VALUE
CASE num > 0
RESULT = 1
CASE num = 0
RESULT = 0
CASE num < 0
RESULT = -1
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 配列
// rank : 抽出する値の小さい方から数えた順位
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION small(array[], rank)
IFB rank >= 1 AND rank <= LENGTH(array) THEN
shellSort(array)
RESULT = array[rank-1]
ELSE
RESULT = ERR_VALUE
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// input : 入力文字列
// length : 埋めたあとの長さ
// str : 埋める文字
// type : 埋める方向
// 【戻り値】
// 指定文字で埋めた文字列
//////////////////////////////////////////////////
FUNCTION strPad(input, length, str = " ", type = RIGHT)
DIM s = ""
SELECT type
CASE LEFT
FOR i = 1 TO CEIL((length - LENGTH(input)) / LENGTH(str))
s = s + str
NEXT
input = COPY(s, 1, length - LENGTH(input)) + input
CASE RIGHT
FOR i = 1 TO CEIL((length - LENGTH(input)) / LENGTH(str))
s = s + str
NEXT
input = input + COPY(s, 1, length - LENGTH(input))
SELEND
RESULT = input
FEND
//////////////////////////////////////////////////
// 【引数】
// inputs : 繰り返す文字列
// multiplier : inputsを繰り返す回数
// 【戻り値】
// inputsをmultiplier回を繰り返した文字列を返します
//////////////////////////////////////////////////
FUNCTION strRepeat(inputs, multiplier)
DIM res = ""
FOR n = 1 TO multiplier
res = res + inputs
NEXT
RESULT = res
FEND
//////////////////////////////////////////////////
// 【引数】
// a : bと交換する値。参照引数。
// b : aと交換する値。参照引数。
// 【戻り値】
//
//////////////////////////////////////////////////
PROCEDURE swap(Var a, Var b)
DIM tmp = a
a = b
b = tmp
FEND
//////////////////////////////////////////////////
// 【引数】
// serial : シリアル値
// format : フォーマット
// 【戻り値】
// 数値を表示書式に基づいて変換した文字列
//////////////////////////////////////////////////
FUNCTION text(serial, format, hour12 = FALSE)
HASHTBL startDate
startDate["明治"] = "1868/01/25"
startDate["大正"] = "1912/07/30"
startDate["昭和"] = "1926/12/25"
startDate["平成"] = "1989/01/08"
startDate["令和"] = "2019/05/01"
DIM baseDate = "1899/12/30"
serial = VAL(serial)
SELECT TRUE
CASE reTest(format, "\[h+\]")
Matches = reExecute(format, "\[(h+)\]")
DIM hour = iif(hour12, Hour(serial) MOD 12, Hour(serial))
RESULT = text(hour, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE reTest(format, "^h+$")
Matches = reExecute(format, "^(h+)$")
hour = iif(hour12, Hour(serial) MOD 12, Hour(serial))
RESULT = text(hour MOD 24, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE reTest(format, "\[m+\]")
Matches = reExecute(format, "\[(m+)\]")
RESULT = text(serial * 1440, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE format = "m"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_MM, "0")
CASE format = "mm"
GETTIME(serial, baseDate)
RESULT = G_TIME_MM2
CASE format = "n"
GETTIME(serial, baseDate)
RESULT = G_TIME_NN
CASE format = "nn"
GETTIME(serial, baseDate)
RESULT = G_TIME_NN2
CASE format = "s"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_SS, "0")
CASE format = "ss"
GETTIME(serial, baseDate)
RESULT = G_TIME_SS2
CASE format = "yyyy"
GETTIME(serial, baseDate)
RESULT = G_TIME_YY4
CASE format = "yy"
GETTIME(serial, baseDate)
RESULT = COPY(G_TIME_YY4, 3, 2)
CASE format = "e"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 2018
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1988
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1925
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1911
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1867
SELEND
CASE format = "ee"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 2018, "00")
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1988, "00")
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1925, "00")
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1911, "00")
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1867, "00")
SELEND
CASE format = "g"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "R"
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "H"
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "S"
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "T"
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "M"
SELEND
CASE format = "gg"
RESULT = COPY(text(serial, "ggg"), 1, 1)
CASE format = "ggg"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "令和"
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "平成"
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "昭和"
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "大正"
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "明治"
SELEND
CASE format = "mmmmm"
RESULT = COPY(text(serial, "mmmm"), 1, 1)
CASE format = "mmmm"
DIM month[] = "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
RESULT = month[text(serial, "m") - 1]
CASE format = "mmm"
RESULT = COPY(text(serial, "mmmm"), 1, 3)
CASE format = "dd"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_DD2, "00")
CASE format = "d"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_DD, "0")
CASE reTest(format, "^[ad]{3,4}$")
Matches = reExecute(format, "([ad]{3,4})")
GETTIME(serial, baseDate)
DIM aaa[] = "日", "月", "火", "水", "木", "金", "土"
DIM aaaa[] = "日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"
DIM ddd[] = "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
DIM dddd[] = "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday";
RESULT = EVAL(Matches.Item(0).SubMatches(0) + "[" + getWeekday(G_TIME_WW, 1) + "]")
CASE reTest(format, "(0+\.?0+)?%")
Matches = reExecute(format, "(0+\.?0+)?%")
RESULT = text(serial * 100, Matches.Item(0).SubMatches(0)) + "%"
CASE reTest(format, "^\[DBNum\d{1,4}\](.*?)$")
Matches = reExecute(format, "^\[DBNum(\d{1,4})\](.*?)$")
DIM value = VAL(Matches.Item(0).SubMatches(0))
DIM sss = text(serial, Matches.Item(0).SubMatches(1))
Matches = reExecute(sss, "(\D+)?(\d+)(\D+)?")
DIM res = ""
FOR m = 0 TO Matches.Count - 1
serial = Matches.Item(m).SubMatches(1)
SELECT value
CASE 1, 2
DIM n[][9] = "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九", + _
"", "壱", "弐", "参", "四", "伍", "六", "七", "八", "九"
DIM a[][3] = "", "十", "百", "千", + _
"", "拾", "百", "阡"
DIM b[][3] = "", "万", "億", "兆", + _
"", "萬", "億", "兆"
DIM r = ""
DIM j = 0
type = value - 1
REPEAT
DIM str = ""
DIM n4 = serial MOD 10000
FOR i = LENGTH(n4) TO 1 STEP -1
s = COPY(n4, i, 1)
IFB s = 1 AND a[type][LENGTH(n4)-i] <> "" THEN
str = IIF(s, a[type][LENGTH(n4)-i], "") + str
ELSE
str = n[type][s] + IIF(s, a[type][LENGTH(n4)-i], "") + str
ENDIF
NEXT
IF str <> "" THEN r = str + b[type][j] + r
j = j + 1
serial = INT(serial / 10000)
UNTIL serial = 0
res = res + Matches.Item(m).SubMatches(0) + r + Matches.Item(m).SubMatches(2)
CASE 3
res = res + Matches.Item(m).SubMatches(0) + STRCONV(serial, SC_FULLWIDTH) + Matches.Item(m).SubMatches(2)
CASE 4
res = res + Matches.Item(m).SubMatches(0) + STRCONV(serial, SC_HALFWIDTH) + Matches.Item(m).SubMatches(2)
SELEND
NEXT
RESULT = res
CASE reTest(format, "^(.*?)(AM\/PM|am\/pm|A\/P|a\/p)(.*?)$")
Matches = reExecute(format, "^(.*?)(AM\/PM|am\/pm|A\/P|a\/p)(.*?)$")
DIM array = SPLIT(Matches.Item(0).SubMatches(1), "/")
ampm = array[IIF(serial - INT(serial) >= 0.5, 1, 0)]
hour12 = TRUE
res = ""
WITH Matches.Item(0)
res = text(serial, .SubMatches(0), hour12) + ampm + text(serial, .SubMatches(2), hour12)
ENDWITH
RESULT = res
CASE reTest(format, "([^ymdagehns]{0,})?(([ymdagehns])\3{0,})([^ymdagehns]+)?")
Matches = reExecute(format, "([^ymdagehns]{0,})?(([ymdagehns])\3{0,})([^ymdagehns]+)?")
FOR n = 0 TO Matches.Count - 1
IF n = 0 THEN res = Matches.Item(n).SubMatches(0)
NEXT
FOR n = 0 TO Matches.Count - 1
WITH Matches.Item(n)
res = res + text(serial, .SubMatches(1), hour12) + .SubMatches(3)
ENDWITH
NEXT
RESULT = res
CASE format = "0/0"
DIM separator = POS(".", serial)
DIM g = 0
IFB separator <> 0 THEN
DIM keta = LENGTH(serial)
DIM shift = POWER(10, keta - separator)
IFB shift >= POWER(10, 15) THEN
DIM position = 0
FOR i = 0 TO 14
IFB serial * POWER(10, i) - serial >= 1 THEN
position = i
BREAK
ENDIF
NEXT
tmp = serial * POWER(10, position)
FOR i = 1 TO 15
r = (tmp * POWER(10, i)) / serial - (tmp / serial)
a1 = tmp * POWER(10, i) - tmp
IF a1 = INT(a1) THEN BREAK
NEXT
DIM frac[] = a1, r
g = GCD(frac)
RESULT = (a1/g) + "/" + (r/g)
ELSE
DIM molecule = serial * shift // 分子
DIM denominator = shift // 分母
DIM nums[] = molecule, denominator
g = GCD(nums)
molecule = molecule / g
denominator = denominator / g
RESULT = molecule + "/" + denominator
ENDIF
ELSE
RESULT = serial + "/1"
ENDIF
CASE reTest(format, "(0+)\.?(0+)?") AND UBound(SPLIT(format, ".")) <= 1
Matches = reExecute(format, "(0+)\.?(0+)?")
len1 = LENGTH(Matches.Item(0).SubMatches(0))
len2 = LENGTH(Matches.Item(0).SubMatches(1))
DIM arr[] = LENGTH(INT(serial)), len1
IFB POS(".", format) THEN
RESULT = REPLACE(FORMAT(serial, CALCARRAY(arr, CALC_MAX) + len2 + 1, len2), " ", "0")
ELSE
RESULT = REPLACE(FORMAT(serial, CALCARRAY(arr, CALC_MAX)), " ", "0")
ENDIF
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 時刻文字列。hh:nn:ss AM/PM、hh:nn AM/PM、hh AM/PM、hh:nn:ss、hh:nn、hh時nn分ss秒、hh時nn分のいずれかの形式を指定。
// 【戻り値】
// シリアル値 (例)0…00:00:00、0.5…12:00:00、0.999988425925926…23:59:59
//////////////////////////////////////////////////
FUNCTION timeValue(str)
DIM serial = 0
DIM Matches
DIM pattern = "(\d+)"
DIM hh = "(0?[0-9]|1[0-2])"
DIM ampm = "([AP]M|[ap]m)"
SELECT TRUE
CASE reTest(str, "\b" + hh + ":" + pattern + ":" + pattern + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + ":" + pattern + ":" + pattern + " " + ampm + "\b")
WITH Matches.Item(0)
serial = timeValue(.SubMatches(0) + " " + .SubMatches(3)) + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + hh + ":" + pattern + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + ":" + pattern + " " + ampm + "\b")
WITH Matches.Item(0)
serial = timeValue(.SubMatches(0) + " " + .SubMatches(2)) + VAL(.SubMatches(1)) / 1440
ENDWITH
CASE reTest(str, "\b" + hh + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + " " + ampm + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0) MOD 12) + IIF(reTest(.SubMatches(1), "AM|am"), 0, 12)
serial = serial / 24
ENDWITH
CASE reTest(str, "\b" + pattern + ":" + pattern + ":" + pattern + "\b")
Matches = reExecute(str, "\b" + pattern + ":" + pattern + ":" + pattern + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + pattern + ":" + pattern + "\b")
Matches = reExecute(str, "\b" + pattern + ":" + pattern + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440
ENDWITH
CASE reTest(str, "\b" + pattern + "時" + pattern + "分" + pattern + "秒")
Matches = reExecute(str, "\b" + pattern + "時" + pattern + "分" + pattern + "秒")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + pattern + "時" + pattern + "分")
Matches = reExecute(str, "\b" + pattern + "時" + pattern + "分")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440
ENDWITH
DEFAULT
serial = ERR_VALUE
SELEND
RESULT = serial - INT(serial)
FEND
//////////////////////////////////////////////////
// 【引数】
// arrayname : 上限値を求める配列の名前
// dimension : 返す次元を示す整数
// 【戻り値】
// 配列の上限値
//////////////////////////////////////////////////
FUNCTION UBound(arrayname[], dimension = 1)
RESULT = EVAL("RESIZE(arrayname" + strRepeat("[0]", dimension - 1) + ")")
FENDOPTION LOGPATH = "CLKITEM.log"
OPTION LOGFILE = 6
HASHTBL ITEMS
ITEMS["ITM_BTN"] = "CLK_BTN"
ITEMS["ITM_LIST"] = "CLK_LIST"
ITEMS["ITM_TAB"] = "CLK_TAB"
ITEMS["ITM_MENU"] = "CLK_MENU"
ITEMS["ITM_TREEVIEW"] = "CLK_TREEVIEW"
ITEMS["ITM_LISTVIEW"] = "CLK_LISTVIEW"
ITEMS["ITM_TOOLBAR"] = "CLK_TOOLBAR"
ITEMS["ITM_LINK"] = "CLK_LINK"
ITEMS["ITM_ACCCLK"] = "CLK_ACC"
FOR sec = 3 TO 1 STEP -1
FUKIDASI(sec + "秒後にアクティブなウィンドウの情報を取得します。")
SLEEP(1.000)
NEXT
DIM ID = GETID(GET_ACTIVE_WIN)
PRINT "DIM ID = GETID(<#DBL>" + STATUS(ID, ST_TITLE) + "<#DBL>, <#DBL>" + STATUS(ID, ST_CLASS) + "<#DBL>)"
PRINT
FUKIDASI("ID = " + ID + " " + STATUS(ID, ST_TITLE) + " " + STATUS(ID, ST_CLASS) + " 取得中")
FOR i = 0 TO LENGTH(ITEMS) - 1
PRINT "//////////////////////////////////////////////////"
PRINT "// " + ITEMS[i, HASH_KEY]
PRINT "//////////////////////////////////////////////////"
PRINT "GETITEM(ID, " + ITEMS[i, HASH_KEY] + ", -1) = " + GETITEM(ID, EVAL(ITEMS[i, HASH_KEY]), -1)
FOR j = 0 TO LENGTH(ALL_ITEM_LIST) - 1
str = ALL_ITEM_LIST[j]
str = REPLACE(str, "<#CR>", "<@cr>")
str = REPLACE(str, "<#DBL>", "<@dbl>")
str = REPLACE(str, "<#TAB>", "<@tab>")
str = REPLACE(str, CHR(10), "<#DBL>+CHR(10)+<#DBL>")
str = REPLACE(str, "<@", "<#")
PRINT " ALL_ITEM_LIST[" + j + "] = <#DBL>" + str + "<#DBL> // CLKITEM(ID, <#DBL>" + str + "<#DBL>, " + ITEMS[i, HASH_VAL] + ")"
NEXT
PRINT
NEXTOPTION LOGPATH = "CHKBTN.log"
OPTION LOGFILE = 6
HASHTBL ITEMS
DIM array[] = "BTN", "TAB", "MENU"
FOR sec = 3 TO 1 STEP -1
FUKIDASI(sec + "秒後にアクティブなウィンドウの情報を取得します。")
SLEEP(1.000)
NEXT
DIM ID = GETID(GET_ACTIVE_WIN)
FUKIDASI("ID = " + ID + " " + STATUS(ID, ST_TITLE) + " " + STATUS(ID, ST_CLASS) + " 取得中")
FOR item IN array
FOR i = 0 TO EVAL("GETITEM(ID, ITM_" + item + ", -1, -1)") -1
IF ALL_ITEM_LIST[i] = "" THEN CONTINUE
ITEMS[ALL_ITEM_LIST[i]] = ""
NEXT
NEXT
PRINT "DIM ID = GETID(<#DBL>" + STATUS(ID, ST_TITLE) + "<#DBL>, <#DBL>" + STATUS(ID, ST_CLASS) + "<#DBL>)"
PRINT
FOR i = 0 TO LENGTH(ITEMS)-1
item = ITEMS[i, HASH_KEY]
DIM n = 0
WHILE TRUE
n = n + 1
DIM flg = FALSE
FOR j = 0 TO 1
DIM acc = VARTYPE(j, VAR_BOOLEAN)
cmd = "CHKBTN(ID, <#DBL>" + item + "<#DBL>, " + n + ", " + acc + ")"
IFB EVAL(cmd) <> -1 THEN
flg = TRUE
PRINT cmd + "<#TAB>// " + EVAL(cmd)
BREAK
ENDIF
NEXT
IF !flg THEN BREAK
WEND
NEXTOPTION LOGPATH = "GETSTR.log"
OPTION LOGFILE = 6
FOR sec = 3 TO 1 STEP -1
FUKIDASI(sec + "秒後にアクティブなウィンドウの情報を取得します。")
SLEEP(1.000)
NEXT
DIM ID = GETID(GET_ACTIVE_WIN)
PRINT "DIM ID = GETID(<#DBL>" + STATUS(ID, ST_TITLE) + "<#DBL>, <#DBL>" + STATUS(ID, ST_CLASS) + "<#DBL>)"
PRINT
FUKIDASI("ID = " + ID + " " + STATUS(ID, ST_TITLE) + " " + STATUS(ID, ST_CLASS) + " 取得中")
HASHTBL ITEMS
ITEMS["STR_EDIT"] = STR_EDIT
ITEMS["STR_STATIC"] = STR_STATIC
ITEMS["STR_STATUS"] = STR_STATUS
ITEMS["STR_ACC_EDIT"] = STR_ACC_EDIT
ITEMS["STR_ACC_STATIC"] = STR_ACC_STATIC
HASHTBL COUNT
COUNT["STR_EDIT"] = GETITEM(ID, ITM_EDIT, -1)
COUNT["STR_STATIC"] = GETITEM(ID, ITM_STATIC, -1)
COUNT["STR_STATUS"] = GETITEM(ID, ITM_STATUSBAR, -1)
COUNT["STR_ACC_EDIT"] = GETITEM(ID, ITM_ACCTXT, -1)
COUNT["STR_ACC_STATIC"] = GETITEM(ID, ITM_ACCTXT, -1)
FOR i = 0 TO LENGTH(ITEMS) - 1
DIM item = ITEMS[i, HASH_KEY]
DIM len = COUNT[item]
PRINT "//////////////////////////////////////////////////"
PRINT "// " + item
PRINT "//////////////////////////////////////////////////"
FOR j = 0 TO len - 1
GETSTRList(id, i, j, ITEMS)
NEXT
FOR j = 0 TO (-1 * (len - 1)) STEP -1
GETSTRList(id, i, j, ITEMS)
NEXT
PRINT
NEXT
PROCEDURE GETSTRList(id, i, j, ITEMS[])
DIM str = GETSTR(id, j, ITEMS[i, HASH_VAL])
IFB LENGTH(str) <> 0 THEN
res = "PRINT GETSTR(ID, " + j + ", " + ITEMS[i, HASH_KEY] + ")" + "<#TAB>// <#DBL>" + str + "<#DBL>"
IFB j <> 0 THEN
IFB ITEMS[i,HASH_KEY] = "STR_EDIT" THEN
res = res + "<#TAB>// SENDSTR(ID, <#DBL>" + str + "<#DBL>, " + j + ", TRUE)"
ELSEIF ITEMS[i, HASH_KEY] = "STR_ACC_EDIT" THEN
res = res + "<#TAB>// SENDSTR(ID, <#DBL>" + str + "<#DBL>, " + j + ", TRUE, TRUE)"
ENDIF
ENDIF
PRINT res
ENDIF
FENDOPTION LOGPATH = "GETITEM.log"
OPTION LOGFILE = 6
FOR sec = 3 TO 1 STEP -1
FUKIDASI(sec + "秒後にアクティブなウィンドウの情報を取得します。")
SLEEP(1.000)
NEXT
DIM ID = GETID(GET_ACTIVE_WIN)
PRINT "DIM ID = GETID(<#DBL>" + STATUS(ID, ST_TITLE) + "<#DBL>, <#DBL>" + STATUS(ID, ST_CLASS) + "<#DBL>)"
PRINT
FUKIDASI("ID = " + ID + " " + STATUS(ID, ST_TITLE) + " " + STATUS(ID, ST_CLASS) + " 取得中")
DIM array[] = "BTN", "LIST", "TAB", "MENU", "TREEVIEW", "LISTVIEW", "EDIT", "STATIC", "STATUSBAR", "TOOLBAR", "LINK", "ACCCLK", "ACCCLK2", "ACCEDIT", "FROMLAST", "BACK"
FOR item IN array
PRINT "//////////////////////////////"
PRINT "// " + item + ""
PRINT "//////////////////////////////"
DIM num = GETITEM(ID, EVAL("ITM_" + item), -1)
PRINT "GETITEM(ID, ITM_" + item + ", -1) = " + num
FOR i = 0 TO num - 1
PRINT "CLKITEM(ID, <#DBL>" + ALL_ITEM_LIST[i] + "<#DBL>, CLK_" + item + ")"
NEXT
PRINT
NEXTOPTION LOGPATH = "GETSLCTLST.log"
OPTION LOGFILE = 6
FOR sec = 3 TO 1 STEP -1
FUKIDASI(sec + "秒後にアクティブなウィンドウの情報を取得します。")
SLEEP(1.000)
NEXT
DIM ID = GETID(GET_ACTIVE_WIN)
PRINT "DIM ID = GETID(<#DBL>" + STATUS(ID, ST_TITLE) + "<#DBL>, <#DBL>" + STATUS(ID, ST_CLASS)+ "<#DBL>)"
PRINT
DIM i = 0
DIM cnt = 0
REPEAT
DIM str = GETSLCTLST(ID, i)
IFB str = "" THEN
cnt = cnt + 1
ELSE
PRINT "GETSLCTLST(ID, " + i + ") = <#DBL>" + str + "<#DBL>"
cnt = 0
ENDIF
i = i + 1
UNTIL str = "" AND cnt >= 10SENDSTR(0, STRCONV(GETSTR(0), SC_UPPERCASE))
FUKIDASI("大文字に変換しました")
SLEEP(0.500)SENDSTR(0, STRCONV(GETSTR(0), SC_LOWERCASE))
FUKIDASI("小文字に変換しました")
SLEEP(0.500)SENDSTR(0, STRCONV(GETSTR(0), SC_HIRAGANA)
FUKIDASI("ひらがなに変換しました")
SLEEP(0.500)SENDSTR(0, STRCONV(GETSTR(0), SC_KATAKANA)
FUKIDASI("カタカナに変換しました")
SLEEP(0.500)SENDSTR(0, STRCONV(GETSTR(0), SC_HALFWIDTH)
FUKIDASI("半角文字に変換しました")
SLEEP(0.500)SENDSTR(0, STRCONV(GETSTR(0), SC_FULLWIDTH)
FUKIDASI("全角文字に変換しました")
SLEEP(0.500)設定
- 低レベル記録
- 低レベル記録は 単純にキーボードとマウスの押し下げ情報を座標と共に低レベル関数で記録します。
記録はマウスクリックかキー操作がされるか、又は マウス移動を0.5秒停止して開始した所から始まります。
- 余分な時間、マウス移動は記録しない
- ここがチェックされていれば マウス移動や余分な時間は記録されません
- マウス座標を相対座標で記録する
- ここがチェックされていれば マウスの座標はアクティブウィンドウに対しての座標で記録されます(後で位置調整の為スクリプトを修正するのであれば、こちら方が良いでしょう)
- 高レベル記録
- 高レベル記録は 高レベル関数を使用して記録します、座標は記録されません。オブジェクトの選択操作は必ずマウスでしてください、キーボードで選択操作をした場合は記録できません。操作はゆっくり実行してください、速いと取りこぼす事があります。多段メニューはメニューが出る毎にクリックを実行してください。記録できないアプリやオブジェクトがあります。
- 記録後クリップボードへコピーする
- 記録終了後、スクリプトをクリップボードへコピーします
- ホットキー
-
- 再生
- 再生ボタンのホットキーを設定します
- 停止
- 再生/記録の停止ホットキーを設定します
- 記録
- 記録ボタンのホットキーを設定します
- トレイ
- タスクトレイ出入りのホットキーを設定します
ホットキーは以下の組み合わせから選択します。
- 母体キー
-
- CTRL
- WIN
- ALT
- SHIFT+CTRL
- SHIFT+ALT
- CTRL+ALT
- 組み合わせるキー
-
- SPACE
- F1
- F2
- F3
- F4
- F9
- F10
- F11
- F12
- ↑
- ↓
- →
- ←
- Q
- W
- E
- R
- A
- S
- D
- F
- End
- Home
- F5
- F6
- F7
- F8
- T
- Y
- U
- I
- O
- P
- G
- H
- J
- K
- L
- Z
- X
- C
- V
- B
- N
- M
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 0
プルダウンメニューそのままの順番で書いていますが、組み合わせるキーはまとめると以下のようになります。
- アルファベット(A〜Z)
- 数字(0〜9)
- ファンクションキー(F1〜F12)
- スペース(Space)
- 矢印(上下左右)
- Home・End
- スケジューラー
- スクリプトのスケジュール設定画面を開きます。スケジュール設定を参照。
スケジュール設定
スクリプトのスケジュール設定ができます。スクリプトファイル名を設定してタイマー設定にて起動時間を指定してください。
休止状態から復帰するがチェックであればサスペンド状態からでも復帰し実行できます。ビープ音で知らせるがチェックであればスクリプト起動時にビープ音で知らせて間を2秒程取ります。
スクリプトの項目には、タイマーに登録するスクリプトのパスと実行回数を設定します。インプットボックスに直接パスを入力するか、...で登録するファイルを選択、実行回数を設定します。インプットボックスに直接入力する場合、スクリプトのパス -R<実行回数>の形式で入力します。実行回数が1回だけの場合スクリプトのパスと入力し、-Rnを省略することができます。
タイマーの項目(初期値:設定なし)を選択すると、実行するタイミングを設定できます。現在設定されている項目で設定なし、起動時、N分毎、H時間毎、HH:NN:<毎日|毎週|毎月>:<曜日|日付>、YYYYMMDD:HH:NN:一回。<式>、win:<Title>:<Class>のいずれかの形式が表示されます。
スケジュールしたスクリプトを実行するにはUWSCが起動している必要があります。毎日など設定している場合は、スタートアップにUWSC.exeを指定してタスクトレイに常駐させておくと良いです。
タイマー設定
- 設定なし
- タイマー設定を行いません。[設定なし]を選択し
OK で確定すると、他の項目に入力していた内容は破棄されます。 - UWSC起動時
- UWSCが起動したときにスクリプトを実行します。
- インターバル
- 0時0分を基準に計算をしています (UWSC起動時からの時間ではない)
分単位:1分毎,2分毎,3分毎,4分毎,5分毎,10分毎,15分毎,20分毎,30分毎
時間単位:1時間毎,2時間毎,3時間毎,4時間毎,6時間毎,8時間毎,12時間毎
- 時間指定
- 毎日、毎週日~土、毎月1~31のいずれかを指定します。
- 一回だけ実行
- 指定した日時に一回だけ実行されます。
- 式による設定
- 自分で式を記述する事により細かな時間設定が決められます
式の書き方は、式による設定で使える変数・演算子を参照。
注意:チェックは分単位でされます、分単位の設定(NN,YMDNN)を忘れずに
NN,YMDNNを記述しないと毎分実行されることになります。 - 指定Windowが現れた時
- タイトルとクラス名のどちらか一方だけでも可
タイトルは一部分だけでも可
指定Windowのタイトルと実行するスクリプト名が部分一致するとスクリプトが無限に起動するので注意
Windowと実行するスクリプト名は違う名前をつけてください - 別プロセスで実行
- 別プロセスで実行します
スクリプト実行中でも起動する事ができます
式による設定で使える変数・演算子
変数
| 変数 | 意味 |
|---|---|
| YY | 年 |
| MM | 月 |
| DD | 日 |
| HH | 時 |
| NN | 分 |
| YMDNN | 2000年からの経過分 |
| WW | 曜日(日=0、月=1、火=2、水=3、木=4、金=5、土=6) |
以下は指定した日時のYMDNN(2000年からの経過分)を求めるプログラムです。
DIM date = "2021/09/17 15:01:00"
PRINT INT(GETTIME(0, date) / 60)以下は現在のYMDNNを表示するプログラムです。1分毎に1ずつ増加されていきます。
WHILE TRUE
DIM YMDNN = INT(GETTIME()/60)
FUKIDASI(YMDNN)
SLEEP(0.100)
WEND論理演算子
論理演算子は、論理式や条件式を組み合わせて論理的な判定や演算を行うための演算子です。一般的には、論理演算子は真偽値(真または偽)を扱います。
| 演算子 | 意味 | 使用例 | 意味 |
|---|---|---|---|
| AND | 論理積 | a AND b | a、bともに真 |
| OR | 論理和 | a OR b | a、bのいずれかが真 |
算術演算子
一定間隔で実行するとき利用します。
| 演算子 | 意味 | 使用例 | 意味 |
|---|---|---|---|
| MOD | 剰余演算子 | a MOD b | aをbで割った余り |
比較演算子
比較演算子は、2つの値を比較して真偽値(真または偽)を返すための演算子です。
| 演算子 | 意味 | 使用例 | 意味 |
|---|---|---|---|
| < | より小さい | a < b | aはbより小さい |
| > | より大きい | a > b | aはbより大きい |
| = | 等しい | a = b | aとbは等しい |
| <> | 等しくない | a <> b | aとbは等しくない |
| <= | 以下 | a <= b | aはb以下 |
| >= | 以上 | a >= b | aはb以上 |
式による設定
指定した式に一致する日時にスクリプトを実行します。
以下に式の書き方を記載していますが、式として指定するときはYMDNNまたはNNとともに指定する必要があるので注意してください。毎分実行されることになります。
毎日12時00分
HH = 12 AND NN = 0毎日0時00分、2時00分、4時00分、…、22時00分
HH MOD 2 = 0 AND NN = 0休日(日または土)
WW = 0 OR WW = 6日:0、土:6なので6で割った余りが0でも土日と判定できます。
WW MOD 6 = 0平日(月〜金)
WW >= 1 AND WW <= 5土日は6で割った余りが0だったので、平日は余りが0以外で判定できます。
WW MOD 6 <> 0min分毎に実行する場合は、剰余関数(MOD)を利用します。
YMDNN MOD min = 020分毎に実行する場合は以下のようになります。毎時0分、20分、40分。
YMDNN MOD 20 = 0min分毎で実行日時をoffsetだけ時間をずらす場合は、以下のように記述します。
YMDNN MOD min = offset毎時5分、35分(min:30分毎、offset:+5分)
YMDNN MOD 30 = 5
(YMDNN - 5) MOD 30 = 0offsetがマイナス値になる場合は、以下のようにoffsetにminを加えます。
YMDNN MOD min = offset + min毎時17分、37分、57分(min:20分毎、offset:-3分)
17は-3+20(offset+min)から求められます。
YMDNN MOD 20 = 17
(YMDNN + 3) MOD 20 = 0以下の式はoffsetがマイナス値になるかどうかに関係なく使えます。
(YMDNN - offset) MOD min = 0記述例
火曜日の0時と12時
(WW=2) AND (HH=0 OR HH=12) AND (NN=0)18分間隔
(YMDNN MOD 18) = 0分が00のとき(1時間毎)
NN = 0分の一の位が「3」の時間(毎時3,13,23,33,43,53分)
(NN MOD 10) = 3分が55分以降(毎時55,56,57,58,59分)
NN >= 55休日(土日)の12:00
WW MOD 6 = 0 AND HH = 12 AND NN = 0平日(月〜金)の18:00
WW MOD 6 <> 0 AND HH = 18 AND NN = 0毎月1日の0:00
DD = 1 AND HH = 0 AND NN = 0存在しない変数や演算子を使ったとき、1年以内に実行する予定がないときは以下のメッセージが表示されます。
実行する日時が複雑な場合は、スクリプトを複数に分けてスケジュールに登録するのも良いと思います。
以下は式がマッチする日時を取得します。
5行目のFOR文で終了値を60 * 24 * 7(現在時刻から一週間までに一致する日時)にしてますが、もっと大きい値を入れるとより先の日時まで求められます。
- Main
- FUNCTIONS
DIM base = INT(GETTIME()/60)
DIM formula = INPUT("式を入力")
IF formula = EMPTY OR formula = "" THEN EXIT
FOR minute = 1 TO 60 * 24 * 7
DIM date = dateAdd("n", base + minute, "2000/01/01 00:00:00")
GETTIME(0, date)
DIM YY = G_TIME_YY
DIM MM = G_TIME_MM
DIM DD = G_TIME_DD
DIM HH = G_TIME_HH
DIM NN = G_TIME_NN
DIM WW = G_TIME_WW
DIM YMDNN = base + minute
IFB EVAL(formula) THEN
PRINT dateAdd("n", YMDNN, "2000/01/01 00:00:00") + IIF(HH=0 AND NN=0, " 00:00:00", "")
ENDIF
NEXT//////////////////////////////////////////////////
// 【引数】
// interval : 加算する時間間隔を表す文字列式(yyyy:年、m:月、d:日、ww:週、h:時、n:分、s:秒)
// num : dateに加算する値。未来は正、過去は負で指定
// date : 時間間隔を加算する日付
// 【戻り値】
// 日時(date)に、指定した単位(interval)の時間(num)を加算して返します
//////////////////////////////////////////////////
FUNCTION dateAdd(interval, num, date)
DIM year, month, day, d
GETTIME(0, date)
DIM time = G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2
SELECT interval
CASE "yyyy"
d = (G_TIME_YY + num) + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
IF time <> "00:00:00" THEN d = d + " " + time
CASE "m"
IFB num > 0 THEN
year = G_TIME_YY + INT((G_TIME_MM + num) / 12)
month = REPLACE(FORMAT(((G_TIME_MM + num) MOD 12), 2), " ", "0")
ELSE
year = G_TIME_YY + CEIL((G_TIME_MM + num) / 12 - 1)
month = REPLACE(FORMAT(G_TIME_MM - (ABS(num) MOD 12), 2), " ", "0")
ENDIF
IF month = "00" THEN month = 12
day = G_TIME_DD2
d = "" + year + month + day
IFB !isDate(d) THEN
d = year + "/" + month + "/" + "01"
d = getEndOfMonth(d)
ELSE
d = year + "/" + month + "/" + day
ENDIF
IF time <> "00:00:00" THEN d = d + " " + time
CASE "d"
t = GETTIME(num, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "ww"
t = GETTIME(num * 7, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "h"
t = GETTIME(num / 24, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "n"
t = GETTIME(num / 1440, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "s"
t = GETTIME(num / 86400, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
SELEND
RESULT = d
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 日付(”YYYYMMDD” or “YYYY/MM/DD” or “YYYY-MM-DD” or “YYYYMMDDHHNNSS” or “YYYY/MM/DD HH:NN:SS”)
// m : 第一引数の指定日からプラスマイナスm月とする
// 【戻り値】
// dateからm月後の月末の日付
//////////////////////////////////////////////////
FUNCTION getEndOfMonth(date, m = 0)
date = dateAdd("m", m + 1, date)
GETTIME(0, date)
GETTIME(-G_TIME_DD, date)
RESULT = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
FEND
//////////////////////////////////////////////////
// 【引数】
// expr : 評価する式
// truepart : 評価した式がTrueのときに返す値
// falsepart : 評価した式がFalseのときに返す値
// 【戻り値】
// truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
IFB EVAL(expr) THEN
RESULT = truepart
ELSE
RESULT = falsepart
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 存在するかを調べる日付文字列。YYYYMMDD or YYYY/MM/DD or YYYY-MM-DDのいずれかの形式。
// 【戻り値】
// TRUE : 日付として認識できる、FALSE : 日付として認識できない
//////////////////////////////////////////////////
FUNCTION isDate(date)
TRY
GETTIME(0, date)
RESULT = TRUE
EXCEPT
RESULT = FALSE
ENDTRY
FEND指定Windowが現れた時
指定したWindowが現れた時にスクリプトを実行します。
ウィンドウのタイトルとクラス名を取得するプログラムです。Alt+Cでクリップボードにマウスカーソル下のウインドウのタイトルとクラス名を送ります。
PUBLIC ttl, cls
SETHOTKEY(VK_ESC, EMPTYPARAM, "forceQuit")
SETHOTKEY(VK_C, MOD_ALT, "sendToClipboard")
WHILE TRUE
DIM ID = GETID(GET_FROMPOINT_WIN)
ttl = STATUS(ID, ST_TITLE)
cls = STATUS(ID, ST_CLASS)
FUKIDASI(ttl + "<#CR>" + cls)
SLEEP(0.001)
WEND
PROCEDURE forceQuit()
EXITEXIT
FEND
PROCEDURE sendToClipboard()
SENDSTR(0, ttl + "," + cls)
FUKIDASI("コピーしました")
SLEEP(1.000)
FENDランチメニュ
スクリプトファイルを登録しておき選択起動できます
(スクリプトファイル以外の EXEや関連付けされたファイル等も登録できます)
ホットキー設定により出現 タスクトレイ時は左ボタンにて出現
RecIE
- 記録/停止
- 指定したURLを開いたところから記録を開始し、停止が押されるまで記録されます。
- 再生
- 記録したスクリプトを再生します。
- 保存
- 生成されたスクリプトを保存します。
- 設定
- 記録時の設定をします。
右クリックメニュー
- 表示項目の取得
- マウス位置の表示項目を取得します。
- クリック処理
- JavaScript処理、画像等で通常クリックで記録できない場合やURLではなくオブジェクト文字として記録したい場合に利用します。
- ページに戻る
- 表示ページを戻します。
- HTMLの取得
- HTMLのbody部を取得します。範囲設定されている場合はその部分のみを取得します。
Debugger
プログラムが複雑になってくると実行時に間違いを見つけることは困難になります。そこでデバッグを行うことで効率的にコーディングすることができるようになります。
左側がスクリプトを記述するスクリプト表示領域、右側上段がグローバル変数表示、中段がローカル変数表示、下段がPRINT文 ログ表示でPRINT文で出力した内容が表示されます。出力するログの1行が長くなる場合は、1024文字毎に折り返されます。
行番号をクリックするとブレークポイントを設定でき、実行時にその行で一時停止させることができます。その時点での変数の値が右欄に表示されるため、間違いを見つけやすくなります。OPTION、PUBLIC、CONST、PROCEDURE、FUNCTION、TEXTBLOCK、ENDTEXTBLOCK、MODULEの行にはブレークポイントを設定することはできません。
グローバル・ローカル変数表示
モジュール
モジュール名.関数名
モジュール名.配列[ ]起動時パラメータ
PARAM_STR[ ]Array of配列
一次元配列
配列名[ ]一次元セーフ配列
配列名->[ ]ニ次元配列
配列名[ ][ ]ニ次元セーフ配列
配列名->[ ][ ]連想配列
連想配列名[ ]Valueは以下のように表示されます。
キー1:値1, キー2:値2, キー3:値3, …変数の型
| 番号 | 型 | 意味 |
|---|---|---|
| 0 | Empty | EMPTY |
| 1 | Null | NULL |
| 2 | SmallInt | 数値 |
| 3 | Integer | 数値 |
| 4 | Single | 数値 |
| 5 | Double | 数値 |
| 6 | Currency | 通貨型 |
| 7 | Date | 日付型 |
| 8 | UString | 文字型 |
| 9 | Dispatch | ポインター |
| 10 | ||
| 11 | Boolean | ブール型 |
| 12 | ||
| 13 | ||
| 16 | Char | バイト型(符号付) |
| 17 | Byte | バイト型(符号なし) |
| 18 | Word | 数値 |
| 19 | LongWord | 数値 |
| 20 | Int64 | 数値 |
| 256 | ||
| 258 | ||
| 8192 |
Debuggerのメニュー
Debuggerにあるメニューは以下の通りです。
- Script
-
プログラムはC:\Program Files(x86)\UWSC\DbgScript\にあります。
- Info Under MouseCursor
- マウスカーソル下の情報を取得します
- ObjectCharacter By Type
- 指定ウィンドウの全オブジェクトの文字を種類別に取得
- Object With Handle
- ハンドルを持つオブジェクトの情報取得
- PosAcc Search
- PosAcc関数にて画面をサーチし情報取得
- Option
-
- Cross Reference
- クロスリファレンスリスト(変数や関数の使用行表示)の起動。利用されていない変数や関数は赤で表示されます。行番号をダブルクリックするとデバッガをその行に移動します。
- Transparent Window...
- デバッガ自身もしくはデバッガに重なるアクティブWindowを透過処理
- Font / Color
- フォント設定や文字カラーの設定をします
- Uws2Exe
- EXE化ツールを起動します
- Help
-
- Debugger Help
- UDebugのヘルプ(UDebug.chm)を開きます。ファイルのパスはC:\Program Files (x86)\UWSC\UDebug.chmです。
- UWSC Help
- UWSCのヘルプ(uwsc.chm)を開きます。ファイルのパスはC:\Program Files (x86)\UWSC\uwsc.chmです。
- .INI/.LOG Folder
- エクスプローラにて、UDebug.INIのあるフォルダを開きます。フォルダのパスはC:\Users\username\AppData\Roaming\UWSC\です。
- About
- バージョン情報を表示します。最新版は2016/10/15でUWSC Ver5.2.3.0、UDebug Ver2.2.3.0です。
Scriptにあるプログラム
-
C:\Program Files (x86)\UWSC\DbgScript
- Info_Under_MouseCursor.uws
- Object_With_Handle.uws
- ObjectCharacter_By_Type.uws
- PosAcc_Search.uws
- Info_Under_MouseCursor.uws
- Object_With_Handle.uws
- ObjectCharacter_By_Type.uws
- PosAcc_Search.uws
// マウスカーソル下の情報取得
// Windowタイトル, Windowクラス名, クライアント位置, オブジェクトクラス名, POSACC, 色
//
title = "マウスカーソル下の情報"
if GETID(title, "TFormhtm")>0 then Exit
dbg_id = GETID("UWSC Debugger","TFOya")
CtrlWin(dbg_id, MIN)
Try
obj = CREATEFORM("about:blank", title, True, 0, 400, 210, 0 ,0)
CONST MAX_LENGTH = 64 // Maximum number of characters
CtrlWin(GETID(GET_FORM_WIN), ACTIVATE)
while obj.Visible
Sleep(0.5)
if GetKeyState(VK_ESC) then break
x=G_MOUSE_X; y=G_MOUSE_Y
fm = def_form
fpid = GETID(GET_FROMPOINT_WIN)
objid = GETID(GET_FROMPOINT_OBJ)
gx = G_MOUSE_X
gy = G_MOUSE_Y
clx = gx - Status(fpid,ST_CLX)
cly = gy - Status(fpid,ST_CLY)
fm = Replace(fm, "DEF_WTITLE", Status(fpid,ST_TITLE))
fm = Replace(fm, "DEF_WCLASS", Status(fpid,ST_CLASS))
fm = Replace(fm, "DEF_X", clx)
fm = Replace(fm, "DEF_Y", cly)
fm = Replace(fm, "DEF_OBJCLS", Status(objid,ST_CLASS))
s = POSACC(fpid, clx, cly)
if Length(s)>MAX_LENGTH then s = Copy(s,1,MAX_LENGTH)+"..."
fm = Replace(fm, "DEF_ACC", s)
gbr = PEEKCOLOR(gx, gy)
gbr16 = Replace(Format(gbr,6,-1)," ","0")
fm = Replace(fm, "DEF_BGR", "$"+gbr16)
fm = Replace(fm, "DEF_R", gbr and $FF)
fm = Replace(fm, "DEF_G", (gbr/$100) and $FF)
fm = Replace(fm, "DEF_B", (gbr/$10000) and $FF)
fm = Replace(fm, "DEF_FNTCOL", Copy(gbr16,5,2)+Copy(gbr16,3,2)+Copy(gbr16,1,2)) // RGB
obj.Document.open()
obj.Document.write(fm)
obj.Document.close()
wend
Finally
CtrlWin(dbg_id, NORMAL)
EndTry
// --- main end ---
// 表示フォーム
TextBlock def_form
<nobr>
Windowタイトル: DEF_WTITLE<br>
Windowクラス名: DEF_WCLASS<br>
クライアント位置: DEF_X, DEF_Y<br>
オブジェクトクラス名: DEF_OBJCLS<br>
POSACC: DEF_ACC<br>
色:BGR=DEF_BGR (R=DEF_R, G=DEF_G, B=DEF_B) <font color='#DEF_FNTCOL'>■■■■■</font>
</nobr>
EndTextBlock// ハンドルを持つオブジェクトの情報取得
// "X, Y, 幅, 高さ, クラス名, キャプション" (可視状態の物のみ、位置はクライアント座標)
//
dbg_id = GETID("UWSC Debugger","TFOya")
CtrlWin(dbg_id, MIN)
Try
Fukidasi("ハンドルを持つオブジェクトの情報の表示<#CR> ウィンドウにカーソルを合わせから Shiftキーを押してください<#CR> キャンセル: ESCキー")
Repeat
if GetKeyState(VK_ESC) then Exit
Sleep(0.02)
Until GetKeyState(VK_SHIFT)
Fukidasi()
PUBLIC fpid, form, lcnt
fpid = GETID(GET_FROMPOINT_WIN)
form = "X, Y, 幅, 高さ, <#DBL>クラス名<#DBL>, <#DBL>キャプション<#DBL>"
form = form + "<BR><select name='hlist' size='_DEF_SIZE_'>"
lcnt = 0
HndInfo(fpid, 0)
form = form + "</select>"
if lcnt < 2 then lcnt = 2
form = Replace(form, "_DEF_SIZE_", lcnt)
obj = CREATEFORM("about:blank", "ハンドル所持オブジェクト", True, 0, 540, 360, 0 ,0)
obj.Document.write(form)
OLEEVENT(obj.Document.body.all["hlist"], "HTMLSelectElementEvents2", "onclick", "fucOnClick")
CtrlWin(GETID(GET_FORM_WIN), ACTIVATE)
Rectan("<#DBL><#DBL>")
while obj.Visible
if GetKeyState(VK_ESC) then break
Sleep(0.1)
wend
CtrlWin(GETID(GET_FORM_WIN), NOTOPMOST)
Rectan("")
Finally
CtrlWin(dbg_id, NORMAL)
EndTry
// --- main end ---
// ハンドル再帰所得
CONST LVL_MARK = " > " // Level indication
CONST MAX_LENGTH = 64 // Maximum number of characters
Procedure HndInfo(id, lvl)
if lvl = 0
s = ""
else
s = (Status(id,ST_CLX)-Status(fpid,ST_CLX))+", "+(Status(id,ST_CLY)-Status(fpid,ST_CLY))+", "+Status(id,ST_WIDTH)+", "+Status(id,ST_HEIGHT)+", "
endif
titl = Status(id,ST_TITLE)
if Length(titl)>MAX_LENGTH then titl = Copy(titl,1,MAX_LENGTH)+"..."
s = s +"<#DBL>"+ Status(id,ST_CLASS) +"<#DBL>, <#DBL>"+ titl +"<#DBL>"
if Pos(s, form)>0 then Exit
form = form + "<option>" + Format(LVL_MARK,lvl*Length(LVL_MARK)) + s + "</option>"
lcnt = lcnt + 1
for n = 0 to GETALLWIN(id)-1
HndInfo(ALL_WIN_ID[n], lvl+1)
next
Fend
// クリックされた
Procedure fucOnClick()
if ! Status(fpid, ST_ISID) then Exit
Rectan(GETFORMDATA("hlist")) // Draw rectangle
Fend
// 赤四角描画
DEF_DLL GetDC(Hwnd):long:user32
DEF_DLL ReleaseDC(Hwnd, Long):long:user32
DEF_DLL SelectObject(long, long):long:gdi32
DEF_DLL Rectangle(long, long, long, long, long):long:gdi32
DEF_DLL CreatePen(long, long, long):long:gdi32
DEF_DLL GetStockObject(long):long:gdi32
DEF_DLL DeleteObject(long):long:gdi32
CONST PS_SOLID = 0
CONST NULL_BRUSH = 5
Procedure Rectan(s)
CtrlWin(fpid, NOTOPMOST) // Clear old line
CtrlWin(GETID(GET_FORM_WIN), TOPNOACTV)
if s = "" then Exit
dc = GetDC(0)
pen = CreatePen(PS_SOLID, 3, $0000FF)
SelectObject(dc, pen)
SelectObject(dc, GetStockObject(NULL_BRUSH))
if Copy(s, 1, 1) = "<#DBL>" // Top Level
x1 = Status(fpid,ST_CLX)
y1 = Status(fpid,ST_CLY)
x2 = x1 + Status(fpid,ST_CLWIDTH)
y2 = y1 + Status(fpid,ST_CLHEIGHT)
else
s = Replace(s, Trim(LVL_MARK), "") // Delete Level mark
ary = Split(s, ",", True, True)
x1 = ary[0] + Status(fpid,ST_CLX)
y1 = ary[1] + Status(fpid,ST_CLY)
x2 = x1 + ary[2]
y2 = y1 + ary[3]
endif
Rectangle(dc, x1, y1, x2, y2)
DeleteObject(pen)
ReleaseDC(0, dc)
Fend// 指定ウィンドウの全オブジェクトの文字を種類別に取得
// "ボタン", "リスト/コンボ", "タブ", "メニュー", "ツリービュ", "リストビュ", "エディト", "リンク",
// "スタテック文字", "ACCクリック可", "ACCテキスト", "ツールバー", "ステータスバー"
// (注:IEに適用すると ITM_STATUSBAR, ITM_TOOLBARにて IE側でエラーが出る事がある)
//
dbg_id = GETID("UWSC Debugger","TFOya")
CtrlWin(dbg_id, MIN)
Try
Fukidasi("オブジェクトの文字を種類別に取得<#CR> ウィンドウにカーソルを合わせから Shiftキーを押してください<#CR> キャンセル: ESCキー")
Repeat
if GetKeyState(VK_ESC) then Exit
Sleep(0.02)
Until GetKeyState(VK_SHIFT)
Fukidasi()
Option OPTFINALLY
thread chkESC()
dim oname[] = "ボタン", "リスト/コンボ", "タブ", "メニュー", "ツリービュ", "リストビュ", "エディト", "リンク", "スタテック文字", "ACCクリック可", "ACCテキスト", "ACCエディト", "ツールバー", "ステータスバー"
dim okind[] = ITM_BTN, ITM_LIST, ITM_TAB, ITM_MENU, ITM_TREEVEW, ITM_LSTVEW, ITM_EDIT, ITM_LINK, ITM_STATIC, ITM_ACCCLK, ITM_ACCTXT, ITM_ACCEDIT, ITM_TOOLBAR, ITM_STATUSBAR
CONST MAX_LENGTH = 64 // Maximum number of characters
fpid = GETID(GET_FROMPOINT_WIN)
Fukidasi("サーチ中 (キャンセル:ESCキー)", 0, 0)
ACW(fpid)
lcnt = 0
form = "<select name='hlist' size='_DEF_SIZE_'>"
for x = 0 to Length(oname)-1
form = form + "<optgroup label='" + oname[x] + "'>"
for y = 0 to GETITEM(fpid, okind[x])-1
s = ALL_ITEM_LIST[y]
if Length(s)>MAX_LENGTH then s = Copy(s,1,MAX_LENGTH)+"..."
form = form + "<option>" + s + "</option>"
lcnt = lcnt + 1
next
form = form + "</optgroup>"
lcnt = lcnt + 1
next
form = form + "</select>"
form = Replace(form, "_DEF_SIZE_", lcnt)
Fukidasi()
obj = CREATEFORM("about:blank", "種類別オブジェクト文字", True, 0, 540, 360, 0 ,0)
obj.Document.write(form)
CtrlWin(GETID(GET_FORM_WIN), ACTIVATE)
while obj.Visible
Sleep(0.1)
wend
Finally
CtrlWin(dbg_id, NORMAL)
EndTry
// --- main end ---
// ESCキーによる終了
Procedure chkESC()
while True
if GetKeyState(VK_ESC) then ExitExit
Sleep(0.1)
wend
Fend// PosAcc関数にて画面をサーチし情報取得
// "X, Y, 幅, 高さ, ACC_ACC/ACC_API, ACC_NAME, ACC_VALUE" (位置はクライアント座標)
//
CONST DEF_XW = 20 // Matrix size X
CONST DEF_YH = 8 // Matrix size Y
dbg_id = GETID("UWSC Debugger","TFOya")
CtrlWin(dbg_id, MIN)
Try
Fukidasi("POSACCにて画面をサーチし情報を取得<#CR> ウィンドウにカーソルを合わせから Shiftキーを押してください<#CR> キャンセル: ESCキー")
Repeat
if GetKeyState(VK_ESC) then Exit
Sleep(0.02)
Until GetKeyState(VK_SHIFT)
Fukidasi()
CONST MAX_LENGTH = 64 // Maximum number of characters
PUBLIC fpid
fpid = GETID(GET_FROMPOINT_WIN)
Fukidasi("サーチ中 (キャンセル:ESCキー)", 0, 0)
ACW(fpid)
hashtbl tbl
for y = DEF_YH/2 to Status(fpid,ST_CLHEIGHT) step DEF_YH
for x = DEF_XW/2 to Status(fpid,ST_CLWIDTH) step DEF_XW
if GetKeyState(VK_ESC) then Exit
MMV(Status(fpid,ST_CLX)+x, Status(fpid,ST_CLY)+y)
if GETID(GET_FROMPOINT_WIN) <> fpid then Continue
loc = PosAcc(fpid, x, y, ACC_LOCATION or ACC_BACK)
if tbl[loc, HASH_EXISTS] then Continue
s1=PosAcc(fpid,x,y,ACC_BACK); if Length(s1)>MAX_LENGTH then s1=Copy(s1,1,MAX_LENGTH)+"..."
s2=PosAcc(fpid,x,y,ACC_NAME or ACC_BACK); if Length(s2)>64 then s2=Copy(s2,1,MAX_LENGTH)+"..."
s3=PosAcc(fpid,x,y,ACC_VALUE or ACC_BACK); if Length(s3)>64 then s3=Copy(s3,1,MAX_LENGTH)+"..."
tbl[loc] = s1+", "+s2+", "+s3
next
next
Fukidasi()
if Status(fpid, ST_WIN64)
form = "X, Y, 幅, 高さ, ACC_ACC, ACC_NAME, ACC_VALUE" // 64bit: not support ACC_API
else
form = "X, Y, 幅, 高さ, ACC_ACC/ACC_API, ACC_NAME, ACC_VALUE"
endif
form = form + "<BR><select name='hlist' size='_DEF_SIZE_'>"
lcnt = 0
for n = 0 to Length(tbl)-1
vs = tbl[n, HASH_VAL]
if Trim(Replace(vs, ",", "")) = "" then Continue
form = form + "<option>" + tbl[n, HASH_KEY] +", "+ vs + "</option>"
lcnt = lcnt + 1
next
form = form + "</select>"
if lcnt < 2 then lcnt = 2
form = Replace(form, "_DEF_SIZE_", lcnt)
obj = CREATEFORM("about:blank", "ACC 情報サーチ", True, 0, 540, 360, 0 ,0)
obj.Document.write(form)
OLEEVENT(obj.Document.body.all["hlist"], "HTMLSelectElementEvents2", "onclick", "fucOnClick")
CtrlWin(GETID(GET_FORM_WIN), ACTIVATE)
Rectan("<#DBL><#DBL>")
while obj.Visible
if GetKeyState(VK_ESC) then break
Sleep(0.1)
wend
CtrlWin(GETID(GET_FORM_WIN), NOTOPMOST)
Rectan("")
Finally
CtrlWin(dbg_id, NORMAL)
EndTry
// --- main end ---
// クリックされた
Procedure fucOnClick()
if ! Status(fpid, ST_ISID) then Exit
Rectan(GETFORMDATA("hlist")) // Draw rectangle
Fend
// 赤四角描画
DEF_DLL GetDC(Hwnd):long:user32
DEF_DLL ReleaseDC(Hwnd, Long):long:user32
DEF_DLL SelectObject(long, long):long:gdi32
DEF_DLL Rectangle(long, long, long, long, long):long:gdi32
DEF_DLL CreatePen(long, long, long):long:gdi32
DEF_DLL GetStockObject(long):long:gdi32
DEF_DLL DeleteObject(long):long:gdi32
CONST PS_SOLID = 0
CONST NULL_BRUSH = 5
Procedure Rectan(s)
CtrlWin(fpid, NOTOPMOST) // Clear old line
CtrlWin(GETID(GET_FORM_WIN), TOPNOACTV)
if s = "" then Exit
dc = GetDC(0)
pen = CreatePen(PS_SOLID, 3, $0000FF)
SelectObject(dc, pen)
SelectObject(dc, GetStockObject(NULL_BRUSH))
if Copy(s, 1, 1) = "<#DBL>" // Top Level
x1 = Status(fpid,ST_CLX)
y1 = Status(fpid,ST_CLY)
x2 = x1 + Status(fpid,ST_CLWIDTH)
y2 = y1 + Status(fpid,ST_CLHEIGHT)
else
ary = Split(s, ",", True, True)
x1 = ary[0] + Status(fpid,ST_CLX)
y1 = ary[1] + Status(fpid,ST_CLY)
x2 = x1 + ary[2]
y2 = y1 + ary[3]
endif
Rectangle(dc, x1, y1, x2, y2)
DeleteObject(pen)
ReleaseDC(0, dc)
Fendsampleにあるプログラム
-
sample
- Calc.uws
- Excel.uws
- GruGru.uws
- IEFlash.uws
- IEtoExcel.uws
- サンプル.uws
- システム情報.uws
- タイトルクラス.uws
- タスクトレイ.uws
- ディレクトリ木.uws
- バックグラウンド.uws
- ポップアップメニュ.uws
- メール送信.uws
- 音声認識.uws
- 画像保存.uws
- 計算フォーム.uws
- 入力フォーム.uws
- 文字情報.uws
- 文字変換.uws
- Calc.uws
- Excel.uws
- GruGru.uws
- IEFlash.uws
- IEtoExcel.uws
- サンプル.uws
- システム情報.uws
- タイトルクラス.uws
- タスクトレイ.uws
- ディレクトリ木.uws
- バックグラウンド.uws
- ポップアップメニュ.uws
- メール送信.uws
- 音声認識.uws
- 画像保存.uws
- 計算フォーム.uws
- 入力フォーム.uws
- 文字情報.uws
- 文字変換.uws
// フォームを使用した電卓
while True
btn = CREATEFORM("Calc.mht", "電卓", False, FOM_NOHIDE, 380, 440)
if btn = "close" then break
wks = GETFORMDATA("equation")
if btn = "dot" then btn = "."
if (wks="") and (btn=".") then btn = "0."
if (wks="") and (val(btn)<0) then continue
ifb btn = "C" // クリア
SETFORMDATA("", "equation")
SETFORMDATA("", "answer")
continue
endif
wks = wks + btn
try
a = eval(wks) // 演算
except
a = "" // 不正演算
endtry
SETFORMDATA(wks, "equation") // 式
SETFORMDATA(a, "answer") // 答え
wend
//
// Calc.mht は以下のhtmlを 画像を埋め込む為に mhtに変換したものです
//
// <html><body style="overflow:hidden;"><form method="POST">
// <input type="text" name="equation"size="30" readonly> =
// <input type="text" name="answer" size="12" readonly><p><p>
// <input type="image" src="p7.jpg" alt="7" name="7">
// <input type="image" src="p8.jpg" alt="8" name="8">
// <input type="image" src="p9.jpg" alt="9" name="9">
// <input type="image" src="pdiv.jpg" alt="/" name="/"><p>
// <input type="image" src="p4.jpg" alt="4" name="4">
// <input type="image" src="p5.jpg" alt="5" name="5">
// <input type="image" src="p6.jpg" alt="6" name="6">
// <input type="image" src="pmuti.jpg" alt="*" name="*"><p>
// <input type="image" src="p1.jpg" alt="1" name="1">
// <input type="image" src="p2.jpg" alt="2" name="2">
// <input type="image" src="p3.jpg" alt="3" name="3">
// <input type="image" src="pmins.jpg" alt="-" name="-"><p>
// <input type="image" src="p0.jpg" alt="0" name="0">
// <input type="image" src="ppuls.jpg" alt="+" name="+">
// <input type="image" src="pdot.jpg" alt="." name="dot">
// <input type="image" src="pc.jpg" alt="CLEAR" name="C"><p>
// </form></body></html>
//////////////////////////////////////////////////
// 【引数】
// interval : 加算する時間間隔を表す文字列式(yyyy:年、m:月、d:日、ww:週、h:時、n:分、s:秒)
// num : dateに加算する値。未来は正、過去は負で指定
// date : 時間間隔を加算する日付
// 【戻り値】
// 日時(date)に、指定した単位(interval)の時間(num)を加算して返します
//////////////////////////////////////////////////
FUNCTION dateAdd(interval, num, date)
DIM year, month, day, d
GETTIME(0, date)
DIM time = G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2
SELECT interval
CASE "yyyy"
d = (G_TIME_YY + num) + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
IF time <> "00:00:00" THEN d = d + " " + time
CASE "m"
IFB num > 0 THEN
year = G_TIME_YY + INT((G_TIME_MM + num) / 12)
month = REPLACE(FORMAT(((G_TIME_MM + num) MOD 12), 2), " ", "0")
ELSE
year = G_TIME_YY + CEIL((G_TIME_MM + num) / 12 - 1)
month = REPLACE(FORMAT(G_TIME_MM - (ABS(num) MOD 12), 2), " ", "0")
ENDIF
IF month = "00" THEN month = 12
day = G_TIME_DD2
d = "" + year + month + day
IFB !isDate(d) THEN
d = year + "/" + month + "/" + "01"
d = getEndOfMonth(d)
ELSE
d = year + "/" + month + "/" + day
ENDIF
IF time <> "00:00:00" THEN d = d + " " + time
CASE "d"
t = GETTIME(num, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "ww"
t = GETTIME(num * 7, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "h"
t = GETTIME(num / 24, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "n"
t = GETTIME(num / 1440, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "s"
t = GETTIME(num / 86400, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
SELEND
RESULT = d
FEND
//////////////////////////////////////////////////
// 【引数】
// interval : 時間単位(yyyy︰年、q:四半期、m︰月、d︰日、w:週日、ww:週、h:時、n:分、s:秒)
// date1 : 日時1
// date2 : 日時2
// 【戻り値】
// date2からdate1を引いた時間間隔を求めます。
//////////////////////////////////////////////////
FUNCTION dateDiff(interval, date1, date2)
DIM y1, y2, m1, m2, d1, d2, d
SELECT interval
CASE "yyyy"
GETTIME(0, date1)
y1 = G_TIME_YY
GETTIME(0, date2)
y2 = G_TIME_YY
d = y2 - y1
CASE "q"
GETTIME(0, date1)
y1 = G_TIME_YY
m1 = G_TIME_MM
GETTIME(0, date2)
y2 = G_TIME_YY
m2 = G_TIME_MM
d = y2 * 4 + CEIL(m2/3) - (y1 * 4 + CEIL(m1/3))
CASE "m"
GETTIME(0, date1)
y1 = G_TIME_YY
m1 = G_TIME_MM
GETTIME(0, date2)
y2 = G_TIME_YY
m2 = G_TIME_MM
d = (y2 - y1) * 12 + m2 - m1
CASE "d"
d1 = GETTIME(0, date1)
d2 = GETTIME(0, date2)
d = (d2 - d1) / 86400
CASE "w"
d = INT(dateDiff("d", date1, date2) / 7)
CASE "ww"
date1 = dateAdd("d", -1 * getWeekday(date1), date1)
d = INT(dateDiff("d", date1, date2) / 7)
CASE "h"
d = dateDiff("d", date1, date2) * 24
CASE "n"
d = dateDiff("d", date1, date2) * 1440
CASE "s"
d = dateDiff("d", date1, date2) * 86400
SELEND
RESULT = d
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 最大公約数を求める数値を格納した配列
// 【戻り値】
// 最大公約数
//////////////////////////////////////////////////
FUNCTION GCD(array[])
DIM c = LENGTH(array)
DIM rem = array[c-1] MOD array[c-2]
IFB rem = 0 THEN
IFB LENGTH(array) = 2 THEN
RESULT = array[c-2]
EXIT
ENDIF
RESIZE(array, c-2)
RESULT = GCD(array)
EXIT
ENDIF
array[c-1] = array[c-2]
array[c-2] = rem
RESULT = GCD(array)
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 日付(”YYYYMMDD” or “YYYY/MM/DD” or “YYYY-MM-DD” or “YYYYMMDDHHNNSS” or “YYYY/MM/DD HH:NN:SS”)
// m : 第一引数の指定日からプラスマイナスm月とする
// 【戻り値】
// dateからm月後の月末の日付
//////////////////////////////////////////////////
FUNCTION getEndOfMonth(date, m = 0)
date = dateAdd("m", m + 1, date)
GETTIME(0, date)
GETTIME(-G_TIME_DD, date)
RESULT = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 日付文字列(”YYYYMMDD” or “YYYY/MM/DD” or “YYYY-MM-DD” or “YYYYMMDDHHNNSS” or “YYYY/MM/DD HH:NN:SS”)もしくはシリアル値
// type : 取得する曜日番号の種類を示す0〜3または11〜17の値。1と17は日曜日を1、2と11は月曜日を1とカウントします。11以降はExcel2010で追加された値で、互換性を保つために重複した値があります。
// 【戻り値】
// typeで指定した種類によって以下の値を返します。 : (0 : 0(日曜)〜6(土曜)、1 : 1(日曜)~7(土曜)、2 : 1(月曜)~7(日曜)、3 : 0(月曜)〜6(日曜)、11 : 1(月曜)~7(日曜)、12 : 1(火曜)~7(月曜)、13 : 1(水曜)~7(火曜)、14 : 1(木曜)~7(水曜)、15 : 1(金曜)~7(木曜)、16 : 1(土曜)~7(金曜)、17 : 1(日曜)~7(土曜))
//////////////////////////////////////////////////
FUNCTION getWeekday(date, type = 1)
IF VARTYPE(date) <> 258 THEN date = text(date, "yyyy/mm/dd")
GETTIME(0, date)
DIM w = G_TIME_WW
SELECT TRUE
CASE type = 0
RESULT = w
CASE type = 1
RESULT = w + 1
CASE type = 2
RESULT = IIF(w=0, 7, w)
CASE type = 3
RESULT = (w+6) MOD 7
CASE type >= 11
RESULT = ((getWeekday(date, 2) + 17 - type) MOD 7) + 1
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// serial : シリアル値もしくは時刻文字列
// 【戻り値】
// 時刻から時間を表す0〜23の範囲の値
//////////////////////////////////////////////////
FUNCTION Hour(serial)
IF VARTYPE(serial) = 258 THEN serial = timeValue(serial)
RESULT = INT(serial * 24) MOD 24
FEND
//////////////////////////////////////////////////
// 【引数】
// expr : 評価する式
// truepart : 評価した式がTrueのときに返す値
// falsepart : 評価した式がFalseのときに返す値
// 【戻り値】
// truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
IFB EVAL(expr) THEN
RESULT = truepart
ELSE
RESULT = falsepart
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 存在するかを調べる日付文字列。YYYYMMDD or YYYY/MM/DD or YYYY-MM-DDのいずれかの形式。
// 【戻り値】
// TRUE : 日付として認識できる、FALSE : 日付として認識できない
//////////////////////////////////////////////////
FUNCTION isDate(date)
TRY
GETTIME(0, date)
RESULT = TRUE
EXCEPT
RESULT = FALSE
ENDTRY
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現で検索した結果をMatchesコレクションとして返します。
//////////////////////////////////////////////////
FUNCTION reExecute(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Execute(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現にマッチするかどうかを示すブール値
//////////////////////////////////////////////////
FUNCTION reTest(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Test(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// inputs : 繰り返す文字列
// multiplier : inputsを繰り返す回数
// 【戻り値】
// inputsをmultiplier回を繰り返した文字列を返します
//////////////////////////////////////////////////
FUNCTION strRepeat(inputs, multiplier)
DIM res = ""
FOR n = 1 TO multiplier
res = res + inputs
NEXT
RESULT = res
FEND
//////////////////////////////////////////////////
// 【引数】
// serial : シリアル値
// format : フォーマット
// 【戻り値】
// 数値を表示書式に基づいて変換した文字列
//////////////////////////////////////////////////
FUNCTION text(serial, format, hour12 = FALSE)
HASHTBL startDate
startDate["明治"] = "1868/01/25"
startDate["大正"] = "1912/07/30"
startDate["昭和"] = "1926/12/25"
startDate["平成"] = "1989/01/08"
startDate["令和"] = "2019/05/01"
DIM baseDate = "1899/12/30"
serial = VAL(serial)
SELECT TRUE
CASE reTest(format, "\[h+\]")
Matches = reExecute(format, "\[(h+)\]")
DIM hour = iif(hour12, Hour(serial) MOD 12, Hour(serial))
RESULT = text(hour, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE reTest(format, "^h+$")
Matches = reExecute(format, "^(h+)$")
hour = iif(hour12, Hour(serial) MOD 12, Hour(serial))
RESULT = text(hour MOD 24, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE reTest(format, "\[m+\]")
Matches = reExecute(format, "\[(m+)\]")
RESULT = text(serial * 1440, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE format = "m"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_MM, "0")
CASE format = "mm"
GETTIME(serial, baseDate)
RESULT = G_TIME_MM2
CASE format = "n"
GETTIME(serial, baseDate)
RESULT = G_TIME_NN
CASE format = "nn"
GETTIME(serial, baseDate)
RESULT = G_TIME_NN2
CASE format = "s"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_SS, "0")
CASE format = "ss"
GETTIME(serial, baseDate)
RESULT = G_TIME_SS2
CASE format = "yyyy"
GETTIME(serial, baseDate)
RESULT = G_TIME_YY4
CASE format = "yy"
GETTIME(serial, baseDate)
RESULT = COPY(G_TIME_YY4, 3, 2)
CASE format = "e"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 2018
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1988
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1925
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1911
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1867
SELEND
CASE format = "ee"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 2018, "00")
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1988, "00")
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1925, "00")
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1911, "00")
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1867, "00")
SELEND
CASE format = "g"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "R"
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "H"
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "S"
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "T"
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "M"
SELEND
CASE format = "gg"
RESULT = COPY(text(serial, "ggg"), 1, 1)
CASE format = "ggg"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "令和"
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "平成"
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "昭和"
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "大正"
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "明治"
SELEND
CASE format = "mmmmm"
RESULT = COPY(text(serial, "mmmm"), 1, 1)
CASE format = "mmmm"
DIM month[] = "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
RESULT = month[text(serial, "m") - 1]
CASE format = "mmm"
RESULT = COPY(text(serial, "mmmm"), 1, 3)
CASE format = "dd"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_DD2, "00")
CASE format = "d"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_DD, "0")
CASE reTest(format, "^[ad]{3,4}$")
Matches = reExecute(format, "([ad]{3,4})")
GETTIME(serial, baseDate)
DIM aaa[] = "日", "月", "火", "水", "木", "金", "土"
DIM aaaa[] = "日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"
DIM ddd[] = "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
DIM dddd[] = "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday";
RESULT = EVAL(Matches.Item(0).SubMatches(0) + "[" + getWeekday(G_TIME_WW, 1) + "]")
CASE reTest(format, "(0+\.?0+)?%")
Matches = reExecute(format, "(0+\.?0+)?%")
RESULT = text(serial * 100, Matches.Item(0).SubMatches(0)) + "%"
CASE reTest(format, "^\[DBNum\d{1,4}\](.*?)$")
Matches = reExecute(format, "^\[DBNum(\d{1,4})\](.*?)$")
DIM value = VAL(Matches.Item(0).SubMatches(0))
DIM sss = text(serial, Matches.Item(0).SubMatches(1))
Matches = reExecute(sss, "(\D+)?(\d+)(\D+)?")
DIM res = ""
FOR m = 0 TO Matches.Count - 1
serial = Matches.Item(m).SubMatches(1)
SELECT value
CASE 1, 2
DIM n[][9] = "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九", + _
"", "壱", "弐", "参", "四", "伍", "六", "七", "八", "九"
DIM a[][3] = "", "十", "百", "千", + _
"", "拾", "百", "阡"
DIM b[][3] = "", "万", "億", "兆", + _
"", "萬", "億", "兆"
DIM r = ""
DIM j = 0
type = value - 1
REPEAT
DIM str = ""
DIM n4 = serial MOD 10000
FOR i = LENGTH(n4) TO 1 STEP -1
s = COPY(n4, i, 1)
IFB s = 1 AND a[type][LENGTH(n4)-i] <> "" THEN
str = IIF(s, a[type][LENGTH(n4)-i], "") + str
ELSE
str = n[type][s] + IIF(s, a[type][LENGTH(n4)-i], "") + str
ENDIF
NEXT
IF str <> "" THEN r = str + b[type][j] + r
j = j + 1
serial = INT(serial / 10000)
UNTIL serial = 0
res = res + Matches.Item(m).SubMatches(0) + r + Matches.Item(m).SubMatches(2)
CASE 3
res = res + Matches.Item(m).SubMatches(0) + STRCONV(serial, SC_FULLWIDTH) + Matches.Item(m).SubMatches(2)
CASE 4
res = res + Matches.Item(m).SubMatches(0) + STRCONV(serial, SC_HALFWIDTH) + Matches.Item(m).SubMatches(2)
SELEND
NEXT
RESULT = res
CASE reTest(format, "^(.*?)(AM\/PM|am\/pm|A\/P|a\/p)(.*?)$")
Matches = reExecute(format, "^(.*?)(AM\/PM|am\/pm|A\/P|a\/p)(.*?)$")
DIM array = SPLIT(Matches.Item(0).SubMatches(1), "/")
ampm = array[IIF(serial - INT(serial) >= 0.5, 1, 0)]
hour12 = TRUE
res = ""
WITH Matches.Item(0)
res = text(serial, .SubMatches(0), hour12) + ampm + text(serial, .SubMatches(2), hour12)
ENDWITH
RESULT = res
CASE reTest(format, "([^ymdagehns]{0,})?(([ymdagehns])\3{0,})([^ymdagehns]+)?")
Matches = reExecute(format, "([^ymdagehns]{0,})?(([ymdagehns])\3{0,})([^ymdagehns]+)?")
FOR n = 0 TO Matches.Count - 1
IF n = 0 THEN res = Matches.Item(n).SubMatches(0)
NEXT
FOR n = 0 TO Matches.Count - 1
WITH Matches.Item(n)
res = res + text(serial, .SubMatches(1), hour12) + .SubMatches(3)
ENDWITH
NEXT
RESULT = res
CASE format = "0/0"
DIM separator = POS(".", serial)
DIM g = 0
IFB separator <> 0 THEN
DIM keta = LENGTH(serial)
DIM shift = POWER(10, keta - separator)
IFB shift >= POWER(10, 15) THEN
DIM position = 0
FOR i = 0 TO 14
IFB serial * POWER(10, i) - serial >= 1 THEN
position = i
BREAK
ENDIF
NEXT
tmp = serial * POWER(10, position)
FOR i = 1 TO 15
r = (tmp * POWER(10, i)) / serial - (tmp / serial)
a1 = tmp * POWER(10, i) - tmp
IF a1 = INT(a1) THEN BREAK
NEXT
DIM frac[] = a1, r
g = GCD(frac)
RESULT = (a1/g) + "/" + (r/g)
ELSE
DIM molecule = serial * shift // 分子
DIM denominator = shift // 分母
DIM nums[] = molecule, denominator
g = GCD(nums)
molecule = molecule / g
denominator = denominator / g
RESULT = molecule + "/" + denominator
ENDIF
ELSE
RESULT = serial + "/1"
ENDIF
CASE reTest(format, "(0+)\.?(0+)?") AND UBound(SPLIT(format, ".")) <= 1
Matches = reExecute(format, "(0+)\.?(0+)?")
len1 = LENGTH(Matches.Item(0).SubMatches(0))
len2 = LENGTH(Matches.Item(0).SubMatches(1))
DIM arr[] = LENGTH(INT(serial)), len1
IFB POS(".", format) THEN
RESULT = REPLACE(FORMAT(serial, CALCARRAY(arr, CALC_MAX) + len2 + 1, len2), " ", "0")
ELSE
RESULT = REPLACE(FORMAT(serial, CALCARRAY(arr, CALC_MAX)), " ", "0")
ENDIF
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 時刻文字列。hh:nn:ss AM/PM、hh:nn AM/PM、hh AM/PM、hh:nn:ss、hh:nn、hh時nn分ss秒、hh時nn分のいずれかの形式を指定。
// 【戻り値】
// シリアル値 (例)0…00:00:00、0.5…12:00:00、0.999988425925926…23:59:59
//////////////////////////////////////////////////
FUNCTION timeValue(str)
DIM serial = 0
DIM Matches
DIM pattern = "(\d+)"
DIM hh = "(0?[0-9]|1[0-2])"
DIM ampm = "([AP]M|[ap]m)"
SELECT TRUE
CASE reTest(str, "\b" + hh + ":" + pattern + ":" + pattern + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + ":" + pattern + ":" + pattern + " " + ampm + "\b")
WITH Matches.Item(0)
serial = timeValue(.SubMatches(0) + " " + .SubMatches(3)) + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + hh + ":" + pattern + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + ":" + pattern + " " + ampm + "\b")
WITH Matches.Item(0)
serial = timeValue(.SubMatches(0) + " " + .SubMatches(2)) + VAL(.SubMatches(1)) / 1440
ENDWITH
CASE reTest(str, "\b" + hh + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + " " + ampm + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0) MOD 12) + IIF(reTest(.SubMatches(1), "AM|am"), 0, 12)
serial = serial / 24
ENDWITH
CASE reTest(str, "\b" + pattern + ":" + pattern + ":" + pattern + "\b")
Matches = reExecute(str, "\b" + pattern + ":" + pattern + ":" + pattern + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + pattern + ":" + pattern + "\b")
Matches = reExecute(str, "\b" + pattern + ":" + pattern + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440
ENDWITH
CASE reTest(str, "\b" + pattern + "時" + pattern + "分" + pattern + "秒")
Matches = reExecute(str, "\b" + pattern + "時" + pattern + "分" + pattern + "秒")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + pattern + "時" + pattern + "分")
Matches = reExecute(str, "\b" + pattern + "時" + pattern + "分")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440
ENDWITH
DEFAULT
serial = ERR_VALUE
SELEND
RESULT = serial - INT(serial)
FEND
//////////////////////////////////////////////////
// 【引数】
// arrayname : 上限値を求める配列の名前
// dimension : 返す次元を示す整数
// 【戻り値】
// 配列の上限値
//////////////////////////////////////////////////
FUNCTION UBound(arrayname[], dimension = 1)
RESULT = EVAL("RESIZE(arrayname" + strRepeat("[0]", dimension - 1) + ")")
FEND// Excelに値を書込み、その後に変更されたセルがあるかをチェック
CONST CELLSU = 30 // セルの大きさ
try
Excel = XLOPEN(True) // Excel起動
except
MSGBOX("Excelがありません")
Exit
endtry
DIM sdat[CELLSU, CELLSU] // マトリックス作成
for y = 1 to CELLSU
for x = 1 to CELLSU
sdat[x,y] = "X"+x+":Y"+y
next
next
XLSETDATA(Excel, sdat, "B2") // B2 から設定
MSGBOX("適当にセルを変更したら、OKを押して下さい")
gdat = XLGETDATA(Excel, "B2:AE31") // B2 からCELLSU(30)分読込み
fcnt = 0
for y = 1 to CELLSU
for x = 1 to CELLSU
ifb sdat[x,y] <> gdat[x,y] // セルが変更されたか
fcnt = fcnt + 1
print x+":"+y+"="+gdat[x,y]
endif
next
next
ifb fcnt = 0
print "変更されたセルはありませんでした"
else
print fcnt + "個のセルが変更されました"
endif
MSGBOX("保存せずに終了します")
XLCLOSE(Excel, True)if GETID("電卓",, 0.1) < 0 then EXEC("calc")
ACW(GETID("電卓"),107,101)
MMV(239,110,20)
MMV(240,110,81)
MMV(240,110,0)
MMV(241,110,20)
ACW(0,109,101,0,0,0)
MMV(245,110,10)
ACW(0,110,101,0,0,0)
MMV(249,110,20)
ACW(0,114,101,0,0,0)
MMV(256,110,20)
ACW(0,118,101,0,0,0)
MMV(264,110,10)
ACW(0,125,101,0,0,0)
MMV(270,110,20)
ACW(0,133,101,0,0,0)
MMV(277,111,20)
ACW(0,139,101,0,0,0)
MMV(281,113,20)
ACW(0,146,102,0,0,0)
MMV(293,113,10)
ACW(0,150,104,0,0,0)
MMV(300,115,20)
ACW(0,162,104,0,0,0)
MMV(311,116,20)
ACW(0,169,106,0,0,0)
MMV(320,119,10)
ACW(0,180,107,0,0,0)
MMV(331,123,20)
ACW(0,189,110,0,0,0)
MMV(344,127,20)
ACW(0,200,114,0,0,0)
MMV(357,132,10)
ACW(0,213,118,0,0,0)
MMV(364,138,20)
ACW(0,226,123,0,0,0)
MMV(380,139,20)
ACW(0,233,129,0,0,0)
MMV(389,147,10)
ACW(0,249,130,0,0,0)
MMV(398,152,20)
ACW(0,258,138,0,0,0)
MMV(408,156,20)
ACW(0,267,143,0,0,0)
MMV(415,162,10)
ACW(0,277,147,0,0,0)
MMV(420,168,20)
ACW(0,284,153,0,0,0)
MMV(422,175,20)
ACW(0,289,159,0,0,0)
MMV(423,183,20)
ACW(0,291,166,0,0,0)
MMV(424,192,10)
ACW(0,292,174,0,0,0)
MMV(424,201,20)
ACW(0,293,183,0,0,0)
MMV(424,210,20)
ACW(0,293,192,0,0,0)
MMV(424,220,10)
ACW(0,293,201,0,0,0)
MMV(423,230,20)
ACW(0,293,211,0,0,0)
MMV(421,241,20)
ACW(0,292,221,0,0,0)
MMV(417,252,10)
ACW(0,290,232,0,0,0)
MMV(411,261,20)
ACW(0,286,243,0,0,0)
MMV(406,270,20)
ACW(0,280,252,0,0,0)
MMV(399,279,10)
ACW(0,275,261,0,0,0)
MMV(390,287,20)
ACW(0,268,270,0,0,0)
MMV(382,295,20)
ACW(0,259,278,0,0,0)
MMV(381,301,10)
ACW(0,251,286,0,0,10)
MMV(379,308,10)
ACW(0,250,292,0,0,0)
MMV(378,316,21)
ACW(0,248,299,0,0,0)
MMV(377,322,20)
ACW(0,247,307,0,0,0)
MMV(371,328,10)
ACW(0,246,313,0,0,0)
MMV(355,336,20)
ACW(0,240,319,0,0,0)
MMV(345,342,20)
ACW(0,224,327,0,0,0)
MMV(335,349,10)
ACW(0,214,333,0,0,0)
MMV(319,354,20)
ACW(0,204,340,0,0,0)
MMV(312,354,20)
ACW(0,188,345,0,0,0)
MMV(303,355,10)
ACW(0,181,345,0,0,0)
MMV(292,355,20)
ACW(0,172,346,0,0,0)
MMV(276,356,20)
ACW(0,161,346,0,0,0)
MMV(270,355,10)
ACW(0,145,347,0,0,0)
MMV(263,355,20)
ACW(0,139,346,0,0,0)
MMV(255,354,20)
ACW(0,132,346,0,0,0)
MMV(248,351,10)
ACW(0,124,345,0,0,0)
MMV(240,349,20)
ACW(0,117,342,0,0,0)
MMV(237,346,20)
ACW(0,109,340,0,0,0)
MMV(234,345,20)
ACW(0,106,337,0,0,0)
MMV(230,344,10)
ACW(0,103,336,0,0,0)
MMV(223,342,20)
ACW(0,99,335,0,0,0)
MMV(212,338,20)
ACW(0,92,333,0,0,0)
MMV(206,333,10)
ACW(0,81,329,0,0,0)
MMV(198,328,20)
ACW(0,75,324,0,0,0)
MMV(198,328,10)
ACW(0,67,319,0,0,0)
MMV(192,322,10)
MMV(187,318,10)
ACW(0,61,313,0,0,0)
MMV(178,313,20)
ACW(0,56,309,0,0,0)
MMV(174,306,20)
ACW(0,47,304,0,0,0)
MMV(169,300,10)
ACW(0,43,297,0,0,0)
MMV(164,294,20)
ACW(0,38,291,0,0,0)
MMV(160,289,20)
ACW(0,33,285,0,0,0)
MMV(157,284,20)
ACW(0,29,280,0,0,0)
MMV(155,278,10)
ACW(0,26,275,0,0,0)
MMV(153,271,20)
ACW(0,24,269,0,0,0)
MMV(152,263,20)
ACW(0,22,262,0,0,0)
MMV(151,255,10)
ACW(0,21,254,0,0,0)
MMV(151,247,20)
ACW(0,20,246,0,0,0)
MMV(151,236,20)
ACW(0,20,238,0,0,0)
MMV(151,224,10)
ACW(0,20,227,0,0,0)
MMV(151,213,20)
ACW(0,20,215,0,0,0)
MMV(151,204,20)
ACW(0,20,204,0,0,0)
MMV(151,196,10)
ACW(0,20,195,0,0,0)
MMV(153,186,21)
ACW(0,20,187,0,0,0)
MMV(154,177,20)
ACW(0,22,177,0,0,0)
MMV(156,168,10)
ACW(0,23,168,0,0,0)
MMV(159,160,20)
ACW(0,25,159,0,0,0)
MMV(162,153,20)
ACW(0,28,151,0,0,0)
MMV(166,147,10)
ACW(0,31,144,0,0,10)
MMV(171,142,10)
ACW(0,35,138,0,0,0)
MMV(174,137,20)
ACW(0,40,133,0,0,0)
MMV(177,134,20)
ACW(0,43,128,0,0,0)
MMV(180,131,10)
ACW(0,46,125,0,0,0)
MMV(183,128,20)
ACW(0,49,122,0,0,0)
MMV(189,124,20)
ACW(0,52,119,0,0,0)
MMV(194,121,10)
ACW(0,58,115,0,0,0)
MMV(199,118,20)
ACW(0,63,112,0,0,0)
MMV(204,116,20)
ACW(0,68,109,0,0,0)
MMV(208,114,10)
ACW(0,73,107,0,0,0)
MMV(211,113,20)
ACW(0,77,105,0,0,0)
MMV(213,113,20)
ACW(0,80,104,0,0,0)
MMV(215,112,10)
ACW(0,82,104,0,0,0)
MMV(217,111,20)
ACW(0,84,103,0,0,0)
MMV(222,110,20)
ACW(0,86,102,0,0,0)
MMV(232,109,10)
ACW(0,91,101,0,0,0)
MMV(240,109,20)
ACW(0,101,100,0,0,0)
MMV(248,111,20)
ACW(0,109,100,0,0,0)
MMV(255,113,20)
ACW(0,117,102,0,0,0)
MMV(260,115,10)
ACW(0,124,104,0,0,0)
MMV(264,116,20)
ACW(0,129,106,0,0,0)
MMV(269,117,20)
ACW(0,133,107,0,0,0)
MMV(276,117,10)
ACW(0,138,108,0,0,0)
MMV(279,118,20)
ACW(0,145,108,0,0,0)
MMV(280,118,20)
ACW(0,148,109,0,0,0)
ACW(0,149,109,0,0,0)
MMV(280,118,0)
MMV(280,119,30)// IEの中のFlashPlayerの操作 (YouTube:20秒間だけ再生)
// IE10では Flashは内臓の為にハンドルを取得できない
// YouTube - Sweet Tired Cat
IE = CreateOLEObj("InternetExplorer.Application")
IE.Visible = True
IE.Navigate("http://www.youtube.com/watch?v=hPzNl6NKAG0")
BusyWait(IE)
// FlashPlayerActiveX のID取得
id = GETID("YouTube", "IEFrame")
hnd = GETCTLHND(id, "MacromediaFlashPlayerActiveX", 2)
if hnd = 0 then hnd = GETCTLHND(id, "MacromediaFlashPlayerActiveX", 1)
if hnd = 0
MsgBox("FlashPlayerActiveX のハンドルを取得できませんでした")
Exit
endif
flashid = HNDtoID(hnd)
x = status(flashid, ST_X)
y = status(flashid, ST_Y)
h = status(flashid, ST_HEIGHT)
MMV(x+8, y+h-8)
sleep(1)
print "Flashの位置: "+ x +","+ y
print "ビデオ時間: "+ GETSTR(flashid, 1, STR_ACC_STATIC)
Repeat
Sleep(0.5)
MMV(x+8, y+h-8-RANDOM(8)) // コントロール部が閉じないように揺らす
Until Copy(GETSTR(flashid, 1, STR_ACC_STATIC),1,3) = "0:2" // 20sec
print "PAUSE"
ClkItem(flashid, "Pause", CLK_ACC or CLK_MUSMOVE, True)
//------
Procedure BusyWait(ie)
Sleep(0.5) // Wait
Const TIME_OUT = 90
tm = Gettime()
repeat
Sleep(0.2)
ifb Gettime() - tm > TIME_OUT
MsgBox("Time Out:BusyWait")
ExitExit
endif
until (! ie.busy) and (ie.readyState=4)
Sleep(0.5)
Fend
//////////////////////////////////////////////////
// 【引数】
// array : 要素を追加する配列(参照引数)
// values : 追加する要素をvalue1から指定
// 【戻り値】
// 処理後の配列の要素の数
//////////////////////////////////////////////////
FUNCTION arrayPush(var array[], value1 = EMPTY, value2 = EMPTY, value3 = EMPTY, value4 = EMPTY, value5 = EMPTY, value6 = EMPTY, value7 = EMPTY, value8 = EMPTY, value9 = EMPTY, value10 = EMPTY, value11 = EMPTY, value12 = EMPTY, value13 = EMPTY, value14 = EMPTY, value15 = EMPTY, value16 = EMPTY)
DIM i = 1
WHILE EVAL("value" + i) <> EMPTY
DIM res = RESIZE(array, UBound(array) + 1)
array[res] = EVAL("value" + i)
i = i + 1
WEND
RESULT = LENGTH(array)
FEND
//////////////////////////////////////////////////
// 【引数】
// needle : 検索する値
// haystack : 配列
// 【戻り値】
// needleが見つかった場合に配列のキー
//////////////////////////////////////////////////
FUNCTION arraySearch(needle, haystack[])
DIM i = 0
FOR item IN haystack
IFB item = needle THEN
RESULT = i
EXIT
ENDIF
i = i + 1
NEXT
FEND
//////////////////////////////////////////////////
// 【引数】
// IE : IEオブジェクト
// 【戻り値】
//
//////////////////////////////////////////////////
PROCEDURE BusyWait(Var IE)
SLEEP(0.500)
DIM t = GETTIME()
TRY
REPEAT
DIM tm = GETTIME() - t
FUKIDASI("BusyWait:" + tm)
SLEEP(0.010)
IF tm >= 60 THEN BREAK
UNTIL !IE.Busy AND IE.readyState = 4
EXCEPT
IE = getIEObj(-1)
PRINT IE.document.URL + " のIEオブジェクトを取得しました。"
BusyWait(IE)
ENDTRY
FUKIDASI()
FEND
//////////////////////////////////////////////////
// 【引数】
// 文字列 or 数値 : 取得したい<a href="https://uwsc.jp/com/ie/" >InternetExplorer オブジェクト</a>のタイトル・URLもしくは数値を指定
// 完全一致フラグ : (TRUE : 文字列が完全一致したものを取得、FALSE : 文字列の一部を含むものを取得)
// 【戻り値】
// 条件に一致する<a href="https://uwsc.jp/com/ie" >InternetExplorer</a>
//////////////////////////////////////////////////
FUNCTION getIEObj(str, flg = FALSE)
DIM Shell = CREATEOLEOBJ("Shell.Application")
DIM ShellWindows = Shell.Windows
DIM IE[-1]
FOR i = 0 TO ShellWindows.Count - 1
TRY
IFB ShellWindows.Item(i).Name = "Internet Explorer" THEN
arrayPush(IE, ShellWindows.Item(i))
ENDIF
EXCEPT
ENDTRY
NEXT
SELECT CHKNUM(str)
CASE TRUE
IFB str = 0 THEN
RESULT = LENGTH(IE)
ELSE
IF str < 0 THEN str = str + LENGTH(IE) + 1
TRY
RESULT = IE[str-1]
EXCEPT
RESULT = ERR_VALUE
ENDTRY
ENDIF
CASE FALSE
DIM pattern = IIF(flg, "^" + str + "$", str)
DIM titleList = SLICE(IE)
FOR i = 0 TO UBound(titleList)
titleList[i] = titleList[i].Document.title
NEXT
DIM urlList = SLICE(IE)
FOR i = 0 TO UBound(urlList)
urlList[i] = urlList[i].Document.URL
NEXT
DIM num = ERR_VALUE
SELECT TRUE
CASE pregGrep(pattern, titleList) <> FALSE; num = arraySearch(pregGrep(pattern, titleList)[0], titleList)
CASE pregGrep(pattern, urlList) <> FALSE; num = arraySearch(pregGrep(pattern, urlList)[0], urlList)
SELEND
TRY
RESULT = IE[num]
EXCEPT
RESULT = ERR_VALUE
ENDTRY
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// expr : 評価する式
// truepart : 評価した式がTrueのときに返す値
// falsepart : 評価した式がFalseのときに返す値
// 【戻り値】
// truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
IFB EVAL(expr) THEN
RESULT = truepart
ELSE
RESULT = falsepart
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// pattern : 検索するパターンを表す文字列
// array : 検索される配列
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION pregGrep(pattern, array[], flags = 0)
DIM res[-1]
FOR item IN array
IF reTest(item, pattern) THEN arrayPush(res, item)
NEXT
RESULT = SLICE(res)
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現にマッチするかどうかを示すブール値
//////////////////////////////////////////////////
FUNCTION reTest(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Test(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// inputs : 繰り返す文字列
// multiplier : inputsを繰り返す回数
// 【戻り値】
// inputsをmultiplier回を繰り返した文字列を返します
//////////////////////////////////////////////////
FUNCTION strRepeat(inputs, multiplier)
DIM res = ""
FOR n = 1 TO multiplier
res = res + inputs
NEXT
RESULT = res
FEND
//////////////////////////////////////////////////
// 【引数】
// arrayname : 上限値を求める配列の名前
// dimension : 返す次元を示す整数
// 【戻り値】
// 配列の上限値
//////////////////////////////////////////////////
FUNCTION UBound(arrayname[], dimension = 1)
RESULT = EVAL("RESIZE(arrayname" + strRepeat("[0]", dimension - 1) + ")")
FEND// Yahoo! ファイナンスを開き 指定株価時系列データを取得してExcelに送る
IE = CREATEOLEOBJ("InternetExplorer.Application") // IE
IE.Visible = True
kcode = "4689.t" // 銘柄コード
yys=2012; mms=1; dds=1 // 開始年月日
yye=2012; mme=3; dde=1 // 終了年月日
url = "http://info.finance.yahoo.co.jp/history/?code="+kcode+"&sy="+yys+"&sm="+mms+"&sd="+dds+"&ey="+yye+"&em="+mme+"&ed="+dde+"&tm=d="
IE.Navigate(url)
BusyWait(IE)
Excel = XLOPEN(True) // Excel起動
Excel.Range("A1").ColumnWidth = 16 // A列の幅
dim head[] = "日付","始値","高値","安値","終値","出来高","調整後終値"
XLSETDATA(Excel, head, "A1")
// データ取得
body = IEGetSrc(IE, "BODY")
body = Copy(body, Pos("調整後終値*",body)) // 取得開始位置
body = Copy(body, 1, Pos("</TBODY>",body)) // 取得終了位置
num = Length(SPLIT(body, "</tr>"))-2 // 行数
dim sdat[num][7]
cnt = 1
for y = num to 1 step -1
for x = 1 to 7 // 列
sdat[y][x] = BetweenStr(body, "<td>", "</td>", cnt)
cnt = cnt + 1
next
next
XLSETDATA(Excel, sdat, "A2") // 一括で設定
Excel.ActiveSheet.Name = IEGetData(IE,"TAG=H1") // シート名に企業名
// グラフ作成
CONST xlColumns = 2
CONST xlLine = 4
RunGraph = Excel.ActiveSheet.ChartObjects.Add(440,10,400,400).Chart
RunGraph.ChartType = xlLine
rng = Excel.Range("A1","E"+num)
RunGraph.SetSourceData(Source:=rng, PlotBy:=xlColumns)
//------
Procedure BusyWait(ie)
Sleep(0.5) // Wait
Const TIME_OUT = 90
tm = Gettime()
repeat
Sleep(0.2)
ifb Gettime() - tm > TIME_OUT
MsgBox("Time Out:BusyWait")
ExitExit
endif
until (! ie.busy) and (ie.readyState=4)
Sleep(0.5)
Fend
//////////////////////////////////////////////////
// 【引数】
// array : 要素を追加する配列(参照引数)
// values : 追加する要素をvalue1から指定
// 【戻り値】
// 処理後の配列の要素の数
//////////////////////////////////////////////////
FUNCTION arrayPush(var array[], value1 = EMPTY, value2 = EMPTY, value3 = EMPTY, value4 = EMPTY, value5 = EMPTY, value6 = EMPTY, value7 = EMPTY, value8 = EMPTY, value9 = EMPTY, value10 = EMPTY, value11 = EMPTY, value12 = EMPTY, value13 = EMPTY, value14 = EMPTY, value15 = EMPTY, value16 = EMPTY)
DIM i = 1
WHILE EVAL("value" + i) <> EMPTY
DIM res = RESIZE(array, UBound(array) + 1)
array[res] = EVAL("value" + i)
i = i + 1
WEND
RESULT = LENGTH(array)
FEND
//////////////////////////////////////////////////
// 【引数】
// needle : 検索する値
// haystack : 配列
// 【戻り値】
// needleが見つかった場合に配列のキー
//////////////////////////////////////////////////
FUNCTION arraySearch(needle, haystack[])
DIM i = 0
FOR item IN haystack
IFB item = needle THEN
RESULT = i
EXIT
ENDIF
i = i + 1
NEXT
FEND
//////////////////////////////////////////////////
// 【引数】
// IE : IEオブジェクト
// 【戻り値】
//
//////////////////////////////////////////////////
PROCEDURE BusyWait(Var IE)
SLEEP(0.500)
DIM t = GETTIME()
TRY
REPEAT
DIM tm = GETTIME() - t
FUKIDASI("BusyWait:" + tm)
SLEEP(0.010)
IF tm >= 60 THEN BREAK
UNTIL !IE.Busy AND IE.readyState = 4
EXCEPT
IE = getIEObj(-1)
PRINT IE.document.URL + " のIEオブジェクトを取得しました。"
BusyWait(IE)
ENDTRY
FUKIDASI()
FEND
//////////////////////////////////////////////////
// 【引数】
// 文字列 or 数値 : 取得したい<a href="https://uwsc.jp/com/ie/" >InternetExplorer オブジェクト</a>のタイトル・URLもしくは数値を指定
// 完全一致フラグ : (TRUE : 文字列が完全一致したものを取得、FALSE : 文字列の一部を含むものを取得)
// 【戻り値】
// 条件に一致する<a href="https://uwsc.jp/com/ie" >InternetExplorer</a>
//////////////////////////////////////////////////
FUNCTION getIEObj(str, flg = FALSE)
DIM Shell = CREATEOLEOBJ("Shell.Application")
DIM ShellWindows = Shell.Windows
DIM IE[-1]
FOR i = 0 TO ShellWindows.Count - 1
TRY
IFB ShellWindows.Item(i).Name = "Internet Explorer" THEN
arrayPush(IE, ShellWindows.Item(i))
ENDIF
EXCEPT
ENDTRY
NEXT
SELECT CHKNUM(str)
CASE TRUE
IFB str = 0 THEN
RESULT = LENGTH(IE)
ELSE
IF str < 0 THEN str = str + LENGTH(IE) + 1
TRY
RESULT = IE[str-1]
EXCEPT
RESULT = ERR_VALUE
ENDTRY
ENDIF
CASE FALSE
DIM pattern = IIF(flg, "^" + str + "$", str)
DIM titleList = SLICE(IE)
FOR i = 0 TO UBound(titleList)
titleList[i] = titleList[i].Document.title
NEXT
DIM urlList = SLICE(IE)
FOR i = 0 TO UBound(urlList)
urlList[i] = urlList[i].Document.URL
NEXT
DIM num = ERR_VALUE
SELECT TRUE
CASE pregGrep(pattern, titleList) <> FALSE; num = arraySearch(pregGrep(pattern, titleList)[0], titleList)
CASE pregGrep(pattern, urlList) <> FALSE; num = arraySearch(pregGrep(pattern, urlList)[0], urlList)
SELEND
TRY
RESULT = IE[num]
EXCEPT
RESULT = ERR_VALUE
ENDTRY
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// expr : 評価する式
// truepart : 評価した式がTrueのときに返す値
// falsepart : 評価した式がFalseのときに返す値
// 【戻り値】
// truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
IFB EVAL(expr) THEN
RESULT = truepart
ELSE
RESULT = falsepart
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// pattern : 検索するパターンを表す文字列
// array : 検索される配列
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION pregGrep(pattern, array[], flags = 0)
DIM res[-1]
FOR item IN array
IF reTest(item, pattern) THEN arrayPush(res, item)
NEXT
RESULT = SLICE(res)
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現にマッチするかどうかを示すブール値
//////////////////////////////////////////////////
FUNCTION reTest(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Test(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// inputs : 繰り返す文字列
// multiplier : inputsを繰り返す回数
// 【戻り値】
// inputsをmultiplier回を繰り返した文字列を返します
//////////////////////////////////////////////////
FUNCTION strRepeat(inputs, multiplier)
DIM res = ""
FOR n = 1 TO multiplier
res = res + inputs
NEXT
RESULT = res
FEND
//////////////////////////////////////////////////
// 【引数】
// arrayname : 上限値を求める配列の名前
// dimension : 返す次元を示す整数
// 【戻り値】
// 配列の上限値
//////////////////////////////////////////////////
FUNCTION UBound(arrayname[], dimension = 1)
RESULT = EVAL("RESIZE(arrayname" + strRepeat("[0]", dimension - 1) + ")")
FEND// サンプル
if KINDOFOS() < 21 // Windows7 未満
msgbox("ごめんなさい。<#CR>このサンプルは Windows7 以上の必要があります。")
Exit
endif
Speak("Run the sample script", True)
// メッセージ表示位置
PUBLIC msgx, msgy
msgx = MONITOR(0, MON_WIDTH) / 2 // メインモニタの真ん中
msgy = MONITOR(0, MON_HEIGHT) / 2
// マウス、キーボード入力をブロックする
StopForm(False) // Stopウィンドウは出さない
LockHardEX(0, LOCK_MOUSE) // マウス禁止
// Paint 全画面表示
paintid = paintimg()
// メモ帳 起動
メモID = EXEC(GET_SYS_DIR+"\notepad.exe", False, 200, 10, 400, 400)
if Pos("メモ帳", Status(メモID, ST_TITLE)) = 0
msgbox("Japanese-Windows only")
Exit
endif
// メモ帳 フォントの変更
ClkItem(メモID, "フォント", CLK_MENU or CLK_SHORT)
fontid = GETID("フォント", "#32770", 3)
if fontid<0 then fontid = GETID("Font", "#32770")
sv_fontStyl = GETSTR(fontid, 2) // 現在のスタイル
sv_fontSize = GETSTR(fontid, 3) // 現在のサイズ
ClkItem(fontid, "太字", CLK_LIST) // スタイル変更
SendStr(fontid, "16", 3, True) // サイズ変更 (ClkItemでも可)
Sleep(1)
ClkItem(fontid, "OK")
// 計算式をメモ帳に書き込み
計算式 = "12345+98765="
SendStr(メモID, 計算式)
Sleep(1)
// 電卓で計算
電卓ID = EXEC(GET_SYS_DIR+"\calc.exe")
if KINDOFOS() < 30 // Windows7, 8
ClkItem(電卓ID, "普通の電卓")
SendStr(電卓ID, 計算式)
Sleep(1)
ret = GetStr(電卓ID, 4, STR_STATIC)
else // Windows10 ストアアプリ
電卓ID = GETID("電卓", "ApplicationFrameWindow")
for modebtn in GetItem(電卓ID, ITM_BTN) // 現在のモードを調べる
if Pos("メニュー、", modebtn)>0
if Pos("標準", modebtn)=0 // 標準 電卓に切り替え
ClkItem(電卓ID, modebtn, CLK_BTN)
sleep(1)
ClkItem(電卓ID, "標準 電卓", CLK_LIST or CLK_LEFTCLK)
endif
break
endif
next
for n in 計算式 // 1文字づつクリック
if n = "+" then n = "プラス"
if n = "=" then n = "等号"
ClkItem(電卓ID, n)
next
Sleep(1)
ret = GetStr(電卓ID, 2, STR_STATIC)
Token(" ", ret)
endif
SendStr(メモID, ret+"<#CR>") // メモ帳に答えを追加
// 電卓回す
SendStr(メモID, "電卓をグルグル回してみる<#CR>")
if MsgBox("回してみます?", BTN_YES or BTN_NO) = BTN_YES
moji = "音楽を入れますか?<#CR>Yesなら5秒以内に Shift キーを押してね"
if 音楽を入れるかキーチェック(VK_SHIFT, moji)
musicnm = "flourish.mid"
Balloon("読み込み中...", msgx, msgy)
Sound(musicnm) // バックミュージック
Balloon()
endif
for 回数 = 1 to 3
if 回数=2 then Balloon("いつもより余計に回しています<#cr>パチパチパチ"_
, msgx, msgy-20, 3, 14) // _により前行と繋がっている
call .\grugru.uws // grugru.uws を実行
next
else
Balloon("それは残念", msgx, msgy, 0, 14)
Sleep(3)
endif
// 終了処理
Balloon("フォントの変更を戻す")
ClkItem(メモID, "フォント", CLK_MENU or CLK_SHORT) // フォントの変更を戻す
fontid = GETID("フォント", "#32770", 3)
if fontid<0 then fontid = GETID("Font", "#32770")
SendStr(fontid, sv_fontStyl, 2, True) // スタイル戻す
SendStr(fontid, sv_fontSize, 3, True) // サイズ戻す
Sleep(1)
ClkItem(fontid, "OK")
CtrlWin(paintid, CLOSE2) // Paint終了
Sound() // SOUND OFF
Balloon() // 吹出しOFF
CtrlWin(電卓ID, CLOSE) // 電卓終了
SendStr(メモID, "終了~")
Sleep(1)
CtrlWin(メモID, CLOSE) // メモ終了
Sleep(1)
ClkItem(GETID("メモ帳", "#32770"), "保存しない")
LockHardEX() // 入力ブロックの解除
// メイン処理はここまでになる(関数の前まで)
// 以下 関数(サブルーチン)
// 指定キーが押されたらTrueを返す
Function 音楽を入れるかキーチェック(chk_key, moji)
Result = False // 戻り値
sv_tm = GetTime()
while GetTime()-sv_tm < 5 // 5秒まで待つ
wk_sec = 5 - (GetTime()-sv_tm)
Balloon(moji+" "+wk_sec, msgx, msgy, 0, 14)
if GETKEYSTATE(chk_key) // 指定キーチェック
Result = True // 戻り値=True
break
endif
sleep(0.2)
wend
Balloon() // 吹出しOFF
fend
// usertile12.bmp/user-200.png/user-192.pngを Paintで表示
Function paintimg()
Result = 0
Const dpath = "C:\ProgramData\Microsoft\User Account Pictures\"
img = dpath + "Default Pictures\usertile12.bmp" // Win7
if ! FOPEN(img, F_EXISTS)
img = dpath + "user-200.png" // Win8
if ! FOPEN(img, F_EXISTS)
img = dpath + "user-192.png" // Win10
if ! FOPEN(img, F_EXISTS) then exit // 無し
endif
endif
id = exec("mspaint.exe <#DBL>"+ img +"<#DBL>")
sleep(1)
ClkItem(id, "表示", CLK_ACC)
ClkItem(id, "全画面", CLK_ACC or CLK_BACK)
sleep(1)
Result = id // IDを返す
Fend// APIによりシステム情報(コンピュータ名、ユーザ名)の取得
// WMIによるBIOS、マザーボード情報の取得
DEF_DLL GetComputerNameA(var string, var Long): Long: kernel32
DEF_DLL GetUserNameA(var string, var Long): Long: advapi32
ComName = Format(NULL, 100) // 領域確保
UserName = Format(NULL, 100)
GetComputerNameA(ComName, Length(ComName))
GetUserNameA(UserName, Length(UserName))
print "コンピュータ名:" + ComName
print "ユーザ名:" + UserName
print
// BIOS情報の表示
Locator = CreateOleObj("WbemScripting.SWbemLocator")
consvr = Locator.ConnectServer()
biosset = consvr.ExecQuery("Select * From Win32_BIOS")
GETOLEITEM(biosset); wk = ALL_OLE_ITEM[0]
print "BIOS情報:"
print wk.Manufacturer
print wk.Name
print wk.SerialNumber
print wk.SMBIOSBIOSVersion
print
// マザーボード情報の表示
baseset = consvr.ExecQuery("Select * From Win32_BaseBoard")
GETOLEITEM(baseset); wk = ALL_OLE_ITEM[0]
print "マザーボード情報:"
print wk.Manufacturer
print wk.Product
print wk.SerialNumber
print wk.Version// マウスカーソル下のウィンドウのタイトルとクラス名を表示
While True
id = GETID(GET_FROMPOINT_WIN) // マウスカーソル下のウィンドウ
moji = STATUS(id, ST_TITLE) + " , " + STATUS(id, ST_CLASS)
Fukidasi(moji, G_MOUSE_X+8, G_MOUSE_Y, 3)
Sleep(0.2)
Wend// タスクトレイの音量を右クリックしボリュームコントロールを開く
// Win9x系はNG
flg = CLKITEM(GETID("","Shell_TrayWnd"), "音量", CLK_TOOLBAR or CLK_RIGHTCLK)
if !flg then flg = CLKITEM(GETID("","Shell_TrayWnd"), "Volume", CLK_TOOLBAR or CLK_RIGHTCLK) // 環境により "音量" or "Volume"
ifb flg
popupid = GETID("", "#32768", -1) // コンテキストメニュー
CLKITEM(popupid, "開く", CLK_ACC or CLK_SHORT or CLK_BACK or CLK_MUSMOVE)
endif// C:ドライブのディレクトリ木表示(3階層まで)
ディレクトリ("C:", 0)
procedure ディレクトリ(dd, lve)
lve = lve + 1
if lve > 3 then Exit
sps = ""
for i = 2 to lve; sps = sps + " "; next
for i=0 to GETDIR(dd,"\")-1
print sps + GETDIR_FILES[i]
ディレクトリ(dd+"\"+GETDIR_FILES[i], lve)
next
fend// バックグランドのメモ帳にKBD関数にてランダム文字を書く
id = EXEC("notepad.exe")
edithnd = GETCTLHND(id, "edit") // 送るべきウィンドウ(注:親ではない)
MOUSEORG(HndToID(edithnd), 2) // バックグラウンド指定
calc = EXEC("calc.exe") // 電卓前面(メモ帳をバックグラウンドに)
ACW(calc, STATUS(id,ST_X), STATUS(id,ST_Y)+80)
for i = 0 to 60
KBD(VK_A+RANDOM(26)) // 文字ランダム
Sleep(0.1)
next// デスクトップの情報を取得しポップアップメニュにする
id = GETID("Program Manager","Progman")
GETITEM(id, ITM_LSTVEW)
x = POPUPMENU(ALL_ITEM_LIST)
CLKITEM(id, ALL_ITEM_LIST[x], CLK_LSTVEW or CLK_LEFTCLK)
CLKITEM(id, ALL_ITEM_LIST[x], CLK_LSTVEW or CLK_DBLCLK)// CDOを利用したメール送信
Const SMTP_SERVER = "mail.xxx.yyy.zzz" // メールサーバー
Const SMTP_PORT = 587 // ポートNo.
Const SMTP_AUTHEN = 1 // SMTP認証: 0:なし、1:basic、2:NTLM
Const SMTP_SSL = True // SSL利用
Const SMTP_ID = "xxxxx" // ID
Const SMTP_PASWD = "yyyyy" // Password
Const MAILFROM = "from@xxx.yyy.zzz" // 送信者メールアドレス
MailTo = "to@xxx.yyy.zzz" // あて先メールアドレス
mailSubj = "題名" // 題名
MailBody = "内容" // 内容
Const cdoPath = "http://schemas.microsoft.com/cdo/configuration/"
Const cdoSendUsingPort = 2
objCDO = CreateOLEObj("CDO.Message")
With objCDO
With .Configuration.Fields // 設定項目
.Item(cdoPath+"sendusing") = cdoSendUsingPort // 外部SMTP指定
.Item(cdoPath+"smtpserver") = SMTP_SERVER // SMTPサーバ名
.Item(cdoPath+"smtpauthenticate") = SMTP_AUTHEN // SMTP認証
.Item(cdoPath+"smtpserverport") = SMTP_PORT // ポートNo
.Item(cdoPath+"smtpusessl") = SMTP_SSL // SSL
.Item(cdoPath+"sendusername") = SMTP_ID // ID
.Item(cdoPath+"sendpassword") = SMTP_PASWD // Password
.Item(cdoPath+"smtpconnectiontimeout") = 60 // タイムアウト
.Update // 設定を更新
EndWith
.MimeFormatted = True
.Fields.Update
.From = MAILFROM
.To = MailTo
.Subject = mailSubj
.TextBody = MailBody
.Send
EndWith// 音声認識によるアプリの操作
// アクティブウィンドウのクリック可能なものを拾得、それを単語登録し使用
// 認識可能な単語は吹き出しにて表示
// コマンド発声前にShiftキーを叩いておくとチェックボックス等でOFF動作
id = -1
dim 単語登録[100]
While True
ifb id <> GETID(GET_ACTIVE_WIN) // アクティブウィンドウが変更されたか
id = GETID(GET_ACTIVE_WIN)
num = GETITEM(id, ITM_BTN+ITM_LIST+ITM_TAB+ITM_MENU+ITM_LSTVEW+ITM_TREEVEW+ITM_TOOLBAR,-1,0,True) // クリック可能なものを全て拾う
if num > resize(単語登録) then num = resize(単語登録) // 数制限
ifb num = 0
Sleep(0.2); Continue
endif
表示 = ""
SETCLEAR(単語登録, "")
for i = 0 to num-1
単語登録[i] = 記号削除(ALL_ITEM_LIST[i]) // 邪魔な文字は削除
if 単語登録[i]<>"" then 表示 = 表示 + 単語登録[i] + "<#CR>"
next
RECOSTATE(True, 単語登録) // 単語登録、実行
Fukidasi(表示, 0, 0, , , , , ,100)
endif
拾得音声 = DICTATE(False) // 拾得
ifb 拾得音声 <> "" // 音声入力あった
Fukidasi()
print 拾得音声
for i = 0 to num-1
ifb 拾得音声 = 単語登録[i]
chk_flg = ! GETKEYSTATE(VK_SHIFT) // Shiftキーが押されてた時は Off動作
CLKITEM(id, ALL_ITEM_LIST[i], 0, chk_flg) // コマンド実行
break
endif
next
id = -1
else
if GETKEYSTATE(VK_LBUTTON) then id = -1 // ボタン操作があった時も更新
endif
Sleep(0.2)
Wend
// 制御コードなどの記号があるとエラーになるのでゴミ文字削除
Function 記号削除(ss)
p = Pos("\", ss)
if p > 0 then ss = Copy(ss, p+1, 999)
ifb Pos("\", ss) > 0
Result=""; Exit // 階層化されている物まで拾うと数が多すぎになるので捨てる
endif
p = Pos("(", ss, -1)
if p > 0 then ss = Copy(ss, 1, p-1) // ( 以降は消す
for i = 1 to Length(ss)
mcd = ASC(Copy(ss,i,1)) // 英数字のチェック
ifb mcd < $80
if (mcd<$30) or (mcd>$7A) or ((mcd>=$3A)and(mcd<=$40)) or ((mcd>=$5B)and(mcd<=$60)) then ss=Copy(ss,1,i-1)+" "+Copy(ss,i+1,999)
endif
next
Result = Replace(ss, " ", "")
Fend// Shiftキーが押された時にマウス位置200ドットの画像を保存
CONST BMPNAME = "画像保存.BMP"
wshell = CreateOLEObj("WScript.Shell")
While True
ifb GETKEYSTATE(VK_SHIFT)
SAVEIMG(BMPNAME, 0, ZCUT(G_MOUSE_X-100), ZCUT(G_MOUSE_Y-100), 200, 200)
wshell.Run(BMPNAME) // BMPに割り当てられたアプリ起動
Break
endif
Sleep(0.2)
Wend// スクリプト内のTextBlockに書かれたHTMLをフォーム表示する
obj = CREATEFORM("about:blank", "Calc", True, FOM_NOHIDE, 460, 200)
obj.Document.write(計算フォーム) // HTMLを書き込む
while obj.Visible // 画面が出ている間
ifb GETFORMDATA("CalBtn") // 計算ボタンが押された
va = VAL(GETFORMDATA("Text1"))
vb = VAL(GETFORMDATA("Text2"))
ifb (val(va)=ERR_VALUE) or (val(vb)=ERR_VALUE)
MsgBox("数値を入れてください"); Continue
endif
select GETFORMDATA("Select1")
case "足し算"; ret = va + vb
case "引き算"; ret = va - vb
case "掛け算"; ret = va * vb
selend
obj.Document.body.all.tags("font").item[0].innerText = ret
endif
Sleep(0.1)
wend
// 計算フォーム.html
TextBlock 計算フォーム
<html><body style="overflow:hidden;"><form method="POST">
<input type='text' name='Text1' size='8'>
<select name='Select1'><option>足し算</option><option>引き算</option><option>掛け算</option></select>
<input type='text' name='Text2' size='8'>
<input type='submit' value=' 計算 ' name='CalBtn'><BR><BR>
<font color='#FF0000'>答え</font>
</form></body></html>
EndTextBlock
//////////////////////////////////////////////////
// 【引数】
// interval : 加算する時間間隔を表す文字列式(yyyy:年、m:月、d:日、ww:週、h:時、n:分、s:秒)
// num : dateに加算する値。未来は正、過去は負で指定
// date : 時間間隔を加算する日付
// 【戻り値】
// 日時(date)に、指定した単位(interval)の時間(num)を加算して返します
//////////////////////////////////////////////////
FUNCTION dateAdd(interval, num, date)
DIM year, month, day, d
GETTIME(0, date)
DIM time = G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2
SELECT interval
CASE "yyyy"
d = (G_TIME_YY + num) + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
IF time <> "00:00:00" THEN d = d + " " + time
CASE "m"
IFB num > 0 THEN
year = G_TIME_YY + INT((G_TIME_MM + num) / 12)
month = REPLACE(FORMAT(((G_TIME_MM + num) MOD 12), 2), " ", "0")
ELSE
year = G_TIME_YY + CEIL((G_TIME_MM + num) / 12 - 1)
month = REPLACE(FORMAT(G_TIME_MM - (ABS(num) MOD 12), 2), " ", "0")
ENDIF
IF month = "00" THEN month = 12
day = G_TIME_DD2
d = "" + year + month + day
IFB !isDate(d) THEN
d = year + "/" + month + "/" + "01"
d = getEndOfMonth(d)
ELSE
d = year + "/" + month + "/" + day
ENDIF
IF time <> "00:00:00" THEN d = d + " " + time
CASE "d"
t = GETTIME(num, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "ww"
t = GETTIME(num * 7, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "h"
t = GETTIME(num / 24, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "n"
t = GETTIME(num / 1440, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "s"
t = GETTIME(num / 86400, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
SELEND
RESULT = d
FEND
//////////////////////////////////////////////////
// 【引数】
// interval : 時間単位(yyyy︰年、q:四半期、m︰月、d︰日、w:週日、ww:週、h:時、n:分、s:秒)
// date1 : 日時1
// date2 : 日時2
// 【戻り値】
// date2からdate1を引いた時間間隔を求めます。
//////////////////////////////////////////////////
FUNCTION dateDiff(interval, date1, date2)
DIM y1, y2, m1, m2, d1, d2, d
SELECT interval
CASE "yyyy"
GETTIME(0, date1)
y1 = G_TIME_YY
GETTIME(0, date2)
y2 = G_TIME_YY
d = y2 - y1
CASE "q"
GETTIME(0, date1)
y1 = G_TIME_YY
m1 = G_TIME_MM
GETTIME(0, date2)
y2 = G_TIME_YY
m2 = G_TIME_MM
d = y2 * 4 + CEIL(m2/3) - (y1 * 4 + CEIL(m1/3))
CASE "m"
GETTIME(0, date1)
y1 = G_TIME_YY
m1 = G_TIME_MM
GETTIME(0, date2)
y2 = G_TIME_YY
m2 = G_TIME_MM
d = (y2 - y1) * 12 + m2 - m1
CASE "d"
d1 = GETTIME(0, date1)
d2 = GETTIME(0, date2)
d = (d2 - d1) / 86400
CASE "w"
d = INT(dateDiff("d", date1, date2) / 7)
CASE "ww"
date1 = dateAdd("d", -1 * getWeekday(date1), date1)
d = INT(dateDiff("d", date1, date2) / 7)
CASE "h"
d = dateDiff("d", date1, date2) * 24
CASE "n"
d = dateDiff("d", date1, date2) * 1440
CASE "s"
d = dateDiff("d", date1, date2) * 86400
SELEND
RESULT = d
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 最大公約数を求める数値を格納した配列
// 【戻り値】
// 最大公約数
//////////////////////////////////////////////////
FUNCTION GCD(array[])
DIM c = LENGTH(array)
DIM rem = array[c-1] MOD array[c-2]
IFB rem = 0 THEN
IFB LENGTH(array) = 2 THEN
RESULT = array[c-2]
EXIT
ENDIF
RESIZE(array, c-2)
RESULT = GCD(array)
EXIT
ENDIF
array[c-1] = array[c-2]
array[c-2] = rem
RESULT = GCD(array)
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 日付(”YYYYMMDD” or “YYYY/MM/DD” or “YYYY-MM-DD” or “YYYYMMDDHHNNSS” or “YYYY/MM/DD HH:NN:SS”)
// m : 第一引数の指定日からプラスマイナスm月とする
// 【戻り値】
// dateからm月後の月末の日付
//////////////////////////////////////////////////
FUNCTION getEndOfMonth(date, m = 0)
date = dateAdd("m", m + 1, date)
GETTIME(0, date)
GETTIME(-G_TIME_DD, date)
RESULT = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 日付文字列(”YYYYMMDD” or “YYYY/MM/DD” or “YYYY-MM-DD” or “YYYYMMDDHHNNSS” or “YYYY/MM/DD HH:NN:SS”)もしくはシリアル値
// type : 取得する曜日番号の種類を示す0〜3または11〜17の値。1と17は日曜日を1、2と11は月曜日を1とカウントします。11以降はExcel2010で追加された値で、互換性を保つために重複した値があります。
// 【戻り値】
// typeで指定した種類によって以下の値を返します。 : (0 : 0(日曜)〜6(土曜)、1 : 1(日曜)~7(土曜)、2 : 1(月曜)~7(日曜)、3 : 0(月曜)〜6(日曜)、11 : 1(月曜)~7(日曜)、12 : 1(火曜)~7(月曜)、13 : 1(水曜)~7(火曜)、14 : 1(木曜)~7(水曜)、15 : 1(金曜)~7(木曜)、16 : 1(土曜)~7(金曜)、17 : 1(日曜)~7(土曜))
//////////////////////////////////////////////////
FUNCTION getWeekday(date, type = 1)
IF VARTYPE(date) <> 258 THEN date = text(date, "yyyy/mm/dd")
GETTIME(0, date)
DIM w = G_TIME_WW
SELECT TRUE
CASE type = 0
RESULT = w
CASE type = 1
RESULT = w + 1
CASE type = 2
RESULT = IIF(w=0, 7, w)
CASE type = 3
RESULT = (w+6) MOD 7
CASE type >= 11
RESULT = ((getWeekday(date, 2) + 17 - type) MOD 7) + 1
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// serial : シリアル値もしくは時刻文字列
// 【戻り値】
// 時刻から時間を表す0〜23の範囲の値
//////////////////////////////////////////////////
FUNCTION Hour(serial)
IF VARTYPE(serial) = 258 THEN serial = timeValue(serial)
RESULT = INT(serial * 24) MOD 24
FEND
//////////////////////////////////////////////////
// 【引数】
// expr : 評価する式
// truepart : 評価した式がTrueのときに返す値
// falsepart : 評価した式がFalseのときに返す値
// 【戻り値】
// truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
IFB EVAL(expr) THEN
RESULT = truepart
ELSE
RESULT = falsepart
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 存在するかを調べる日付文字列。YYYYMMDD or YYYY/MM/DD or YYYY-MM-DDのいずれかの形式。
// 【戻り値】
// TRUE : 日付として認識できる、FALSE : 日付として認識できない
//////////////////////////////////////////////////
FUNCTION isDate(date)
TRY
GETTIME(0, date)
RESULT = TRUE
EXCEPT
RESULT = FALSE
ENDTRY
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現で検索した結果をMatchesコレクションとして返します。
//////////////////////////////////////////////////
FUNCTION reExecute(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Execute(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現にマッチするかどうかを示すブール値
//////////////////////////////////////////////////
FUNCTION reTest(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Test(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// inputs : 繰り返す文字列
// multiplier : inputsを繰り返す回数
// 【戻り値】
// inputsをmultiplier回を繰り返した文字列を返します
//////////////////////////////////////////////////
FUNCTION strRepeat(inputs, multiplier)
DIM res = ""
FOR n = 1 TO multiplier
res = res + inputs
NEXT
RESULT = res
FEND
//////////////////////////////////////////////////
// 【引数】
// serial : シリアル値
// format : フォーマット
// 【戻り値】
// 数値を表示書式に基づいて変換した文字列
//////////////////////////////////////////////////
FUNCTION text(serial, format, hour12 = FALSE)
HASHTBL startDate
startDate["明治"] = "1868/01/25"
startDate["大正"] = "1912/07/30"
startDate["昭和"] = "1926/12/25"
startDate["平成"] = "1989/01/08"
startDate["令和"] = "2019/05/01"
DIM baseDate = "1899/12/30"
serial = VAL(serial)
SELECT TRUE
CASE reTest(format, "\[h+\]")
Matches = reExecute(format, "\[(h+)\]")
DIM hour = iif(hour12, Hour(serial) MOD 12, Hour(serial))
RESULT = text(hour, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE reTest(format, "^h+$")
Matches = reExecute(format, "^(h+)$")
hour = iif(hour12, Hour(serial) MOD 12, Hour(serial))
RESULT = text(hour MOD 24, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE reTest(format, "\[m+\]")
Matches = reExecute(format, "\[(m+)\]")
RESULT = text(serial * 1440, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE format = "m"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_MM, "0")
CASE format = "mm"
GETTIME(serial, baseDate)
RESULT = G_TIME_MM2
CASE format = "n"
GETTIME(serial, baseDate)
RESULT = G_TIME_NN
CASE format = "nn"
GETTIME(serial, baseDate)
RESULT = G_TIME_NN2
CASE format = "s"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_SS, "0")
CASE format = "ss"
GETTIME(serial, baseDate)
RESULT = G_TIME_SS2
CASE format = "yyyy"
GETTIME(serial, baseDate)
RESULT = G_TIME_YY4
CASE format = "yy"
GETTIME(serial, baseDate)
RESULT = COPY(G_TIME_YY4, 3, 2)
CASE format = "e"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 2018
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1988
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1925
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1911
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1867
SELEND
CASE format = "ee"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 2018, "00")
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1988, "00")
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1925, "00")
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1911, "00")
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1867, "00")
SELEND
CASE format = "g"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "R"
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "H"
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "S"
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "T"
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "M"
SELEND
CASE format = "gg"
RESULT = COPY(text(serial, "ggg"), 1, 1)
CASE format = "ggg"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "令和"
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "平成"
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "昭和"
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "大正"
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "明治"
SELEND
CASE format = "mmmmm"
RESULT = COPY(text(serial, "mmmm"), 1, 1)
CASE format = "mmmm"
DIM month[] = "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
RESULT = month[text(serial, "m") - 1]
CASE format = "mmm"
RESULT = COPY(text(serial, "mmmm"), 1, 3)
CASE format = "dd"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_DD2, "00")
CASE format = "d"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_DD, "0")
CASE reTest(format, "^[ad]{3,4}$")
Matches = reExecute(format, "([ad]{3,4})")
GETTIME(serial, baseDate)
DIM aaa[] = "日", "月", "火", "水", "木", "金", "土"
DIM aaaa[] = "日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"
DIM ddd[] = "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
DIM dddd[] = "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday";
RESULT = EVAL(Matches.Item(0).SubMatches(0) + "[" + getWeekday(G_TIME_WW, 1) + "]")
CASE reTest(format, "(0+\.?0+)?%")
Matches = reExecute(format, "(0+\.?0+)?%")
RESULT = text(serial * 100, Matches.Item(0).SubMatches(0)) + "%"
CASE reTest(format, "^\[DBNum\d{1,4}\](.*?)$")
Matches = reExecute(format, "^\[DBNum(\d{1,4})\](.*?)$")
DIM value = VAL(Matches.Item(0).SubMatches(0))
DIM sss = text(serial, Matches.Item(0).SubMatches(1))
Matches = reExecute(sss, "(\D+)?(\d+)(\D+)?")
DIM res = ""
FOR m = 0 TO Matches.Count - 1
serial = Matches.Item(m).SubMatches(1)
SELECT value
CASE 1, 2
DIM n[][9] = "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九", + _
"", "壱", "弐", "参", "四", "伍", "六", "七", "八", "九"
DIM a[][3] = "", "十", "百", "千", + _
"", "拾", "百", "阡"
DIM b[][3] = "", "万", "億", "兆", + _
"", "萬", "億", "兆"
DIM r = ""
DIM j = 0
type = value - 1
REPEAT
DIM str = ""
DIM n4 = serial MOD 10000
FOR i = LENGTH(n4) TO 1 STEP -1
s = COPY(n4, i, 1)
IFB s = 1 AND a[type][LENGTH(n4)-i] <> "" THEN
str = IIF(s, a[type][LENGTH(n4)-i], "") + str
ELSE
str = n[type][s] + IIF(s, a[type][LENGTH(n4)-i], "") + str
ENDIF
NEXT
IF str <> "" THEN r = str + b[type][j] + r
j = j + 1
serial = INT(serial / 10000)
UNTIL serial = 0
res = res + Matches.Item(m).SubMatches(0) + r + Matches.Item(m).SubMatches(2)
CASE 3
res = res + Matches.Item(m).SubMatches(0) + STRCONV(serial, SC_FULLWIDTH) + Matches.Item(m).SubMatches(2)
CASE 4
res = res + Matches.Item(m).SubMatches(0) + STRCONV(serial, SC_HALFWIDTH) + Matches.Item(m).SubMatches(2)
SELEND
NEXT
RESULT = res
CASE reTest(format, "^(.*?)(AM\/PM|am\/pm|A\/P|a\/p)(.*?)$")
Matches = reExecute(format, "^(.*?)(AM\/PM|am\/pm|A\/P|a\/p)(.*?)$")
DIM array = SPLIT(Matches.Item(0).SubMatches(1), "/")
ampm = array[IIF(serial - INT(serial) >= 0.5, 1, 0)]
hour12 = TRUE
res = ""
WITH Matches.Item(0)
res = text(serial, .SubMatches(0), hour12) + ampm + text(serial, .SubMatches(2), hour12)
ENDWITH
RESULT = res
CASE reTest(format, "([^ymdagehns]{0,})?(([ymdagehns])\3{0,})([^ymdagehns]+)?")
Matches = reExecute(format, "([^ymdagehns]{0,})?(([ymdagehns])\3{0,})([^ymdagehns]+)?")
FOR n = 0 TO Matches.Count - 1
IF n = 0 THEN res = Matches.Item(n).SubMatches(0)
NEXT
FOR n = 0 TO Matches.Count - 1
WITH Matches.Item(n)
res = res + text(serial, .SubMatches(1), hour12) + .SubMatches(3)
ENDWITH
NEXT
RESULT = res
CASE format = "0/0"
DIM separator = POS(".", serial)
DIM g = 0
IFB separator <> 0 THEN
DIM keta = LENGTH(serial)
DIM shift = POWER(10, keta - separator)
IFB shift >= POWER(10, 15) THEN
DIM position = 0
FOR i = 0 TO 14
IFB serial * POWER(10, i) - serial >= 1 THEN
position = i
BREAK
ENDIF
NEXT
tmp = serial * POWER(10, position)
FOR i = 1 TO 15
r = (tmp * POWER(10, i)) / serial - (tmp / serial)
a1 = tmp * POWER(10, i) - tmp
IF a1 = INT(a1) THEN BREAK
NEXT
DIM frac[] = a1, r
g = GCD(frac)
RESULT = (a1/g) + "/" + (r/g)
ELSE
DIM molecule = serial * shift // 分子
DIM denominator = shift // 分母
DIM nums[] = molecule, denominator
g = GCD(nums)
molecule = molecule / g
denominator = denominator / g
RESULT = molecule + "/" + denominator
ENDIF
ELSE
RESULT = serial + "/1"
ENDIF
CASE reTest(format, "(0+)\.?(0+)?") AND UBound(SPLIT(format, ".")) <= 1
Matches = reExecute(format, "(0+)\.?(0+)?")
len1 = LENGTH(Matches.Item(0).SubMatches(0))
len2 = LENGTH(Matches.Item(0).SubMatches(1))
DIM arr[] = LENGTH(INT(serial)), len1
IFB POS(".", format) THEN
RESULT = REPLACE(FORMAT(serial, CALCARRAY(arr, CALC_MAX) + len2 + 1, len2), " ", "0")
ELSE
RESULT = REPLACE(FORMAT(serial, CALCARRAY(arr, CALC_MAX)), " ", "0")
ENDIF
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 時刻文字列。hh:nn:ss AM/PM、hh:nn AM/PM、hh AM/PM、hh:nn:ss、hh:nn、hh時nn分ss秒、hh時nn分のいずれかの形式を指定。
// 【戻り値】
// シリアル値 (例)0…00:00:00、0.5…12:00:00、0.999988425925926…23:59:59
//////////////////////////////////////////////////
FUNCTION timeValue(str)
DIM serial = 0
DIM Matches
DIM pattern = "(\d+)"
DIM hh = "(0?[0-9]|1[0-2])"
DIM ampm = "([AP]M|[ap]m)"
SELECT TRUE
CASE reTest(str, "\b" + hh + ":" + pattern + ":" + pattern + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + ":" + pattern + ":" + pattern + " " + ampm + "\b")
WITH Matches.Item(0)
serial = timeValue(.SubMatches(0) + " " + .SubMatches(3)) + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + hh + ":" + pattern + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + ":" + pattern + " " + ampm + "\b")
WITH Matches.Item(0)
serial = timeValue(.SubMatches(0) + " " + .SubMatches(2)) + VAL(.SubMatches(1)) / 1440
ENDWITH
CASE reTest(str, "\b" + hh + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + " " + ampm + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0) MOD 12) + IIF(reTest(.SubMatches(1), "AM|am"), 0, 12)
serial = serial / 24
ENDWITH
CASE reTest(str, "\b" + pattern + ":" + pattern + ":" + pattern + "\b")
Matches = reExecute(str, "\b" + pattern + ":" + pattern + ":" + pattern + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + pattern + ":" + pattern + "\b")
Matches = reExecute(str, "\b" + pattern + ":" + pattern + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440
ENDWITH
CASE reTest(str, "\b" + pattern + "時" + pattern + "分" + pattern + "秒")
Matches = reExecute(str, "\b" + pattern + "時" + pattern + "分" + pattern + "秒")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + pattern + "時" + pattern + "分")
Matches = reExecute(str, "\b" + pattern + "時" + pattern + "分")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440
ENDWITH
DEFAULT
serial = ERR_VALUE
SELEND
RESULT = serial - INT(serial)
FEND
//////////////////////////////////////////////////
// 【引数】
// arrayname : 上限値を求める配列の名前
// dimension : 返す次元を示す整数
// 【戻り値】
// 配列の上限値
//////////////////////////////////////////////////
FUNCTION UBound(arrayname[], dimension = 1)
RESULT = EVAL("RESIZE(arrayname" + strRepeat("[0]", dimension - 1) + ")")
FEND// フォーム(入力画面)を出し、入力された値を表示
btn = CREATEFORM("testform.html", "タイトル", False, 0, 400, 480)
print "押されたボタン(Submit)= " + btn
print "text(一行)= "+ GETFORMDATA("Text1")
wks = "チェックボックス="
if GETFORMDATA("Check1") then wks = wks + " aaaa"
if GETFORMDATA("Check2") then wks = wks + " bbbb"
print wks
if GETFORMDATA("Radio1", "V1") then print "ラジオボタン= 1111"
if GETFORMDATA("Radio1", "V2") then print "ラジオボタン= 2222"
print "セレクトボックス= "+ GETFORMDATA("D1") // 複数時はTAB区切り
print "text(複数行)= "+ GETFORMDATA("S1")
//////////////////////////////////////////////////
// 【引数】
// interval : 加算する時間間隔を表す文字列式(yyyy:年、m:月、d:日、ww:週、h:時、n:分、s:秒)
// num : dateに加算する値。未来は正、過去は負で指定
// date : 時間間隔を加算する日付
// 【戻り値】
// 日時(date)に、指定した単位(interval)の時間(num)を加算して返します
//////////////////////////////////////////////////
FUNCTION dateAdd(interval, num, date)
DIM year, month, day, d
GETTIME(0, date)
DIM time = G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2
SELECT interval
CASE "yyyy"
d = (G_TIME_YY + num) + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
IF time <> "00:00:00" THEN d = d + " " + time
CASE "m"
IFB num > 0 THEN
year = G_TIME_YY + INT((G_TIME_MM + num) / 12)
month = REPLACE(FORMAT(((G_TIME_MM + num) MOD 12), 2), " ", "0")
ELSE
year = G_TIME_YY + CEIL((G_TIME_MM + num) / 12 - 1)
month = REPLACE(FORMAT(G_TIME_MM - (ABS(num) MOD 12), 2), " ", "0")
ENDIF
IF month = "00" THEN month = 12
day = G_TIME_DD2
d = "" + year + month + day
IFB !isDate(d) THEN
d = year + "/" + month + "/" + "01"
d = getEndOfMonth(d)
ELSE
d = year + "/" + month + "/" + day
ENDIF
IF time <> "00:00:00" THEN d = d + " " + time
CASE "d"
t = GETTIME(num, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "ww"
t = GETTIME(num * 7, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "h"
t = GETTIME(num / 24, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "n"
t = GETTIME(num / 1440, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
CASE "s"
t = GETTIME(num / 86400, date)
d = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2 + IIF(t MOD 86400, " " + G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2, "")
SELEND
RESULT = d
FEND
//////////////////////////////////////////////////
// 【引数】
// interval : 時間単位(yyyy︰年、q:四半期、m︰月、d︰日、w:週日、ww:週、h:時、n:分、s:秒)
// date1 : 日時1
// date2 : 日時2
// 【戻り値】
// date2からdate1を引いた時間間隔を求めます。
//////////////////////////////////////////////////
FUNCTION dateDiff(interval, date1, date2)
DIM y1, y2, m1, m2, d1, d2, d
SELECT interval
CASE "yyyy"
GETTIME(0, date1)
y1 = G_TIME_YY
GETTIME(0, date2)
y2 = G_TIME_YY
d = y2 - y1
CASE "q"
GETTIME(0, date1)
y1 = G_TIME_YY
m1 = G_TIME_MM
GETTIME(0, date2)
y2 = G_TIME_YY
m2 = G_TIME_MM
d = y2 * 4 + CEIL(m2/3) - (y1 * 4 + CEIL(m1/3))
CASE "m"
GETTIME(0, date1)
y1 = G_TIME_YY
m1 = G_TIME_MM
GETTIME(0, date2)
y2 = G_TIME_YY
m2 = G_TIME_MM
d = (y2 - y1) * 12 + m2 - m1
CASE "d"
d1 = GETTIME(0, date1)
d2 = GETTIME(0, date2)
d = (d2 - d1) / 86400
CASE "w"
d = INT(dateDiff("d", date1, date2) / 7)
CASE "ww"
date1 = dateAdd("d", -1 * getWeekday(date1), date1)
d = INT(dateDiff("d", date1, date2) / 7)
CASE "h"
d = dateDiff("d", date1, date2) * 24
CASE "n"
d = dateDiff("d", date1, date2) * 1440
CASE "s"
d = dateDiff("d", date1, date2) * 86400
SELEND
RESULT = d
FEND
//////////////////////////////////////////////////
// 【引数】
// array : 最大公約数を求める数値を格納した配列
// 【戻り値】
// 最大公約数
//////////////////////////////////////////////////
FUNCTION GCD(array[])
DIM c = LENGTH(array)
DIM rem = array[c-1] MOD array[c-2]
IFB rem = 0 THEN
IFB LENGTH(array) = 2 THEN
RESULT = array[c-2]
EXIT
ENDIF
RESIZE(array, c-2)
RESULT = GCD(array)
EXIT
ENDIF
array[c-1] = array[c-2]
array[c-2] = rem
RESULT = GCD(array)
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 日付(”YYYYMMDD” or “YYYY/MM/DD” or “YYYY-MM-DD” or “YYYYMMDDHHNNSS” or “YYYY/MM/DD HH:NN:SS”)
// m : 第一引数の指定日からプラスマイナスm月とする
// 【戻り値】
// dateからm月後の月末の日付
//////////////////////////////////////////////////
FUNCTION getEndOfMonth(date, m = 0)
date = dateAdd("m", m + 1, date)
GETTIME(0, date)
GETTIME(-G_TIME_DD, date)
RESULT = G_TIME_YY4 + "/" + G_TIME_MM2 + "/" + G_TIME_DD2
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 日付文字列(”YYYYMMDD” or “YYYY/MM/DD” or “YYYY-MM-DD” or “YYYYMMDDHHNNSS” or “YYYY/MM/DD HH:NN:SS”)もしくはシリアル値
// type : 取得する曜日番号の種類を示す0〜3または11〜17の値。1と17は日曜日を1、2と11は月曜日を1とカウントします。11以降はExcel2010で追加された値で、互換性を保つために重複した値があります。
// 【戻り値】
// typeで指定した種類によって以下の値を返します。 : (0 : 0(日曜)〜6(土曜)、1 : 1(日曜)~7(土曜)、2 : 1(月曜)~7(日曜)、3 : 0(月曜)〜6(日曜)、11 : 1(月曜)~7(日曜)、12 : 1(火曜)~7(月曜)、13 : 1(水曜)~7(火曜)、14 : 1(木曜)~7(水曜)、15 : 1(金曜)~7(木曜)、16 : 1(土曜)~7(金曜)、17 : 1(日曜)~7(土曜))
//////////////////////////////////////////////////
FUNCTION getWeekday(date, type = 1)
IF VARTYPE(date) <> 258 THEN date = text(date, "yyyy/mm/dd")
GETTIME(0, date)
DIM w = G_TIME_WW
SELECT TRUE
CASE type = 0
RESULT = w
CASE type = 1
RESULT = w + 1
CASE type = 2
RESULT = IIF(w=0, 7, w)
CASE type = 3
RESULT = (w+6) MOD 7
CASE type >= 11
RESULT = ((getWeekday(date, 2) + 17 - type) MOD 7) + 1
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// serial : シリアル値もしくは時刻文字列
// 【戻り値】
// 時刻から時間を表す0〜23の範囲の値
//////////////////////////////////////////////////
FUNCTION Hour(serial)
IF VARTYPE(serial) = 258 THEN serial = timeValue(serial)
RESULT = INT(serial * 24) MOD 24
FEND
//////////////////////////////////////////////////
// 【引数】
// expr : 評価する式
// truepart : 評価した式がTrueのときに返す値
// falsepart : 評価した式がFalseのときに返す値
// 【戻り値】
// truepart : 評価した式がTrueのとき、falsepart : 評価した式がFalseのとき
//////////////////////////////////////////////////
FUNCTION IIF(expr, truepart, falsepart)
IFB EVAL(expr) THEN
RESULT = truepart
ELSE
RESULT = falsepart
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// date : 存在するかを調べる日付文字列。YYYYMMDD or YYYY/MM/DD or YYYY-MM-DDのいずれかの形式。
// 【戻り値】
// TRUE : 日付として認識できる、FALSE : 日付として認識できない
//////////////////////////////////////////////////
FUNCTION isDate(date)
TRY
GETTIME(0, date)
RESULT = TRUE
EXCEPT
RESULT = FALSE
ENDTRY
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現で検索した結果をMatchesコレクションとして返します。
//////////////////////////////////////////////////
FUNCTION reExecute(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Execute(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 正規表現による検索の対象となる文字列
// Pattern : 正規表現で使用するパターンを設定
// IgnoreCase : 大文字・小文字を区別しない場合はTrue、区別する場合はFalse
// Global : 文字列全体を検索する場合はTrue、しない場合はFalse
// 【戻り値】
// 正規表現にマッチするかどうかを示すブール値
//////////////////////////////////////////////////
FUNCTION reTest(str, Pattern, IgnoreCase = TRUE, Global = TRUE)
DIM re = CREATEOLEOBJ("VBScript.RegExp")
re.Pattern = Pattern
re.IgnoreCase = IgnoreCase
re.Global = Global
RESULT = re.Test(str)
FEND
//////////////////////////////////////////////////
// 【引数】
// inputs : 繰り返す文字列
// multiplier : inputsを繰り返す回数
// 【戻り値】
// inputsをmultiplier回を繰り返した文字列を返します
//////////////////////////////////////////////////
FUNCTION strRepeat(inputs, multiplier)
DIM res = ""
FOR n = 1 TO multiplier
res = res + inputs
NEXT
RESULT = res
FEND
//////////////////////////////////////////////////
// 【引数】
// serial : シリアル値
// format : フォーマット
// 【戻り値】
// 数値を表示書式に基づいて変換した文字列
//////////////////////////////////////////////////
FUNCTION text(serial, format, hour12 = FALSE)
HASHTBL startDate
startDate["明治"] = "1868/01/25"
startDate["大正"] = "1912/07/30"
startDate["昭和"] = "1926/12/25"
startDate["平成"] = "1989/01/08"
startDate["令和"] = "2019/05/01"
DIM baseDate = "1899/12/30"
serial = VAL(serial)
SELECT TRUE
CASE reTest(format, "\[h+\]")
Matches = reExecute(format, "\[(h+)\]")
DIM hour = iif(hour12, Hour(serial) MOD 12, Hour(serial))
RESULT = text(hour, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE reTest(format, "^h+$")
Matches = reExecute(format, "^(h+)$")
hour = iif(hour12, Hour(serial) MOD 12, Hour(serial))
RESULT = text(hour MOD 24, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE reTest(format, "\[m+\]")
Matches = reExecute(format, "\[(m+)\]")
RESULT = text(serial * 1440, strRepeat("0", LENGTH(Matches.Item(0).SubMatches(0))))
CASE format = "m"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_MM, "0")
CASE format = "mm"
GETTIME(serial, baseDate)
RESULT = G_TIME_MM2
CASE format = "n"
GETTIME(serial, baseDate)
RESULT = G_TIME_NN
CASE format = "nn"
GETTIME(serial, baseDate)
RESULT = G_TIME_NN2
CASE format = "s"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_SS, "0")
CASE format = "ss"
GETTIME(serial, baseDate)
RESULT = G_TIME_SS2
CASE format = "yyyy"
GETTIME(serial, baseDate)
RESULT = G_TIME_YY4
CASE format = "yy"
GETTIME(serial, baseDate)
RESULT = COPY(G_TIME_YY4, 3, 2)
CASE format = "e"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 2018
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1988
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1925
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1911
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(serial, "yyyy") - 1867
SELEND
CASE format = "ee"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 2018, "00")
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1988, "00")
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1925, "00")
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1911, "00")
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0
RESULT = text(text(serial, "yyyy") - 1867, "00")
SELEND
CASE format = "g"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "R"
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "H"
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "S"
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "T"
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "M"
SELEND
CASE format = "gg"
RESULT = COPY(text(serial, "ggg"), 1, 1)
CASE format = "ggg"
SELECT TRUE
CASE dateDiff("d", startDate["令和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "令和"
CASE dateDiff("d", startDate["平成"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "平成"
CASE dateDiff("d", startDate["昭和"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "昭和"
CASE dateDiff("d", startDate["大正"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "大正"
CASE dateDiff("d", startDate["明治"], text(serial, "yyyy/mm/dd")) >= 0; RESULT = "明治"
SELEND
CASE format = "mmmmm"
RESULT = COPY(text(serial, "mmmm"), 1, 1)
CASE format = "mmmm"
DIM month[] = "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
RESULT = month[text(serial, "m") - 1]
CASE format = "mmm"
RESULT = COPY(text(serial, "mmmm"), 1, 3)
CASE format = "dd"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_DD2, "00")
CASE format = "d"
GETTIME(serial, baseDate)
RESULT = text(G_TIME_DD, "0")
CASE reTest(format, "^[ad]{3,4}$")
Matches = reExecute(format, "([ad]{3,4})")
GETTIME(serial, baseDate)
DIM aaa[] = "日", "月", "火", "水", "木", "金", "土"
DIM aaaa[] = "日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"
DIM ddd[] = "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
DIM dddd[] = "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday";
RESULT = EVAL(Matches.Item(0).SubMatches(0) + "[" + getWeekday(G_TIME_WW, 1) + "]")
CASE reTest(format, "(0+\.?0+)?%")
Matches = reExecute(format, "(0+\.?0+)?%")
RESULT = text(serial * 100, Matches.Item(0).SubMatches(0)) + "%"
CASE reTest(format, "^\[DBNum\d{1,4}\](.*?)$")
Matches = reExecute(format, "^\[DBNum(\d{1,4})\](.*?)$")
DIM value = VAL(Matches.Item(0).SubMatches(0))
DIM sss = text(serial, Matches.Item(0).SubMatches(1))
Matches = reExecute(sss, "(\D+)?(\d+)(\D+)?")
DIM res = ""
FOR m = 0 TO Matches.Count - 1
serial = Matches.Item(m).SubMatches(1)
SELECT value
CASE 1, 2
DIM n[][9] = "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九", + _
"", "壱", "弐", "参", "四", "伍", "六", "七", "八", "九"
DIM a[][3] = "", "十", "百", "千", + _
"", "拾", "百", "阡"
DIM b[][3] = "", "万", "億", "兆", + _
"", "萬", "億", "兆"
DIM r = ""
DIM j = 0
type = value - 1
REPEAT
DIM str = ""
DIM n4 = serial MOD 10000
FOR i = LENGTH(n4) TO 1 STEP -1
s = COPY(n4, i, 1)
IFB s = 1 AND a[type][LENGTH(n4)-i] <> "" THEN
str = IIF(s, a[type][LENGTH(n4)-i], "") + str
ELSE
str = n[type][s] + IIF(s, a[type][LENGTH(n4)-i], "") + str
ENDIF
NEXT
IF str <> "" THEN r = str + b[type][j] + r
j = j + 1
serial = INT(serial / 10000)
UNTIL serial = 0
res = res + Matches.Item(m).SubMatches(0) + r + Matches.Item(m).SubMatches(2)
CASE 3
res = res + Matches.Item(m).SubMatches(0) + STRCONV(serial, SC_FULLWIDTH) + Matches.Item(m).SubMatches(2)
CASE 4
res = res + Matches.Item(m).SubMatches(0) + STRCONV(serial, SC_HALFWIDTH) + Matches.Item(m).SubMatches(2)
SELEND
NEXT
RESULT = res
CASE reTest(format, "^(.*?)(AM\/PM|am\/pm|A\/P|a\/p)(.*?)$")
Matches = reExecute(format, "^(.*?)(AM\/PM|am\/pm|A\/P|a\/p)(.*?)$")
DIM array = SPLIT(Matches.Item(0).SubMatches(1), "/")
ampm = array[IIF(serial - INT(serial) >= 0.5, 1, 0)]
hour12 = TRUE
res = ""
WITH Matches.Item(0)
res = text(serial, .SubMatches(0), hour12) + ampm + text(serial, .SubMatches(2), hour12)
ENDWITH
RESULT = res
CASE reTest(format, "([^ymdagehns]{0,})?(([ymdagehns])\3{0,})([^ymdagehns]+)?")
Matches = reExecute(format, "([^ymdagehns]{0,})?(([ymdagehns])\3{0,})([^ymdagehns]+)?")
FOR n = 0 TO Matches.Count - 1
IF n = 0 THEN res = Matches.Item(n).SubMatches(0)
NEXT
FOR n = 0 TO Matches.Count - 1
WITH Matches.Item(n)
res = res + text(serial, .SubMatches(1), hour12) + .SubMatches(3)
ENDWITH
NEXT
RESULT = res
CASE format = "0/0"
DIM separator = POS(".", serial)
DIM g = 0
IFB separator <> 0 THEN
DIM keta = LENGTH(serial)
DIM shift = POWER(10, keta - separator)
IFB shift >= POWER(10, 15) THEN
DIM position = 0
FOR i = 0 TO 14
IFB serial * POWER(10, i) - serial >= 1 THEN
position = i
BREAK
ENDIF
NEXT
tmp = serial * POWER(10, position)
FOR i = 1 TO 15
r = (tmp * POWER(10, i)) / serial - (tmp / serial)
a1 = tmp * POWER(10, i) - tmp
IF a1 = INT(a1) THEN BREAK
NEXT
DIM frac[] = a1, r
g = GCD(frac)
RESULT = (a1/g) + "/" + (r/g)
ELSE
DIM molecule = serial * shift // 分子
DIM denominator = shift // 分母
DIM nums[] = molecule, denominator
g = GCD(nums)
molecule = molecule / g
denominator = denominator / g
RESULT = molecule + "/" + denominator
ENDIF
ELSE
RESULT = serial + "/1"
ENDIF
CASE reTest(format, "(0+)\.?(0+)?") AND UBound(SPLIT(format, ".")) <= 1
Matches = reExecute(format, "(0+)\.?(0+)?")
len1 = LENGTH(Matches.Item(0).SubMatches(0))
len2 = LENGTH(Matches.Item(0).SubMatches(1))
DIM arr[] = LENGTH(INT(serial)), len1
IFB POS(".", format) THEN
RESULT = REPLACE(FORMAT(serial, CALCARRAY(arr, CALC_MAX) + len2 + 1, len2), " ", "0")
ELSE
RESULT = REPLACE(FORMAT(serial, CALCARRAY(arr, CALC_MAX)), " ", "0")
ENDIF
SELEND
FEND
//////////////////////////////////////////////////
// 【引数】
// str : 時刻文字列。hh:nn:ss AM/PM、hh:nn AM/PM、hh AM/PM、hh:nn:ss、hh:nn、hh時nn分ss秒、hh時nn分のいずれかの形式を指定。
// 【戻り値】
// シリアル値 (例)0…00:00:00、0.5…12:00:00、0.999988425925926…23:59:59
//////////////////////////////////////////////////
FUNCTION timeValue(str)
DIM serial = 0
DIM Matches
DIM pattern = "(\d+)"
DIM hh = "(0?[0-9]|1[0-2])"
DIM ampm = "([AP]M|[ap]m)"
SELECT TRUE
CASE reTest(str, "\b" + hh + ":" + pattern + ":" + pattern + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + ":" + pattern + ":" + pattern + " " + ampm + "\b")
WITH Matches.Item(0)
serial = timeValue(.SubMatches(0) + " " + .SubMatches(3)) + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + hh + ":" + pattern + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + ":" + pattern + " " + ampm + "\b")
WITH Matches.Item(0)
serial = timeValue(.SubMatches(0) + " " + .SubMatches(2)) + VAL(.SubMatches(1)) / 1440
ENDWITH
CASE reTest(str, "\b" + hh + " " + ampm + "\b")
Matches = reExecute(str, "\b" + hh + " " + ampm + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0) MOD 12) + IIF(reTest(.SubMatches(1), "AM|am"), 0, 12)
serial = serial / 24
ENDWITH
CASE reTest(str, "\b" + pattern + ":" + pattern + ":" + pattern + "\b")
Matches = reExecute(str, "\b" + pattern + ":" + pattern + ":" + pattern + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + pattern + ":" + pattern + "\b")
Matches = reExecute(str, "\b" + pattern + ":" + pattern + "\b")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440
ENDWITH
CASE reTest(str, "\b" + pattern + "時" + pattern + "分" + pattern + "秒")
Matches = reExecute(str, "\b" + pattern + "時" + pattern + "分" + pattern + "秒")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440 + VAL(.SubMatches(2)) / 86400
ENDWITH
CASE reTest(str, "\b" + pattern + "時" + pattern + "分")
Matches = reExecute(str, "\b" + pattern + "時" + pattern + "分")
WITH Matches.Item(0)
serial = VAL(.SubMatches(0)) / 24 + VAL(.SubMatches(1)) / 1440
ENDWITH
DEFAULT
serial = ERR_VALUE
SELEND
RESULT = serial - INT(serial)
FEND
//////////////////////////////////////////////////
// 【引数】
// arrayname : 上限値を求める配列の名前
// dimension : 返す次元を示す整数
// 【戻り値】
// 配列の上限値
//////////////////////////////////////////////////
FUNCTION UBound(arrayname[], dimension = 1)
RESULT = EVAL("RESIZE(arrayname" + strRepeat("[0]", dimension - 1) + ")")
FEND// マウス位置の文字情報を取得
While True
x = G_MOUSE_X; y = G_MOUSE_Y // マウス位置
id = GETID(GET_FROMPOINT_WIN) // アクティブウィンドウ
ofx = x - STATUS(id, ST_CLX) // 相対位置
ofy = y - STATUS(id, ST_CLY)
wks = PosACC(id, ofx, ofy)
wks = wks + "<#CR>" + PosACC(id, ofx, ofy, ACC_NAME)
wks = wks + "<#CR>" + PosACC(id, ofx, ofy, ACC_VALUE)
wks = wks + "<#CR>" + PosACC(id, ofx, ofy, ACC_ROLE)
wks = wks + "<#CR>" + PosACC(id, ofx, ofy, ACC_STATE)
wks = wks + "<#cr>" + "x="+ofx+", y="+ofy
Fukidasi(wks, x+10, y+10, 3)
Sleep(0.5)
Wend// 入力された文字を全角大文字にしてメモ帳に表示していく
CONST 漢数字 = "一二三四五六七八九"
メモID = EXEC("notepad.exe")
While True
wks = INPUT("何か文字を入れて下さい")
if wks = EMPTY then break
wks = STRCONV(wks, SC_UPPERCASE or SC_FULLWIDTH)
for i = 1 to 9 // 数字は漢数字に
wks = Replace(wks, CHR(ASC("0")+i), Copy(漢数字,i,1))
next
SENDSTR(メモID, wks+"<#CR>")
WendFont / Color
エディタのフォントと色を設定します。
- Tab
- タブ幅を指定します。
- Font
- フォントを指定します。
- Font Color
- ベースの文字色を設定します。
- Background
- 背景色を指定します。
- 構文
- 構文(その他項目)の文字色を指定。
- 定数
- 定数(その他項目)の文字色を指定。
- 特殊変数
- 特殊変数(その他項目)の文字色を指定。
- コメント
- コメント部分(ダブルスラッシュ)箇所の文字色を指定。
- UWSC関数
- UWSC関数(その他項目)の文字色を指定。
- 文字列
- ダブルクォーテーション("文字列")で囲まれた範囲の文字色を指定。
太字・斜体にする場合はチェックボックスにチェックを入れます。
Uws2Exe
UWSCファイルをEXEファイルにします。EXE化後は単体での実行が可能で、ライセンスフリーにて配布できます。
完成したスクリプトまたは改竄されたくないスクリプトをEXE化するときに使います。
UWSCをインストールしていない環境でも実行することができます。
- EXE化するスクリプトを指定してください
- EXE化するファイルを指定またはウィンドウ上にドラッグします。複数ファイルで構成されている場合は、トップのスクリプトを指定します。
CALL文で呼ばれるファイル、CREATEFORM関数のHTMLファイル、CHKIMG関数の画像ファイルは自動で取り込まれます、変数でファイル名が指定されている場合は取り込みません。
(HTML画面に関しては下記HTML画面使用にてを参照) - アイコンの変更
- アイコンを変更するときはチェックを入れ、拡張子が*.ICOのファイルを指定してください。PNG、JPEG、GIF、BMPの画像をアイコンに変更するには以下のリンクを利用してください。
- PNG ICO 変換。オンライン フリー — Convertio
- JPG ICO 変換。オンライン フリー — Convertio
- GIF ICO 変換。オンライン フリー — Convertio
- BMP ICO 変換。オンライン フリー — Convertio
- STOPボタンを出さない
- 画面上にSTOPボタンを出しません。
- タスクバーに出さない
- タスクバー上にアイコンを出しません。
(CREATEFORM関数によりフォームを作成した場合はフォームのアイコンは出ます) - INIファイルを作らない
- INIファイルを作成しません。
作成を許可している場合はUWSC.INIからPosition(位置)、StopHotKey(停止ホットキー)、LogLines(ログ行数)、DefaultFont(フォント)の情報をコピーします。 - ログファイルを作らない
- PRINT文で表示される情報を保存しません。
- BMPファイルを取り込まない
- CHKIMG関数にて使用するBMPファイルを取り込みません。
- 多重起動を許さない
- 多重起動を禁止します。多重起動を禁止にしているときに多重起動すると、後に開いたEXEファイルは強制終了します。
- 実行ファイルを圧縮する
- upxを利用してサイズを約3分の1にできます。
uws2exe.INIのUpxPath=にupx.exeのあるフォルダを記述することによりupxが使用できます。 - バージョン情報
- EXEのプロパティに埋め込まれるバージョン情報を設定します。
UWSファイルの中にコメント形式にて設定することもできます。
(下記バージョン情報の設定を参照。)
EXE化したものは単体で動作可能になります。
EXE化したものはライセンスフリーであり配布等は自由です。
UPX: the Ultimate Packer for eXecutables - HomepageにあるDownload latest releaseのリンクでGitHubのページが開くので、upx-4.2.1-win64.zipをダウンロードしてください。
HTML画面使用にて(複数ファイルで構成されているとき)
画像やCSSファイルがある場合もしくはマルチフレームの場合、htmlからmhtに変換して1ファイルにしてください。
(IEで表示してからファイル->名前を付けて保存でファイルの種類にてWebアーカイブ、単一のファイル(*.mht)を選択して保存)
バージョン情報の設定
UWSファイルの中にコメント形式にて設定できます。ここで指定した内容はEXE化するスクリプトを指定したときに自動的にバージョン情報の項目に適用されます。同じ項目を複数記述した場合は、より後に書かれた方が適用されます。
以下の内容をEXE化するスクリプトの先頭に記述しておきます。
// _EXEVERSION = 数値.数値.数値.数値
// _FILEDESCRIPTION = ファイルの説明
// _PRODUCTNAME = 製品名
// _LEGALCOPYRIGHT = 著作権実行停止について
INIファイルの作成が有効の場合には、UWSCの停止ホットキーと同じキーが引き継がれます。
他の停止方法としては、タスクバーのアイコン上で右クリックして閉じる(C)を選択、またはSETHOTKEY関数にて定義してください。
SETHOTKEY(VK_ESC, EMPTYPARAM, "forceQuit")
PROCEDURE forceQuit()
EXITEXIT
FENDコマンドラインからの起動
オプションは/もしくは-の後に連続で表記します。オプションは順不同で指定できます。
| オプション | 内容 |
|---|---|
| S | STOPボタンを出さない |
| T | タスクバーに出さない |
| I | INIファイルを作らない |
| L | ログファイルを作らない |
| B | BMPファイルを取り込まない |
| M | 多重起動を許さない |
| U | EXEファイルをの圧縮(uws2exe.INIのUpxPath=にupx.exeのあるパスを記述) |
| E | 画面を出さずにEXE化処理の実行 |
| EXE化するスクリプトの指定 変更するアイコンの指定 |
記述例
uws2exe.exe /SI c:\temp\a.uws // STOPボタン,INIファイル,画面表示
uws2exe.exe /SIE c:\temp\a.uws // STOPボタン,INIファイル,即実行
uws2exe.exe c:\temp\a.uws c:\temp\a.ico // アイコンの変更、デフォルトのオプションバージョンは0.0.0.0〜999.999.999.999まで指定できます。
バージョンはメジャーバージョン.マイナーバージョン.ビルドバージョン.リビジョンのように表します。
| バージョン | 意味 |
|---|---|
| メジャーバージョン | 根本から変更したとき |
| マイナーバージョン | 大幅な仕様変更・機能を加えたとき |
| ビルドバージョン | 小さな仕様変更・機能を加えたとき |
| リビジョン | バグの修正等 |
.は区切り文字であり小数を表しているわけではありません。そのため1.0.0.9にバグ修正を加えた場合は1.0.1.0ではなく、1.0.0.10となります。
上位の数字が加えられた場合、下位の数字は0に戻します。
最初は1.0.0.0を指定します。
UWSC Free版でEXEファイルを作成する方法
IExpress(C:\Windows\System32\iexpress.exe)を使うことで、EXEファイルを作成することが可能です。
ファイル名を指定して実行やコマンドプロンプトからiexpress.exeを入力し、IExpress Wizardを起動します。
Create new SelfExtraction Directive file.を選択し次へ。

Package purposeと表示されるのでExtract files and run an installation commandを選択し次へ。

Package titleと表示されるので、タイトルを入力し次へ。

Confirmation promptと表示されるので、No prompt.を選択し次へ。

License agreementと表示されるので、Do not display a license.を選択し次へ。

Paclaged filesと表示されるので、Addをクリックし、まずUWSC.exeを追加し次にEXE化したいUWSファイルを選択します。UWSC.exeはC:\Program Files (x86)\UWSC\UWSC.exeにあります。追加が終わったら次へ。

Install Program to Launchと表示されるので、Install ProgramにUWSC.exe <UWSファイル名.uws>を入力します。Post Install Commandは<None>を選択し次へ。

Show windowと表示されるので、Default (recommended)を選択し次へ。

Finished messageと表示されるので、No message.を選択し次へ。

Package Name and Optionsと表示されるので、作成したEXEファイルの保存先を入力もしくはBrowseで指定。OptionsのStore files using Long File Name inside Packageにチェックを入れダイアログが表示されるのではいを選択し次へ。


Configure restartと表示されるので、No restartを選択し次へ。

これまでの設定内容を保存する場合はSave SelfExtraction Directive (SED) file:を選択し、保存先のパスを入力もしくはBrowseから指定。

Create packageと表示されるので次へ。

完了を選択し終了します。

Cross Reference(XRef・クロスリファレンス)
UWSC Debuggerの[Option]->[Cross Reference]から起動。保存されていないファイルの場合は実行できません。ファイルを保存してから実行します。
変数や関数が使われている行番号を一覧で出力します。宣言・定義はしているのに利用されていない変数や関数は赤字で表示されます。
- 読み込みファイル
- Cross Referenceに読み込まれているファイルのパス
- MODULE定義
- モジュールが定義されている行。モジュール名のみで内部に定義された関数名は表示されません。
- ユーザー関数
- ユーザー関数・モジュールが定義・呼び出されている行。モジュール内で定義された関数はモジュール名.関数名のように表示されます。
- CONST変数
- CONSTで定数が宣言されている行。
- PROTECTED変数(MODULE内定義)
- モジュール内で宣言された変数。
- LOCAL変数
- ローカル変数が宣言されている行。先頭にargがついている変数は自作関数内で値を受け取り利用するために宣言された変数(仮引数)。値を受け取った行番号はなぜか実際の値よりも-1されている。












