Selenium オブジェクトでブラウザ操作を行うためのWebDriverのダウンロードを行います。
WebDriver.Start メソッド (Selenium)でブラウザを起動する直前に記述することで、ブラウザのバージョンに合ったドライバーをダウンロードします。
直近にダウンロードしたブラウザのバージョンをINIファイルに記録しておくことにより、現在のブラウザのバージョンと同じ場合はダウンロード処理を行いません。
バージョンが同じでもドライバーの再ダウンロードを行いたい場合はforceにTrueを指定します。
- 構文
- WebDriverDownload.Chrome( bit64, force )
WebDriverDownload.Firefox( force )
WebDriverDownload.MsEdge( force )
- 引数
- bit64 必須
- Chromeブラウザが64bitの場合はTrue、32bitの場合はFalseを指定。省略した場合、インストール先のフォルダパスから判断。
- force 省略可
- 現在インストールされているドライバーとバージョンが一致しても強制的にインストール処理を行う場合、Trueを指定
- 戻り値
プログラム
//////////////////////////////////////////////////
// 【引数】
// bit64 : Chromeブラウザが64bitの場合はTrue、32bitの場合はFalseを指定。省略した場合、インストール先のフォルダパスから判断。
// force : 現在インストールされているドライバーとバージョンが一致しても強制的にインストール処理を行う場合、Trueを指定
// 【戻り値】
//
//////////////////////////////////////////////////
MODULE WebDriverDownload
DIM WshShell = CREATEOLEOBJ("WScript.Shell")
DIM folderspec = WshShell.ExpandEnvironmentStrings("%LOCALAPPDATA%\SeleniumBasic\")
PROCEDURE Chrome(bit64, force = FALSE)
DIM browserVersion = ChromeBrowserVersion()
IF browserVersion = READINI("Chrome", "version", folderspec + "WebDriverVersion.ini") AND !force THEN EXIT
DIM bit = IIF(bit64, "64", "32")
WRITEINI("Chrome", "bit", bit, folderspec + "WebDriverVersion.ini")
DIM driverVersion = ChromeDriverVersion(browserVersion)
DIM driverURL = ChromeDriverURL(driverVersion, bit)
WRITEINI("Chrome", "DriverURL", driverURL, folderspec + "WebDriverVersion.ini")
InstallChromeDriver(driverURL, bit)
WRITEINI("Chrome", "version", browserVersion, folderspec + "WebDriverVersion.ini")
FEND
FUNCTION ChromeBrowserVersion()
TRY
DIM path = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe\Path")
EXCEPT
PRINT "Google Chromeがインストールされていません"
EXIT
ENDTRY
RESULT = TRIM(DOSCMD("DIR /B /O-N <#DBL>" + path + "<#DBL> | FINDSTR <#DBL>^[0-9].*¥>"))
FEND
FUNCTION ChromeDriverVersion(version)
DIM major = SPLIT(version, ".")[0]
IFB major >= 115 THEN
DIM url = "https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_" + major
ELSE
url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_" + major
ENDIF
WITH CREATEOLEOBJ("Msxml2.XMLHTTP")
.Open("GET", url, FALSE)
.Send()
RESULT = .ResponseText
ENDWITH
FEND
FUNCTION ChromeDriverURL(browserVersion, bit)
DIM driverVersion = ChromeDriverVersion(browserVersion)
DIM major = SPLIT(browserVersion, ".")[0]
IFB versionCompare(driverVersion, "121.0.6167.184", ">=") THEN
RESULT = "https://storage.googleapis.com/chrome-for-testing-public/" + driverVersion + "/win" + bit + "/chromedriver-win" + bit + ".zip"
ELSEIF major >= 115 THEN
RESULT = "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/" + driverVersion + "/win" + bit + "/chromedriver-win" + bit + ".zip"
ELSE
RESULT = "https://chromedriver.storage.googleapis.com/" + driverVersion + "/chromedriver_win32.zip"
ENDIF
FEND
PROCEDURE InstallChromeDriver(driverURL, bit)
DIM filename = "chromedriver.zip"
IF Download(driverURL, folderspec, filename) THEN UnZip(folderspec + filename)
path = folderspec + "chromedriver-win" + bit + "\chromedriver.exe"
WITH CREATEOLEOBJ("Scripting.FileSystemObject")
.CopyFile(path, folderspec, TRUE)
.DeleteFolder(.GetParentFolderName(path))
ENDWITH
FEND
PROCEDURE Firefox(force = FALSE)
DIM driverVersion = FireFoxDriverVersion()
IF driverVersion = READINI("Firefox", "DriverVersion", folderspec + "WebDriverVersion.ini") AND !force THEN EXIT
DIM driverURL = FirefoxDriverURL(driverVersion)
WRITEINI("Firefox", "DriverURL", driverURL, folderspec + "WebDriverVersion.ini")
InstallFirefoxDriver(driverURL)
WRITEINI("Firefox", "DriverVersion", driverVersion, folderspec + "WebDriverVersion.ini")
FEND
FUNCTION FireFoxDriverVersion()
DIM versionURL = "https://api.github.com/repos/mozilla/geckodriver/tags"
WITH CREATEOLEOBJ("Msxml2.XMLHTTP")
.Open("GET", versionURL, FALSE)
.Send()
DIM json = .ResponseText
ENDWITH
DIM obj = JSON.Parse(json)
RESULT = obj.Item(0).name
FEND
FUNCTION FirefoxDriverURL(driverVersion)
TRY
path = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe\")
DIM bit = IIF(POS("Program Files (x86)", path), 32, 64)
EXCEPT
PRINT "Firefoxがインストールされていません"
EXIT
ENDTRY
RESULT = "https://github.com/mozilla/geckodriver/releases/download/" + driverVersion + "/geckodriver-" + driverVersion + "-win" + bit + ".zip"
FEND
PROCEDURE InstallFirefoxDriver(driverURL)
DIM filename = "geckodriver.zip"
IF Download(driverURL, folderspec , filename, TRUE) THEN UnZip(folderspec + filename)
FEND
PROCEDURE MsEdge(force = FALSE)
DIM browserVersion = MsEdgeBrowserVersion()
IF browserVersion = READINI("MsEdge", "version", folderspec + "WebDriverVersion.ini") AND !force THEN EXIT
DIM driverVersion = MsEdgeDriverVersion(browserVersion)
DIM driverURL = MsEdgeDriverURL(driverVersion)
WRITEINI("MsEdge", "DriverURL", driverURL, folderspec + "WebDriverVersion.ini")
InstallMsEdgeDriver(driverVersion, driverURL)
WRITEINI("MsEdge", "version", browserVersion, folderspec + "WebDriverVersion.ini")
FEND
FUNCTION MsEdgeBrowserVersion()
TRY
path = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\msedge.exe\")
EXCEPT
PRINT "Microsoft Edgeがインストールされていません"
EXIT
ENDTRY
RESULT = TRIM(POWERSHELL("(get-item (<#DBL>" + path + "<#DBL>)).VersionInfo.FileVersion"))
FEND
FUNCTION MsEdgeDriverVersion(browserVersion)
DIM major = TOKEN(".", browserVersion)
DIM Request = Request("https://msedgewebdriverstorage.blob.core.windows.net/edgewebdriver/LATEST_RELEASE_" + major + "_WINDOWS")
RESULT = TRIM(Request.responseText)
FEND
FUNCTION MsEdgeDriverURL(driverVersion)
RESULT = "https://msedgewebdriverstorage.blob.core.windows.net/edgewebdriver/" + driverVersion + "/edgedriver_win" + IIF(KINDOFOS(TRUE), "64", "32") + ".zip"
FEND
PROCEDURE InstallMsEdgeDriver(driverVersion, driverURL)
DIM filename = "msedgedriver." + driverVersion + ".zip"
IF Download(driverURL, folderspec, filename) THEN UnZip(folderspec + filename)
FEND
ENDMODULE
//////////////////////////////////////////////////
// ダウンロード
// url:URL、dir:ディレクトリ名、filename:ファイル名、isServerXMLHTTP:
//////////////////////////////////////////////////
FUNCTION Download(url, dir, filename, isServerXMLHTTP = FALSE)
CONST adSaveCreateOverWrite = 2
WITH CREATEOLEOBJ("ADODB.Stream")
.Open()
.Type = 1
IF isServerXMLHTTP THEN
obj = CREATEOLEOBJ("Msxml2.ServerXMLHTTP")
ELSE
obj = CREATEOLEOBJ("Msxml2.XMLHTTP")
ENDIF
obj.Open("GET", url, FALSE)
obj.Send()
.Write(obj.responseBody)
.SaveToFile(dir + filename, adSaveCreateOverWrite)
.Close()
ENDWITH
RESULT = FOPEN(dir + filename, F_EXISTS)
FEND
//////////////////////////////////////////////////
// 要求
// url:URL、isServerXMLHTTP:
//////////////////////////////////////////////////
FUNCTION Request(url, isServerXMLHTTP = FALSE)
IFB isServerXMLHTTP THEN
RESULT = CREATEOLEOBJ("Msxml2.ServerXMLHTTP")
ELSE
RESULT = CREATEOLEOBJ("Msxml2.XMLHTTP")
ENDIF
WITH RESULT
.Open("GET", url, FALSE)
.Send()
ENDWITH
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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// num : 数値
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION decimalDigits(num)
DIM str = fixed(num)
RESULT = IIF(POS(".", str), LENGTH(BETWEENSTR(str, ".")), 0)
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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// 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("Array.prototype.Item = function(i, value){if(value === undefined) return this[i]; this[i] = value;}")
CodeObject = .CodeObject
ENDWITH
FEND
FUNCTION Parse(text, reviver = NULL)
RESULT = CodeObject.JSON.parse(text, reviver)
FEND
FUNCTION Stringify(value, replacer = NULL, space = "")
RESULT = CodeObject.JSON.stringify(value, replacer, space)
IF space <> "" THEN RESULT = REPLACE(RESULT, CHR(10), "<#CR>")
FEND
ENDMODULE
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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// 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 : フォーマット
// 【戻り値】
// 数値を表示書式に基づいて変換した文字列
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// path
// destination
// 【戻り値】
//
//////////////////////////////////////////////////
PROCEDURE UnZip(path, destination = "")
DIM FSO = CREATEOLEOBJ("Scripting.FileSystemObject")
DIM folderspec = FSO.GetParentFolderName(path)
DIM filename = FSO.GetFileName(path)
IF destination = "" THEN destination = folderspec
POWERSHELL("Set-Location " + folderspec + "; Expand-Archive " + filename + " -DestinationPath " + destination + " -Force")
FEND
//////////////////////////////////////////////////
// 【引数】
// version1 : 1つ目のバージョン
// version2 : 2つ目のバージョン
// operator : <、<=、>、>=、=、<>のいずれかの演算子
// 【戻り値】
// 1つ目のバージョンが2つ目のバージョンより小さい場合-1、同じ場合0、2つ目のバージョンが小さい場合1を返します。演算子を指定したときは、演算子の関係を満たす場合True、満たさない場合はFalseを返します。
//////////////////////////////////////////////////
FUNCTION versionCompare(version1, version2, operator = EMPTY)
DIM array1 = SPLIT(version1, ".")
DIM array2 = SPLIT(version2, ".")
IFB LENGTH(array1) <> LENGTH(array2) THEN
RESULT = ERR_VALUE
EXIT
ENDIF
IFB operator = EMPTY THEN
FOR i = 0 TO UBound(array1)
IFB array1[i] < array2[i] THEN
RESULT = -1
EXIT
ELSEIF array1[i] > array2[i] THEN
RESULT = 1
EXIT
ENDIF
NEXT
RESULT = 0
ELSE
FOR i = 0 TO UBound(array1)
IFB array1[i] <> array2[i] THEN
RESULT = EVAL("array1[i] " + operator + " array2[i]")
EXIT
ENDIF
NEXT
IFB POS("=", operator) THEN
RESULT = TRUE
ELSE
RESULT = FALSE
ENDIF
ENDIF
FEND
解説
- 2行目
- WshShell オブジェクトを生成しWshShellに代入します。
DIM WshShell = CREATEOLEOBJ("WScript.Shell")
- 3行目
- SeleniumBasicがインストールされているパスをfolderspecに代入します。
DIM folderspec = WshShell.ExpandEnvironmentStrings("%LOCALAPPDATA%\SeleniumBasic\")
- 4,14行目
- Google Chromeドライバーのダウンロード処理をする関数。
PROCEDURE Chrome(bit64, force = FALSE) … FEND
- 5行目
- ChromeBrowserVersion関数でChromeブラウザのバージョンを取得しbrowserVersionに代入します。
DIM browserVersion = ChromeBrowserVersion()
- 6行目
- WebDriverVersion.iniのChromeセクション、versionキーの値とbroswerVersionの値を比較し、バージョンが違うもしくはforceがTrueの場合は以下に続く処理を続けます。バージョンが同じ、もしくはforceがFalseの場合は処理を中断します。
IF browserVersion = READINI("Chrome", "version", folderspec + "WebDriverVersion.ini") AND !force THEN EXIT
- 7行目
- bit64の値がTrueならば64、Falseならば32をbitに代入します。
DIM bit = IIF(bit64, "64", "32")
- 9行目
- ChromeDriverVersion関数を実行し、browserVersionの値からダウンロードするドライバーのバージョンを生成しdriverVersionに代入します。
DIM driverVersion = ChromeDriverVersion(browserVersion)
- 10行目
- ChromeDriverURL関数を実行し、driverVersionとbitの値からドライバーのURLを生成し、driverURLに代入します。
DIM driverURL = ChromeDriverURL(driverVersion, bit)
- 12行目
- InstallChromeDriver関数を実行し、driverURLとbitの値からChromeのWebDriverのインストール処理を実行します。
InstallChromeDriver(driverURL, bit)
- 15-23行目
- Chromeブラウザのバージョンを返す関数です。レジストリのHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe\PathというキーからChromeブラウザがインストールされているパスを取得しpathに代入します。このときエラーが発生した場合はChromeブラウザがインストールされていないと判断し処理を中断します。Chromeブラウザのパスからコマンドプロンプトを使いバージョンを取得します。
FUNCTION ChromeBrowserVersion() TRY DIM path = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe\Path") EXCEPT PRINT "Google Chromeがインストールされていません" EXIT ENDTRY RESULT = TRIM(DOSCMD("DIR /B /O-N <#DBL>" + path + "<#DBL> | FINDSTR <#DBL>^[0-9].*¥>")) FEND
- 24,36行目
- Chromeブラウザのバージョンから対応するWebDriverのバージョンを取得する関数です。
FUNCTION ChromeDriverVersion(version) … FEND
- 25行目
- バージョンからメジャーバージョンの部分を取得しmajorに代入します。
DIM major = SPLIT(version, ".")[0]
- 26-30行目
- メジャーバージョンが115以降ならばhttps://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_" + major、115より前ならhttps://chromedriver.storage.googleapis.com/LATEST_RELEASE_" + majorをurlに代入します。
IFB major >= 115 THEN DIM url = "https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_" + major ELSE url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_" + major ENDIF
- 31-35行目
- urlを開き、Webページのテキスト全体を戻り値として返します。
WITH CREATEOLEOBJ("Msxml2.XMLHTTP") .Open("GET", url, FALSE) .Send() RESULT = .ResponseText ENDWITH
- 37-47行目
- Chromeブラウザのバージョンとビット数からダウンロードするWebDriverのURLを取得します。
FUNCTION ChromeDriverURL(browserVersion, bit) DIM driverVersion = ChromeDriverVersion(browserVersion) DIM major = SPLIT(browserVersion, ".")[0] IFB versionCompare(driverVersion, "121.0.6167.184", ">=") THEN RESULT = "https://storage.googleapis.com/chrome-for-testing-public/" + driverVersion + "/win" + bit + "/chromedriver-win" + bit + ".zip" ELSEIF major >= 115 THEN RESULT = "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/" + driverVersion + "/win" + bit + "/chromedriver-win" + bit + ".zip" ELSE RESULT = "https://chromedriver.storage.googleapis.com/" + driverVersion + "/chromedriver_win32.zip" ENDIF FEND
- 48,56行目
- Chromeドライバーのインストール処理を行う関数です。
PROCEDURE InstallChromeDriver(driverURL, bit) … FEND
- 49行目
- ダウンロードするZIPファイルのファイル名をchromedriver.zipにします。
DIM filename = "chromedriver.zip"
- 50行目
- driverURLに指定したURLのファイルをダウンロードします。folderspecがダウンロード先のフォルダ名、filenameがファイル名です。ダウンロードに成功した場合、そのZIPファイルを解凍します。
IF Download(driverURL, folderspec, filename) THEN UnZip(folderspec + filename)
- 51行目
- 解凍したZIPファイルからchromedriver.exeのパスをpathに代入します。
path = folderspec + "chromedriver-win" + bit + "\chromedriver.exe"
- 52-55行目
- ZIPファイルからpathのファイルをfolderspecにコピーし、ZIPファイルを削除します。
WITH CREATEOLEOBJ("Scripting.FileSystemObject") .CopyFile(path, folderspec, TRUE) .DeleteFolder(.GetParentFolderName(path)) ENDWITH
WebDriverとは
WebDriverはWebページの操作を自動化するためのインターフェイスです。Seleniumというブラウザを自動操作するためのライブラリとセットで使うため、Selenium オブジェクトを参考に事前にインストールしておいてください。
Seleniumを利用して書かれたプログラムはWebDriverを経由してブラウザの操作を行うのですが、ブラウザやそのバージョンに対応するWebDriverを用意する必要があります。そのためブラウザのアップデートでバージョンが変わるたびにWebDriverもインストールし直さなければならないため手間がかかります。WebDriverDownload関数はそのWebDriverのダウンロード・インストールの処理を自動で行うためのプログラムです。
WebDriverのダウンロード
WebDriverをダウンロードする手順はブラウザごとに異なるためそれぞれ以下に示します。
Chrome
Chromeはブラウザのバージョンによってダウンロード先が異なります。
Ver.115以降(最新版)
Chrome for Testing availabilityを開いて一番上にある表のCannelの列のStable(安定版)、Beta(ベータ版)、Dev(デベロッパー版)、Canary(カナリア版)の中からStableをクリックします。
リンクを選択するとページ内でStableの表がある位置に移動するので、Binary列にあるchromedriverの中からChromeブラウザのビット数に合わせて32bitならwin32、64ビットならwin64のどちらかに記載しているURLをコピー&ペーストして開きZIPファイルをダウンロードします。
Ver.115以降(特定のバージョン)
Ver.115以降の特定のバージョンのWebDriverをダウンロードするにはhttps://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.jsonのJSONファイルからWebDriverがあるURLを探し出します。
以下はリンク先のJSONファイルの一部を整形したものです。versions配列にはバージョンごとのデータが格納されています。downloadsキー内のchrome配列がOSごとのデータで、Windowsで32bitの場合はplatformキーがwin32、64bitの場合はplatformキーがwin64のurlキーの値がWebDriverのダウンロード先のURLです。
このURLをブラウザのアドレスバーに貼り付けるなどして開き、ZIPファイルをダウンロードします。
{
"timestamp": "2024-03-27T08:10:26.912Z",
"versions": [
{
"version": "113.0.5672.0",
"revision": "1121455",
"downloads": {
"chrome": [
{
"platform": "linux64",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/linux64/chrome-linux64.zip"
},
{
"platform": "mac-arm64",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/mac-arm64/chrome-mac-arm64.zip"
},
{
"platform": "mac-x64",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/mac-x64/chrome-mac-x64.zip"
},
{
"platform": "win32",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/win32/chrome-win32.zip"
},
{
"platform": "win64",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.0/win64/chrome-win64.zip"
}
]
}
},
{
"version": "113.0.5672.35",
"revision": "1121455",
"downloads": {
"chrome": [
{
"platform": "linux64",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.35/linux64/chrome-linux64.zip"
},
{
"platform": "mac-arm64",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.35/mac-arm64/chrome-mac-arm64.zip"
},
{
"platform": "mac-x64",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.35/mac-x64/chrome-mac-x64.zip"
},
{
"platform": "win32",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.35/win32/chrome-win32.zip"
},
{
"platform": "win64",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.35/win64/chrome-win64.zip"
}
]
}
},
{
"version": "113.0.5672.63",
"revision": "1121455",
"downloads": {
"chrome": [
{
"platform": "linux64",
"url": "https://storage.googleapis.com/chrome-for-testing-public/113.0.5672.63/linux64/chrome-linux64.zip"
}
]
}
}
]
}
Ver.114以前
Downloads | ChromeDriver | Chrome for Developersを開き、Chromeブラウザと対応するバージョンのWebDriverを選択します。
ChromeブラウザのVer.70〜114のバージョンに対応しています。Ver.82はブラウザのリリース自体がキャンセルされたのでドライバーもありません。
ダウンロードするWebDriverのバージョンは、以下の<メジャーバージョン>にブラウザのメジャーバージョンを代入しリンクを開くことで確認できます。
https://chromedriver.storage.googleapis.com/LATEST_RELEASE_<メジャーバージョン>
ブラウザのバージョンが70.0.3538.110の場合、 メジャーバージョンは一つ目のピリオドまでの数字で70となり以下のようになります。
https://chromedriver.storage.googleapis.com/LATEST_RELEASE_70
このURLを開いてダウンロードするWebDriverのバージョンを取得します。例えば上記のURLの場合、70.0.3538.97というバージョンが取得されます。
https://chromedriver.storage.googleapis.com/index.htmlの項目の中からLATEST_RELEASE_<メジャーバージョン>のファイルを選択することでも確認できます。
次にWebDriverのバージョンからWebDriverをダウンロードするためのURLを生成します。
https://chromedriver.storage.googleapis.com/<ドライバーのバージョン>/chromedriver_win32.zip
WebDriverのバージョンが70.0.3538.97の場合、URLは以下のようになります。
https://chromedriver.storage.googleapis.com/70.0.3538.97/chromedriver_win32.zip
このURLを開くとブラウザのバージョンに対応するchromedriver.exeのZIPフォイルがダウンロードされます。
WebDriverのインストール
ダウンロードしたZIPファイル(chromedriver-win32.zip、chromedriver-win64.zip)を解凍しフォルダ内にあるchromedriver.exeをSeleniumをインストールしているフォルダ(%LOCALAPPDATA%\SeleniumBasic\)に移動することでChromeブラウザを起動できるようになります。
Chromeのインストール先のフォルダ
Ver.85より前からChromeをインストールしていた場合、64bitでも32bitと同じC:\Program Files (x86)\にインストールされています。
bit64の引数を省略すると正しく判定できない場合があるので、正しくドライバーがインストールできない場合はブール値を指定してください。
使い方
ChromeブラウザのWebDriverをダウンロード
ChromeブラウザとWebDriverのバージョンが一致しない場合、Chromeブラウザ(64ビット)のWebDriverをダウンロードします。バージョンが一致している場合ダウンロード処理は行いません。
WebDriverDownload.Chrome(TRUE)
ChromeブラウザとWebDriverのバージョンが一致しない場合、Chromeブラウザ(32ビット)のWebDriverをダウンロードします。バージョンが一致している場合ダウンロード処理は行いません。
WebDriverDownload.Chrome(FALSE)
FirefoxブラウザのWebDriverをダウンロード
FirefoxブラウザとWebDriverのバージョンが一致しない場合、FirefoxブラウザのWebDriverをダウンロードします。
WebDriverDownload.Firefox()
Microsoft EdgeブラウザのWebDriverをダウンロード
Microsoft EdgeブラウザとWebDriverのバージョンが一致しない場合、EdgeブラウザのWebDriverをダウンロードします。
WebDriverDownload.MsEdge()
プログラム実行例
未読メールの本文からURLを抽出
DIM Outlook = CREATEOLEOBJ("Outlook.Application")
DIM NameSpace = Outlook.GetNameSpace("MAPI")
DIM Folder = NameSpace.Folders("Android_新").Folders("受信トレイ")
DIM Items = Folder.Items.Restrict("[UnRead] = TRUE")
Items.Sort("受信日時", TRUE)
// クリックするURLを格納した配列(部分一致)
DIM urls[] = "://example.com"
DIM driver = CREATEOLEOBJ("Selenium.WebDriver")
WebDriverDownload.Chrome()
// ログイン情報を保存
CONST PROFILE_PATH = "C:\Users\" + BETWEENSTR(DOSCMD("SET"), "USERNAME=", "<#CR>") + "\AppData\Local\Google\Chrome\User Data\Default"
driver.AddArgument("user-data-dir=" + PROFILE_PATH)
driver.Start("chrome")
DIM count = Items.Count
FOR Index = count TO 1 STEP -1
WITH Items.Item(Index)
FUKIDASI(Index + "<#TAB>" + .SenderEmailAddress + "<#TAB>" + .ReceivedTime)
DIM Matches = reExecute(.Body, "https?://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?")
// メール本文のURLをループ
FOR Match IN Matches
// クリックするURLをチェック
FOR i = 0 TO UBound(urls)
IF POS(urls[i], Match.Value) = 0 THEN CONTINUE
driver.Get(Match.Value) // リンクを開く
NEXT
NEXT
SLEEP(1.000)
ENDWITH
NEXT
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// num : 数値
// 【戻り値】
//
//////////////////////////////////////////////////
FUNCTION decimalDigits(num)
DIM str = fixed(num)
RESULT = IIF(POS(".", str), LENGTH(BETWEENSTR(str, ".")), 0)
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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// 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("Array.prototype.Item = function(i, value){if(value === undefined) return this[i]; this[i] = value;}")
CodeObject = .CodeObject
ENDWITH
FEND
FUNCTION Parse(text, reviver = NULL)
RESULT = CodeObject.JSON.parse(text, reviver)
FEND
FUNCTION Stringify(value, replacer = NULL, space = "")
RESULT = CodeObject.JSON.stringify(value, replacer, space)
IF space <> "" THEN RESULT = REPLACE(RESULT, CHR(10), "<#CR>")
FEND
ENDMODULE
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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// 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 : フォーマット
// 【戻り値】
// 数値を表示書式に基づいて変換した文字列
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// 【引数】
// 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
//////////////////////////////////////////////////
// 【引数】
// path
// destination
// 【戻り値】
//
//////////////////////////////////////////////////
PROCEDURE UnZip(path, destination = "")
DIM FSO = CREATEOLEOBJ("Scripting.FileSystemObject")
DIM folderspec = FSO.GetParentFolderName(path)
DIM filename = FSO.GetFileName(path)
IF destination = "" THEN destination = folderspec
POWERSHELL("Set-Location " + folderspec + "; Expand-Archive " + filename + " -DestinationPath " + destination + " -Force")
FEND
//////////////////////////////////////////////////
// 【引数】
// version1 : 1つ目のバージョン
// version2 : 2つ目のバージョン
// operator : <、<=、>、>=、=、<>のいずれかの演算子
// 【戻り値】
// 1つ目のバージョンが2つ目のバージョンより小さい場合-1、同じ場合0、2つ目のバージョンが小さい場合1を返します。演算子を指定したときは、演算子の関係を満たす場合True、満たさない場合はFalseを返します。
//////////////////////////////////////////////////
FUNCTION versionCompare(version1, version2, operator = EMPTY)
DIM array1 = SPLIT(version1, ".")
DIM array2 = SPLIT(version2, ".")
IFB LENGTH(array1) <> LENGTH(array2) THEN
RESULT = ERR_VALUE
EXIT
ENDIF
IFB operator = EMPTY THEN
FOR i = 0 TO UBound(array1)
IFB array1[i] < array2[i] THEN
RESULT = -1
EXIT
ELSEIF array1[i] > array2[i] THEN
RESULT = 1
EXIT
ENDIF
NEXT
RESULT = 0
ELSE
FOR i = 0 TO UBound(array1)
IFB array1[i] <> array2[i] THEN
RESULT = EVAL("array1[i] " + operator + " array2[i]")
EXIT
ENDIF
NEXT
IFB POS("=", operator) THEN
RESULT = TRUE
ELSE
RESULT = FALSE
ENDIF
ENDIF
FEND
//////////////////////////////////////////////////
// 【引数】
// bit64 : Chromeブラウザが64bitの場合はTrue、32bitの場合はFalseを指定。省略した場合、インストール先のフォルダパスから判断。
// force : 現在インストールされているドライバーとバージョンが一致しても強制的にインストール処理を行う場合、Trueを指定
// 【戻り値】
//
//////////////////////////////////////////////////
MODULE WebDriverDownload
DIM WshShell = CREATEOLEOBJ("WScript.Shell")
DIM folderspec = WshShell.ExpandEnvironmentStrings("%LOCALAPPDATA%\SeleniumBasic\")
PROCEDURE Chrome(bit64, force = FALSE)
DIM browserVersion = ChromeBrowserVersion()
IF browserVersion = READINI("Chrome", "version", folderspec + "WebDriverVersion.ini") AND !force THEN EXIT
DIM bit = IIF(bit64, "64", "32")
WRITEINI("Chrome", "bit", bit, folderspec + "WebDriverVersion.ini")
DIM driverVersion = ChromeDriverVersion(browserVersion)
DIM driverURL = ChromeDriverURL(driverVersion, bit)
WRITEINI("Chrome", "DriverURL", driverURL, folderspec + "WebDriverVersion.ini")
InstallChromeDriver(driverURL, bit)
WRITEINI("Chrome", "version", browserVersion, folderspec + "WebDriverVersion.ini")
FEND
FUNCTION ChromeBrowserVersion()
TRY
DIM path = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe\Path")
EXCEPT
PRINT "Google Chromeがインストールされていません"
EXIT
ENDTRY
RESULT = TRIM(DOSCMD("DIR /B /O-N <#DBL>" + path + "<#DBL> | FINDSTR <#DBL>^[0-9].*¥>"))
FEND
FUNCTION ChromeDriverVersion(version)
DIM major = SPLIT(version, ".")[0]
IFB major >= 115 THEN
DIM url = "https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_" + major
ELSE
url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_" + major
ENDIF
WITH CREATEOLEOBJ("Msxml2.XMLHTTP")
.Open("GET", url, FALSE)
.Send()
RESULT = .ResponseText
ENDWITH
FEND
FUNCTION ChromeDriverURL(browserVersion, bit)
DIM driverVersion = ChromeDriverVersion(browserVersion)
DIM major = SPLIT(browserVersion, ".")[0]
IFB versionCompare(driverVersion, "121.0.6167.184", ">=") THEN
RESULT = "https://storage.googleapis.com/chrome-for-testing-public/" + driverVersion + "/win" + bit + "/chromedriver-win" + bit + ".zip"
ELSEIF major >= 115 THEN
RESULT = "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/" + driverVersion + "/win" + bit + "/chromedriver-win" + bit + ".zip"
ELSE
RESULT = "https://chromedriver.storage.googleapis.com/" + driverVersion + "/chromedriver_win32.zip"
ENDIF
FEND
PROCEDURE InstallChromeDriver(driverURL, bit)
DIM filename = "chromedriver.zip"
IF Download(driverURL, folderspec, filename) THEN UnZip(folderspec + filename)
path = folderspec + "chromedriver-win" + bit + "\chromedriver.exe"
WITH CREATEOLEOBJ("Scripting.FileSystemObject")
.CopyFile(path, folderspec, TRUE)
.DeleteFolder(.GetParentFolderName(path))
ENDWITH
FEND
PROCEDURE Firefox(force = FALSE)
DIM driverVersion = FireFoxDriverVersion()
IF driverVersion = READINI("Firefox", "DriverVersion", folderspec + "WebDriverVersion.ini") AND !force THEN EXIT
DIM driverURL = FirefoxDriverURL(driverVersion)
WRITEINI("Firefox", "DriverURL", driverURL, folderspec + "WebDriverVersion.ini")
InstallFirefoxDriver(driverURL)
WRITEINI("Firefox", "DriverVersion", driverVersion, folderspec + "WebDriverVersion.ini")
FEND
FUNCTION FireFoxDriverVersion()
DIM versionURL = "https://api.github.com/repos/mozilla/geckodriver/tags"
WITH CREATEOLEOBJ("Msxml2.XMLHTTP")
.Open("GET", versionURL, FALSE)
.Send()
DIM json = .ResponseText
ENDWITH
DIM obj = JSON.Parse(json)
RESULT = obj.Item(0).name
FEND
FUNCTION FirefoxDriverURL(driverVersion)
TRY
path = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe\")
DIM bit = IIF(POS("Program Files (x86)", path), 32, 64)
EXCEPT
PRINT "Firefoxがインストールされていません"
EXIT
ENDTRY
RESULT = "https://github.com/mozilla/geckodriver/releases/download/" + driverVersion + "/geckodriver-" + driverVersion + "-win" + bit + ".zip"
FEND
PROCEDURE InstallFirefoxDriver(driverURL)
DIM filename = "geckodriver.zip"
IF Download(driverURL, folderspec , filename, TRUE) THEN UnZip(folderspec + filename)
FEND
PROCEDURE MsEdge(force = FALSE)
DIM browserVersion = MsEdgeBrowserVersion()
IF browserVersion = READINI("MsEdge", "version", folderspec + "WebDriverVersion.ini") AND !force THEN EXIT
DIM driverVersion = MsEdgeDriverVersion(browserVersion)
DIM driverURL = MsEdgeDriverURL(driverVersion)
WRITEINI("MsEdge", "DriverURL", driverURL, folderspec + "WebDriverVersion.ini")
InstallMsEdgeDriver(driverVersion, driverURL)
WRITEINI("MsEdge", "version", browserVersion, folderspec + "WebDriverVersion.ini")
FEND
FUNCTION MsEdgeBrowserVersion()
TRY
path = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\msedge.exe\")
EXCEPT
PRINT "Microsoft Edgeがインストールされていません"
EXIT
ENDTRY
RESULT = TRIM(POWERSHELL("(get-item (<#DBL>" + path + "<#DBL>)).VersionInfo.FileVersion"))
FEND
FUNCTION MsEdgeDriverVersion(browserVersion)
DIM major = TOKEN(".", browserVersion)
DIM Request = Request("https://msedgewebdriverstorage.blob.core.windows.net/edgewebdriver/LATEST_RELEASE_" + major + "_WINDOWS")
RESULT = TRIM(Request.responseText)
FEND
FUNCTION MsEdgeDriverURL(driverVersion)
RESULT = "https://msedgewebdriverstorage.blob.core.windows.net/edgewebdriver/" + driverVersion + "/edgedriver_win" + IIF(KINDOFOS(TRUE), "64", "32") + ".zip"
FEND
PROCEDURE InstallMsEdgeDriver(driverVersion, driverURL)
DIM filename = "msedgedriver." + driverVersion + ".zip"
IF Download(driverURL, folderspec, filename) THEN UnZip(folderspec + filename)
FEND
ENDMODULE
//////////////////////////////////////////////////
// ダウンロード
// url:URL、dir:ディレクトリ名、filename:ファイル名、isServerXMLHTTP:
//////////////////////////////////////////////////
FUNCTION Download(url, dir, filename, isServerXMLHTTP = FALSE)
CONST adSaveCreateOverWrite = 2
WITH CREATEOLEOBJ("ADODB.Stream")
.Open()
.Type = 1
IF isServerXMLHTTP THEN
obj = CREATEOLEOBJ("Msxml2.ServerXMLHTTP")
ELSE
obj = CREATEOLEOBJ("Msxml2.XMLHTTP")
ENDIF
obj.Open("GET", url, FALSE)
obj.Send()
.Write(obj.responseBody)
.SaveToFile(dir + filename, adSaveCreateOverWrite)
.Close()
ENDWITH
RESULT = FOPEN(dir + filename, F_EXISTS)
FEND
//////////////////////////////////////////////////
// 要求
// url:URL、isServerXMLHTTP:
//////////////////////////////////////////////////
FUNCTION Request(url, isServerXMLHTTP = FALSE)
IFB isServerXMLHTTP THEN
RESULT = CREATEOLEOBJ("Msxml2.ServerXMLHTTP")
ELSE
RESULT = CREATEOLEOBJ("Msxml2.XMLHTTP")
ENDIF
WITH RESULT
.Open("GET", url, FALSE)
.Send()
ENDWITH
FEND
参考文献
- https://kzstock.blogspot.com/2020/06/chrome64-defaultfolder.html
- 「C:\Program Files」:2 - 無無無庵2
- Releases · mozilla/geckodriver · GitHub
- 各種Driverの取得方法について - hifive
- Downloads | ChromeDriver | Chrome for Developers
- Chromeバージョン115より最新のWebドライバー取得ができない - 誰でもカンタンにテスト自動化ができる時代 テスト自動化ツール T-DASH
- 古いバージョンのGoogle Chrome (Windows) | Uptodown