UNPKG

nadesiko3

Version:
1,819 lines (1,790 loc) 116 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import { NakoRuntimeError } from './nako_errors.mjs' import { NakoSystem } from './plugin_api.mjs' export default { 'meta': { type: 'const', value: { pluginName: 'plugin_system', // プラグインの名前 description: 'システム関連の命令を提供するプラグイン', // プラグインの説明 pluginVersion: '3.6.0', // プラグインのバージョン nakoRuntime: ['wnako', 'cnako', 'phpnako'], // 対象ランタイム nakoVersion: '3.6.0' // 要求なでしこバージョン } }, '初期化': { type: 'func', josi: [], pure: false, fn: function (sys: NakoSystem) { // システム変数の初期化 const system: any = sys sys.isDebug = false // システム変数にアクセスするための関数を定義 sys.__setSysVar = (name: string, value: any): void => system.__v0.set(name, value) sys.__getSysVar = (name: string, defaultValue: any = undefined): any => { const v = system.__v0.get(name) if (v === undefined) { return defaultValue } return v } sys.__setSore = (v: any): any => { (sys as any).__vars.set('それ', v); return v } sys.__getSore = (): any => (sys as any).__vars.get('それ') sys.tags = {} // タグ - プラグイン側で自由に使えるオブジェクト // 言語バージョンを設定 sys.__setSysVar('ナデシコバージョン', sys.version) sys.__setSysVar('ナデシコ言語バージョン', sys.coreVersion) if (!system.__namespaceList) { system.__namespaceList = [] } // なでしこの関数や変数を探して返す sys.__findVar = function (nameStr: any, def: any): any { if (typeof nameStr === 'function') { return nameStr } // ローカル変数を探す const localVar = system.__locals.get(nameStr) if (localVar) { return localVar } // 名前空間が指定されている場合 if (nameStr.indexOf('__') >= 0) { for (let i = 2; i >= 0; i--) { const varScope = system.__varslist[i] const scopeValue = varScope.get(nameStr) if (scopeValue) { return scopeValue } } return def } // 名前空間を参照して関数・変数名を解決する const modList = system.__modList ? system.__modList : [system.__modName] for (const modName of modList) { const gname = modName + '__' + nameStr for (let i = 2; i >= 0; i--) { const scope = system.__varslist[i] const scopeValue = scope.get(gname) if (scopeValue) { return scopeValue } } } return def } // 文字列から関数を探す sys.__findFunc = function (nameStr: any, parentFunc: string): any { const f = sys.__findVar(nameStr) if (typeof f === 'function') { return f } throw new Error(`『${parentFunc}』に実行できない関数が指定されました。`) } // システム関数を実行 sys.__exec = function (func: string, params: any[]): any { // システム命令を優先 const f0 = sys.__getSysVar(func) if (f0) { return f0.apply(this, params) } // グローバル・ローカルを探す const f = sys.__findVar(func) if (!f) { throw new Error('システム関数でエイリアスの指定ミス:' + func) } return f.apply(this, params) } // タイマーに関する処理(タイマーは「!クリア」で全部停止する) sys.__timeout = [] sys.__interval = [] // 日付処理などに使う const z2 = sys.__zero2 = (s: string|number): string => { s = '00' + s return s.substring(s.length - 2) } sys.__zero = (s: string, keta: number): string => { let zeroS = '' for (let i = 0; i < keta; i++) { zeroS += '0' } s = zeroS + s return s.substring(s.length - keta) } sys.__formatDate = (t: Date): string => { return t.getFullYear() + '/' + z2(t.getMonth() + 1) + '/' + z2(t.getDate()) } sys.__formatTime = (t: Date): string => { return z2(t.getHours()) + ':' + z2(t.getSeconds()) + ':' + z2(t.getMinutes()) } sys.__formatDateTime = (t: Date, fmt: string): string => { const dateStr = t.getFullYear() + '/' + z2(t.getMonth() + 1) + '/' + z2(t.getDate()) const timeStr = z2(t.getHours()) + ':' + z2(t.getMinutes()) + ':' + z2(t.getSeconds()) if (fmt.match(/^\d+\/\d+\/\d+\s+\d+:\d+:\d+$/)) { return dateStr + ' ' + timeStr } if (fmt.match(/^\d+\/\d+\/\d+$/)) { return dateStr } if (fmt.match(/^\d+:\d+:\d+$/)) { return timeStr } return dateStr + ' ' + timeStr } sys.__str2date = (s: string): Date => { // trim s = ('' + s).replace(/(^\s+|\s+$)/, '') // is unix time if (s.match(/^(\d+|\d+\.\d+)$/)) { return new Date(parseFloat(s) * 1000) } // is time ? if (s.match(/^\d+:\d+(:\d+)?$/)) { const t = new Date() const a = (s + ':0').split(':') return new Date( t.getFullYear(), t.getMonth(), t.getDate(), parseInt(a[0]), parseInt(a[1]), parseInt(a[2])) } // replace splitter to '/' s = s.replace(/[\s:\-T]/g, '/') s += '/0/0/0' // 日付だけのときのために時間分を足す const a = s.split('/') return new Date(parseInt(a[0]), parseInt(a[1]) - 1, parseInt(a[2]), parseInt(a[3]), parseInt(a[4]), parseInt(a[5])) } // 『継続表示』のための一時変数(『表示』実行で初期化) sys.__printPool = '' // 暗黙の型変換で足し算を行うときに使用。bigint はそのまま、その他は number に自動変換 sys.__parseFloatOrBigint = (v: any): number | bigint => { return (typeof v) === 'bigint' ? v : parseFloat(v) } // undefinedチェック system.chk = (value:any, constId: number): any => { if (typeof value === 'undefined') { const cp = system.constPools[constId] const [msgNo, msgArgs, fileNo, lineNo] = cp let msg = system.constPoolsTemplate[msgNo] for (const i in msgArgs) { const arg = system.constPoolsTemplate[msgArgs[i]] msg = msg.split(`$${i}`).join(arg) } const fileStr = system.constPoolsTemplate[fileNo] sys.logger.warn(msg, { file: fileStr, line: lineNo }) } return value } // eval function #1733 sys.__evalSafe = (src: string) => { // evalのスコープを変えるためのテクニック // https://esbuild.github.io/content-types/#direct-eval const _eval = eval try { return _eval(src) } catch (e) { console.warn('[eval]', e) return null } } // eval function #1733 - 互換性を優先するため、direct evalを使うことに // eslint-disable-next-line @typescript-eslint/no-unused-vars sys.__evalJS = (src: string, sys?: NakoSystem) => { try { return eval(src) } catch (e) { console.warn('[eval]', e) return null } } // Propアクセス支援 // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type sys.__registPropAccessor = (f: Function, getProp: (prop: string|string[], sys: NakoSystem) => any, setProp: (prop: string|string[], value: object, sys: NakoSystem) => any) => { system.__propAccessor.push( { target: f, getProp, setProp } ) } sys.__checkPropAccessor = (mode: 'get'|'set', obj: any):void => { if ((mode === 'get' && obj.__getProp === undefined) || (mode === 'set' && obj.__setProp === undefined)) { for (let i = 0; i < system.__propAccessor.length; i++) { const accs = system.__propAccessor[i] if (accs.target[Symbol.hasInstance](obj)) { if (accs.getProp) { obj.__getProp = accs.getProp } else { obj.__getProp = null } if (accs.setProp) { obj.__setProp = accs.setProp } else { obj.__setProp = null } return } } obj.__getProp = obj.__setProp = null } } // 「??」ハテナ関数の設定 sys.__hatena = sys.__getSysVar('デバッグ表示') } }, '!クリア': { type: 'func', josi: [], fn: function (sys: NakoSystem) { if (sys.__exec) { sys.__exec('全タイマー停止', [sys]) } sys.__setSysVar('表示ログ', '') } }, // @システム定数 'ナデシコバージョン': { type: 'const', value: '?' }, // @なでしこばーじょん 'ナデシコ言語バージョン': { type: 'const', value: '?' }, // @なでしこげんごばーじょん 'ナデシコエンジン': { type: 'const', value: 'nadesi.com/v3' }, // @なでしこえんじん 'ナデシコ種類': { type: 'const', value: '?' }, // @なでしこしゅるい 'はい': { type: 'const', value: 1 }, // @はい 'いいえ': { type: 'const', value: 0 }, // @いいえ '真': { type: 'const', value: 1 }, // @しん '偽': { type: 'const', value: 0 }, // @ぎ '永遠': { type: 'const', value: 1 }, // @えいえん 'オン': { type: 'const', value: 1 }, // @おん 'オフ': { type: 'const', value: 0 }, // @おふ '改行': { type: 'const', value: '\n' }, // @かいぎょう 'タブ': { type: 'const', value: '\t' }, // @たぶ 'カッコ': { type: 'const', value: '「' }, // @かっこ 'カッコ閉': { type: 'const', value: '」' }, // @かっことじ '波カッコ': { type: 'const', value: '{' }, // @なみかっこ '波カッコ閉': { type: 'const', value: '}' }, // @なみかっことじ 'OK': { type: 'const', value: true }, // @OK 'NG': { type: 'const', value: false }, // @NG 'キャンセル': { type: 'const', value: 0 }, // @きゃんせる 'TRUE': { type: 'const', value: true }, // @TRUE 'FALSE': { type: 'const', value: false }, // @FALSE 'true': { type: 'const', value: true }, // @true 'false': { type: 'const', value: false }, // @false 'PI': { type: 'const', value: Math.PI }, // @PI '空': { type: 'const', value: '' }, // @から 'NULL': { type: 'const', value: null }, // @NULL 'undefined': { type: 'const', value: undefined }, // @undefined '未定義': { type: 'const', value: undefined }, // @みていぎ 'エラーメッセージ': { type: 'const', value: '' }, // @えらーめっせーじ '対象': { type: 'const', value: '' }, // @たいしょう '対象キー': { type: 'const', value: '' }, // @たいしょうきー '回数': { type: 'const', value: '' }, // @かいすう 'CR': { type: 'const', value: '\r' }, // @CR 'LF': { type: 'const', value: '\n' }, // @LF '非数': { type: 'const', value: NaN }, // @ひすう '無限大': { type: 'const', value: Infinity }, // @むげんだい '戻値無': { type: 'const', value: 0 }, // @もどりちなし '戻値有': { type: 'const', value: 1 }, // @もどりちあり '空配列': { // @空の配列を返す。『[]』と同義。 // @からはいれつ type: 'func', josi: [], pure: true, fn: function (): any { return [] } }, '空辞書': { // @空の辞書型を返す。『{}』と同義。 // @からじしょ type: 'func', josi: [], pure: true, fn: function (): any { return {} } }, '空ハッシュ': { // @空のハッシュを返す(v3.2以降非推奨) // @からはっしゅ type: 'func', josi: [], pure: true, fn: function (): any { return {} } }, '空オブジェクト': { // @空のオブジェクトを返す(v3.2以降非推奨) // @からおぶじぇくと type: 'func', josi: [], pure: false, fn: function (sys: NakoSystem): any { return sys.__exec('空ハッシュ', [sys]) } }, // @標準出力 '表示': { // @Sを表示 // @ひょうじ type: 'func', josi: [['を', 'と']], pure: true, fn: function (s: string, sys: any) { // 継続表示の一時プールを出力 s = sys.__printPool + s sys.__printPool = '' // sys.__setSysVar('表示ログ', sys.__getSysVar('表示ログ') + s + '\n') sys.logger.send('stdout', s + '') }, return_none: true }, '継続表示': { // @Sを改行なしで表示(ただし「表示」命令を使うことで画面出力される) // @けいぞくひょうじ type: 'func', josi: [['を', 'と']], pure: true, fn: function (s: string, sys: any) { sys.__printPool += s }, return_none: true }, '連続表示': { // @引数に指定した引数を全て表示する // @れんぞく表示 type: 'func', josi: [['と', 'を']], isVariableJosi: true, pure: true, fn: function (...a: any) { const sys = a.pop() const v = a.join('') sys.__exec('表示', [v, sys]) }, return_none: true }, '連続無改行表示': { // @引数に指定した引数を全て表示する(改行しない) // @れんぞくむかいぎょうひょうじ type: 'func', josi: [['と', 'を']], isVariableJosi: true, pure: true, fn: function (...a: any) { const sys = a.pop() const v = a.join('') sys.__exec('継続表示', [v, sys]) }, return_none: true }, '表示ログ': { type: 'const', value: '' }, // @ひょうじろぐ '表示ログクリア': { // @表示ログを空にする // @ひょうじろぐくりあ type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem) { sys.__setSysVar('表示ログ', '') }, return_none: true }, '言': { // @Sを表示 // @いう type: 'func', josi: [['を', 'と']], pure: true, fn: function (s: string, sys: any) { sys.logger.send('stdout', s + '') }, return_none: true }, 'コンソール表示': { // @Sをコンソール表示する(console.log) // @こんそーるひょうじ type: 'func', josi: [['を', 'と']], pure: true, fn: function (s: string) { console.log(s) }, return_none: true }, // @四則演算 '足': { // @AとBを足す // @たす type: 'func', josi: [['に', 'と'], ['を']], isVariableJosi: false, pure: true, fn: function (a: any, b: any) { return a + b } }, '引': { // @AからBを引く // @ひく type: 'func', josi: [['から'], ['を']], pure: true, fn: function (a: any, b: any) { return a - b } }, '掛': { // @AにBを掛ける // @かける type: 'func', josi: [['に', 'と'], ['を']], pure: true, fn: function (a: any, b: any) { // 数値の掛け算 if (typeof a === 'number') { return a * b } // 文字列の掛け算(文字列の繰り返し) if (typeof a === 'string') { let s = '' for (let i = 0; i < parseInt(b); i++) { s += a } return s } // 配列の繰り返し if (a instanceof Array) { const aa: any[] = [] for (let i = 0; i < parseInt(b); i++) { aa.push(...a) } return aa } return a * b } }, '倍': { // @AのB倍を求める // @ばい type: 'func', josi: [['の', 'を'], ['']], pure: true, fn: function (a: any, b: any) { return a * b } }, '割': { // @AをBで割る // @わる type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a: any, b: any) { return a / b } }, '割余': { // @AをBで割った余りを求める // @わったあまり type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a: any, b: any) { return a % b } }, '偶数': { // @Aが偶数なら真を返す // @ぐうすう type: 'func', josi: [['が']], pure: true, fn: function (a: any) { return (parseInt(a) % 2 === 0) } }, '奇数': { // @Aが奇数なら真を返す // @きすう type: 'func', josi: [['が']], pure: true, fn: function (a: any) { return (parseInt(a) % 2 === 1) } }, '二乗': { // @Aを二乗する // @にじょう type: 'func', josi: [['の', 'を']], pure: true, fn: function (a: any) { return a * a } }, 'べき乗': { // @AのB乗を求める // @べきじょう type: 'func', josi: [['の'], ['の']], pure: true, fn: function (a: any, b: any) { return Math.pow(a, b) } }, '以上': { // @AがB以上か // @いじょう type: 'func', josi: [['が'], ['']], pure: true, fn: function (a: any, b: any) { return a >= b } }, '以下': { // @AがB以下か // @いか type: 'func', josi: [['が'], ['']], pure: true, fn: function (a: any, b: any) { return a <= b } }, '未満': { // @AがB未満か // @みまん type: 'func', josi: [['が'], ['']], pure: true, fn: function (a: any, b: any) { return a < b } }, '超': { // @AがB超か // @ちょう type: 'func', josi: [['が'], ['']], pure: true, fn: function (a: any, b: any) { return a > b } }, '等': { // @AがBと等しいか // @ひとしい type: 'func', josi: [['が'], ['と']], pure: true, fn: function (a: any, b: any) { return a === b } }, '等無': { // @AがBと等しくないか // @ひとしくない type: 'func', josi: [['が'], ['と']], pure: true, fn: function (a: any, b: any) { return a !== b } }, '一致': { // @AがBと一致するか(配列や辞書も比較可能) // @いっち type: 'func', josi: [['が'], ['と']], pure: true, fn: function (a: any, b: any) { // オブジェクトの場合、JSONに変換して比較 if (typeof (a) === 'object') { const jsonA = JSON.stringify(a) const jsonB = JSON.stringify(b) return jsonA === jsonB } return a === b } }, '不一致': { // @AがBと不一致か(配列や辞書も比較可能) // @ふいっち type: 'func', josi: [['が'], ['と']], pure: true, fn: function (a: any, b: any) { // オブジェクトの場合、JSONに変換して比較 if (typeof (a) === 'object') { const jsonA = JSON.stringify(a) const jsonB = JSON.stringify(b) return jsonA !== jsonB } return a !== b } }, '範囲内': { // @VがAからBの範囲内か // @はんいない type: 'func', josi: [['が'], ['から'], ['の', 'までの']], pure: true, fn: function (v: any, a: any, b: any) { return (a <= v) && (v <= b) } }, '範囲': { // @AからBの範囲を表現する範囲オブジェクトを返す // @はんい type: 'func', josi: [['から'], ['の', 'までの']], pure: true, fn: function (a: any, b: any) { return { '先頭': a, '末尾': b } } }, '連続加算': { // @A1+A2+A3...にBを足す // @れんぞくかさん type: 'func', josi: [['を'], ['に', 'と']], isVariableJosi: true, pure: true, fn: function (b: any, ...a: any) { a.pop() // 必ず末尾に sys があるので、末尾のシステム変数を除外 a.push(b) return a.reduce((p: any, c: any) => p + c) } }, 'MAX': { // @2個以上の数値のうち最大値を返す。// @MAX type: 'func', josi: [['の'], ['と']], isVariableJosi: true, pure: true, fn: function (b: number, ...a: any): number { const sys = a.pop() return sys.__exec('最大値', [b, ...a, sys]) } }, '最大値': { // @2個以上の数値のうち最大値を返す。// @さいだいち type: 'func', josi: [['の'], ['と']], isVariableJosi: true, pure: true, fn: function (b: number, ...a: any): number { a.pop() // 必ず末尾に sys があるので、末尾のシステム変数を除外 a.push(b) return a.reduce((p: number, c: number) => Math.max(p, c)) } }, 'MIN': { // @2個以上の数値のうち最小値を返す。// @MIN type: 'func', josi: [['の'], ['と']], isVariableJosi: true, pure: true, fn: function (b: number, ...a: any): number { const sys = a.pop() return sys.__exec('最小値', [b, ...a, sys]) } }, '最小値': { // @2個以上の数値のうち最小値を返す。// @さいしょうち type: 'func', josi: [['の'], ['と']], isVariableJosi: true, pure: true, fn: function (b: number, ...a: any): number { a.pop() // 必ず末尾に sys があるので、末尾のシステム変数を除外 a.push(b) return a.reduce((p: number, c: number) => Math.min(p, c)) } }, 'CLAMP': { // @数値を下限から上限の範囲内に収めた値を返す。// @CLAMP type: 'func', josi: [['の', 'を'], ['から'], ['までの', 'で']], pure: true, fn: function (x: number, a: number, b: number): number { return Math.min(Math.max(x, a), b) } }, // @敬語 'ください': { // @敬語対応のため // @ください type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem) { if (!sys.__reisetu) { sys.__reisetu = 0 } sys.__reisetu++ }, return_none: true }, 'お願': { // @ソースコードを読む人を気持ちよくする // @おねがいします type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem) { if (!sys.__reisetu) { sys.__reisetu = 0 } sys.__reisetu++ }, return_none: true }, 'です': { // @ソースコードを読む人を気持ちよくする // @です type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem) { if (!sys.__reisetu) { sys.__reisetu = 0 } sys.__reisetu++ }, return_none: true }, '拝啓': { // @ソースコードを読む人を気持ちよくする // @はいけい type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem) { sys.__reisetu = 0 }, return_none: true }, '敬具': { // @ソースコードを読む人を気持ちよくする // @けいぐ type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem) { sys.__reisetu += 100 // bonus point }, return_none: true }, '礼節レベル取得': { // @(お遊び)敬語を何度使ったか返す // @おねがいします type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem) { if (!sys.__reisetu) { sys.__reisetu = 0 } return sys.__reisetu } }, // @特殊命令 'JS実行': { // @JavaScriptのコードSRCを実行する(変数sysでなでしこシステムを参照できる) // @JSじっこう type: 'func', josi: [['を', 'で']], pure: true, fn: function (src: string, sys: NakoSystem) { return sys.__evalJS(src, sys) // #1733 } }, 'JSオブジェクト取得': { // @なでしこで定義した関数や変数nameのJavaScriptオブジェクトを取得する // @JSおぶじぇくとしゅとく type: 'func', josi: [['の']], pure: false, fn: function (name: string, sys: any) { return sys.__findVar(name, null) } }, 'JS関数実行': { // @JavaScriptの関数NAMEを引数ARGS(配列)で実行する // @JSかんすうじっこう type: 'func', josi: [['を'], ['で']], fn: function (name: any, args: any, sys: NakoSystem) { // nameが文字列ならevalして関数を得る // eslint-disable-next-line no-eval if (typeof name === 'string') { name = sys.__evalJS(name, sys) } if (typeof name !== 'function') { throw new Error('JS関数取得で実行できません。') } // argsがArrayでなければArrayに変換する if (!(args instanceof Array)) { args = [args] } // 実行 // eslint-disable-next-line prefer-spread return name.apply(null, args) } }, 'ASYNC': { // @なでしこのユーザー関数定義でASYNC(非同期関数である)ことを宣言する // @ASYNC type: 'func', josi: [], asyncFn: true, pure: true, fn: async function () { // empty }, return_none: true }, 'AWAIT実行': { // @JavaScriptの非同期関数(Promise/async関数)のFを引数ARGSでawait実行する // @JSかんすうAWAIT type: 'func', josi: [['を'], ['で']], pure: true, asyncFn: true, fn: async function (f: any, args: any, sys: any) { // nameが文字列ならevalして関数を得る if (typeof f === 'string') { f = sys.__findFunc(f, 'AWAIT実行') } if (!(f instanceof Function)) { throw new Error('『AWAIT実行』の第一引数はなでしこ関数名かFunction型で指定してください。') } // 実行 return await f(...args) } }, 'JSメソッド実行': { // @JavaScriptのオブジェクトOBJのメソッドMを引数ARGS(配列)で実行する // @JSめそっどじっこう type: 'func', josi: [['の'], ['を'], ['で']], fn: function (obj: any, m: any, args: any, sys: NakoSystem) { // objが文字列ならevalして関数を得る // eslint-disable-next-line no-eval if (typeof obj === 'string') { obj = sys.__evalJS(obj, sys) } if (typeof obj !== 'object') { throw new Error('JSオブジェクトを取得できませんでした。') } // method を求める if (typeof m !== 'function') { m = obj[m] } // argsがArrayでなければArrayに変換する if (!(args instanceof Array)) { args = [args] } // 実行 return m.apply(obj, args) } }, 'ナデシコ': { // @なでしこのコードCODEを実行する // @なでしこする type: 'func', josi: [['を', 'で']], pure: false, fn: function (code: string, sys: any) { sys.__setSysVar('表示ログ', '') sys.__self.runEx(code, sys.__modName, { resetEnv: false, resetLog: true }) const outLog = sys.__getSysVar('表示ログ') + '' if (outLog) { sys.logger.trace(outLog) } return outLog } }, 'ナデシコ続': { // @なでしこのコードCODEを実行する // @なでしこつづける type: 'func', josi: [['を', 'で']], fn: function (code: string, sys: any) { sys.__self.runEx(code, sys.__modName, { resetEnv: false, resetAll: false }) const out = sys.__getSysVar('表示ログ') + '' if (out) { sys.logger.trace(out) } return out } }, '実行': { // @ 無名関数(あるいは、文字列で関数名を指定)Fを実行する(Fが関数でなければ無視する) // @じっこう type: 'func', josi: [['を', 'に', 'で']], pure: false, fn: function (f: any, sys: any) { // #938 の規則に従って処理 // 引数が関数なら実行 if (typeof f === 'function') { return f(sys) } // 文字列なら関数に変換できるか判定して実行 if (typeof f === 'string') { const tf = sys.__findFunc(f, '実行') if (typeof tf === 'function') { return tf(sys) } } // それ以外ならそのまま値を返す return f } }, '実行時間計測': { // @ 関数Fを実行して要した時間をミリ秒で返す // @じっこうじかんけいそく type: 'func', josi: [['の']], pure: false, fn: function (f: any, sys: any) { if (typeof f === 'string') { f = sys.__findFunc(f, '実行時間計測') } // if (performance && performance.now) { const t1 = performance.now() f(sys) const t2 = performance.now() return (t2 - t1) } else { const t1 = Date.now() f(sys) const t2 = Date.now() return (t2 - t1) } } }, '終': { // @終わる // @終わる type: 'func', josi: [], pure: true, fn: function (sys: NakoSystem) { // デバッグモードでなければ例外を投げることでプログラムを終了させる sys.__setSysVar('__forceClose', true) if (!sys.__getSysVar('__useDebug')) { throw new Error('__終わる__') } } }, // @型変換 '変数型確認': { // @変数Vの型を返す // @へんすうかたかくにん type: 'func', josi: [['の']], pure: true, fn: function (v: any) { return (typeof v) } }, 'TYPEOF': { // @変数Vの型を返す // @TYPEOF type: 'func', josi: [['の']], pure: true, fn: function (v: any) { return (typeof v) } }, '文字列変換': { // @値Vを文字列に変換 // @もじれつへんかん type: 'func', josi: [['を']], pure: true, fn: function (v: any): string { return String(v) } }, 'TOSTR': { // @値Vを文字列に変換 // @TOSTR type: 'func', josi: [['を']], pure: true, fn: function (v: any): string { return String(v) } }, '整数変換': { // @値Vを整数に変換 // @せいすうへんかん type: 'func', josi: [['を']], pure: true, fn: function (v: any): number { return parseInt(v) } }, 'TOINT': { // @値Vを整数に変換 // @TOINT type: 'func', josi: [['を']], pure: true, fn: function (v: any): number { return parseInt(v) } }, '実数変換': { // @値Vを実数に変換 // @じっすうへんかん type: 'func', josi: [['を']], pure: true, fn: function (v: any): number { return parseFloat(v) } }, 'TOFLOAT': { // @値Vを実数に変換 // @TOFLOAT type: 'func', josi: [['を']], pure: true, fn: function (v: any): number { return parseFloat(v) } }, 'INT': { // @値Vを整数に変換 // @INT type: 'func', josi: [['の']], pure: true, fn: function (v: any): number { return parseInt(v) } }, 'FLOAT': { // @値Vを実数に変換 // @FLOAT type: 'func', josi: [['の']], pure: true, fn: function (v: any): number { return parseFloat(v) } }, 'NAN判定': { // @値VがNaNかどうかを判定(命令『非数判定』を使う事を推奨) // @NANはんてい type: 'func', josi: [['を']], pure: true, fn: function (v: any): boolean { return isNaN(v) } }, '非数判定': { // @値Vが非数かどうかを判定(NAN判定より堅牢) // @ひすうはんてい type: 'func', josi: [['を']], pure: true, fn: function (v: any): boolean { // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN return Number.isNaN(v) } }, 'HEX': { // @値Vを16進数に変換 // @HEX type: 'func', josi: [['の']], pure: true, fn: function (a: any): string { return parseInt(a).toString(16) } }, '進数変換': { // @値VをN進数に変換 // @しんすうへんかん type: 'func', josi: [['を', 'の'], ['']], pure: true, fn: function (v: any, n: number): string { return parseInt(v).toString(n) } }, '二進': { // @値Vを2進数に変換 // @にしん type: 'func', josi: [['を', 'の', 'から']], pure: true, fn: function (v: any): string { return parseInt(v).toString(2) } }, '二進表示': { // @値Vを2進数に変換して表示 // @にしんひょうじ type: 'func', josi: [['を', 'の', 'から']], pure: true, fn: function (v: any, sys: any) { const s = parseInt(v).toString(2) sys.__exec('表示', [s, sys]) } }, 'RGB': { // @HTML用のカラーコードを返すRGB(R,G,B)で各値は0-255 // @RGB type: 'func', josi: [['と'], ['の'], ['で']], pure: true, fn: function (r: any, g: any, b: any): string { const z2 = (v: any): string => { const v2: string = '00' + (parseInt('' + v).toString(16)) return v2.substring(v2.length - 2, v2.length) } return '#' + z2(r) + z2(g) + z2(b) } }, // @論理演算 '論理OR': { // @(ビット演算で)AとBの論理和を返す(v1非互換)。 // @ろんりOR type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a: any, b: any) { return (a || b) } }, '論理AND': { // @(ビット演算で)AとBの論理積を返す(v1非互換)。日本語の「AかつB」に相当する // @ろんりAND type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a: any, b: any) { return (a && b) } }, '論理NOT': { // @値Vが0ならば1、それ以外ならば0を返す(v1非互換) // @ろんりNOT type: 'func', josi: [['の']], pure: true, fn: function (v: any): number { return (!v) ? 1 : 0 } }, // @ビット演算 'OR': { // @(ビット演算で)AとBの論理和を返す。 // @OR type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a: any, b: any) { return (a | b) } }, 'AND': { // @(ビット演算で)AとBの論理積を返す。日本語の「AかつB」に相当する // @AND type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a: any, b: any) { return (a & b) } }, 'XOR': { // @(ビット演算で)AとBの排他的論理和を返す。// @XOR type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a: any, b: any) { return (a ^ b) } }, 'NOT': { // @(ビット演算で)vの各ビットを反転して返す。// @NOT type: 'func', josi: [['の']], pure: true, fn: function (v: any) { return (~v) } }, 'SHIFT_L': { // @VをAビット左へシフトして返す // @SHIFT_L type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a: any, b: any) { return (a << b) } }, 'SHIFT_R': { // @VをAビット右へシフトして返す(符号を維持する) // @SHIFT_R type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a: any, b: any) { return (a >> b) } }, 'SHIFT_UR': { // @VをAビット右へシフトして返す(符号を維持しない、0で埋める) // @SHIFT_UR type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a: any, b: any) { return (a >>> b) } }, // @文字列処理 '文字数': { // @文字列Vの文字数を返す // @もじすう type: 'func', josi: [['の']], pure: true, fn: function (v: any) { if (!Array.from) { return String(v).length } return Array.from(v).length } }, '何文字目': { // @文字列SでAが何文字目にあるか調べて返す。見つからなければ0を返す。 // @なんもじめ type: 'func', josi: [['で', 'の'], ['が']], pure: true, fn: function (s: string, a: string): number { return String(s).indexOf(a) + 1 } }, 'CHR': { // @文字コードV(あるいは文字列配列)から文字を返す // @CHR type: 'func', josi: [['の']], pure: true, fn: function (v: number|number[]): string|string[] { if (typeof v === 'number') { if (!String.fromCodePoint) { return String.fromCharCode(v) } return String.fromCodePoint(v) } const res: string[] = [] for (const s of v) { if (!String.fromCodePoint) { res.push(String.fromCharCode(s)) } res.push(String.fromCodePoint(s)) } return res } }, 'ASC': { // @文字列V(あるいは文字列配列)の最初の文字の文字コードを返す // @ASC type: 'func', josi: [['の']], pure: true, fn: function (v: string|string[]): number|number[] { if (typeof v === 'string') { if (!String.prototype.codePointAt) { return String(v).charCodeAt(0) } return String(v).codePointAt(0) || 0 } const res: number[] = [] for (const s of v) { if (!String.prototype.codePointAt) { res.push(String(s).charCodeAt(0)) } res.push(String(s).codePointAt(0) || 0) } return res } }, '文字挿入': { // @文字列SのI文字目に文字列Aを挿入する // @もじそうにゅう type: 'func', josi: [['で', 'の'], ['に', 'へ'], ['を']], pure: true, fn: function (s: string, i: number, a: string): string { if (i <= 0) { i = 1 } const ss = String(s) const mae = ss.substring(0, i - 1) const usi = ss.substring(i - 1) return mae + a + usi } }, '文字検索': { // @文字列SでA文字目から文字列Bを検索。見つからなければ0を返す。(類似命令に『何文字目』がある)(v1非互換) // @もじけんさく type: 'func', josi: [['で', 'の'], ['から'], ['を']], pure: true, fn: function (s: string, a: number, b: string): number { let str = String(s) str = str.substring(a) const res: number = str.indexOf(b) if (res === -1) { return 0 } return res + 1 + a } }, '追加': { // @文字列または配列SにAを追加して返す(v1非互換) // @ついか type: 'func', josi: [['で', 'に', 'へ'], ['を']], pure: true, fn: function (s: any, a: any): any { if (s instanceof Array) { s.push(a) return s } return String(s) + String(a) } }, '一行追加': { // @文字列または配列SにAと改行を追加して返す(v1非互換) // @いちぎょうついか type: 'func', josi: [['で', 'に', 'へ'], ['を']], pure: true, fn: function (s: any, a: any): any { if (s instanceof Array) { s.push(a) return s } return String(s) + String(a) + '\n' } }, '文字列分解': { // @文字列Vを一文字ずつに分解して返す // @もじれつぶんかい type: 'func', josi: [['を', 'の', 'で']], pure: true, fn: function (v: any) { if (!Array.from) { return String(v).split('') } return Array.from(v) } }, 'リフレイン': { // @文字列VをCNT回繰り返す(v1非互換) // @りふれいん type: 'func', josi: [['を', 'の'], ['で']], pure: true, fn: function (v: any, cnt: number): string { let s = '' for (let i = 0; i < cnt; i++) { s += String(v) } return s } }, '出現回数': { // @文字列SにAが何回出現するか数える // @しゅつげんかいすう type: 'func', josi: [['で'], ['の']], pure: true, fn: function (s: string, a: string) { s = '' + s a = '' + a return s.split(a).length - 1 } }, 'MID': { // @文字列SのA文字目からCNT文字を抽出する // @MID type: 'func', josi: [['で', 'の'], ['から'], ['を']], pure: true, fn: function (s: any, a: any, cnt: number) { cnt = cnt || 1 return (String(s).substring(a - 1, a + cnt - 1)) } }, '文字抜出': { // @文字列SのA文字目からCNT文字を抽出する // @もじぬきだす type: 'func', josi: [['で', 'の'], ['から'], ['を', '']], pure: true, fn: function (s: any, a: any, cnt: number) { cnt = cnt || 1 return (String(s).substring(a - 1, a + cnt - 1)) } }, 'LEFT': { // @文字列Sの左端からCNT文字を抽出する // @LEFT type: 'func', josi: [['の', 'で'], ['だけ']], pure: true, fn: function (s: string, cnt: number): string { return (String(s).substring(0, cnt)) } }, '文字左部分': { // @文字列Sの左端からCNT文字を抽出する // @もじひだりぶぶん type: 'func', josi: [['の', 'で'], ['だけ', '']], pure: true, fn: function (s: string, cnt: number): string { return (String(s).substring(0, cnt)) } }, 'RIGHT': { // @文字列Sの右端からCNT文字を抽出する // @RIGHT type: 'func', josi: [['の', 'で'], ['だけ']], pure: true, fn: function (s: string, cnt: number): string { s = '' + s return (s.substring(s.length - cnt, s.length)) } }, '文字右部分': { // @文字列Sの右端からCNT文字を抽出する // @もじみぎぶぶん type: 'func', josi: [['の', 'で'], ['だけ', '']], pure: true, fn: function (s: string, cnt: number): string { s = '' + s return (s.substring(s.length - cnt, s.length)) } }, '区切': { // @文字列Sを区切り文字Aで区切って配列で返す // @くぎる type: 'func', josi: [['の', 'を'], ['で']], pure: true, fn: function (s: string, a: string) { return ('' + s).split('' + a) } }, '文字列分割': { // @文字列Sを区切り文字Aで分割して配列で返す // @もじれつぶんかつ type: 'func', josi: [['を'], ['で']], pure: true, fn: function (s: string, a: string) { s = '' + s a = '' + a const i = s.indexOf(a) if (i < 0) { return [s] } return [s.substring(0, i), s.substring(i + a.length)] } }, '切取': { // @文字列Sから文字列Aまでの部分を抽出する。切り取った残りは特殊変数『対象』に代入される。(v1非互換) // @きりとる type: 'func', josi: [['から', 'の'], ['まで', 'を']], pure: true, fn: function (s: string, a: string, sys: any) { s = String(s) const i = s.indexOf(a) if (i < 0) { sys.__setSysVar('対象', '') return s } sys.__setSysVar('対象', s.substring(i + a.length)) return s.substring(0, i) } }, '範囲切取': { // @文字列Sで文字列AからBまでの部分を抽出して返す。切り取った残りは特殊変数『対象』に代入される。(v1非互換) // @はんいきりとる type: 'func', josi: [['で', 'の'], ['から'], ['まで', 'を']], pure: true, fn: function (s: string, a: string, b: string, sys: any) { s = String(s) let mae = '' let usiro = '' const i = s.indexOf(a) if (i < 0) { sys.__setSysVar('対象', s) return '' } mae = s.substring(0, i) const subS = s.substring(i + a.length) const j = subS.indexOf(b) if (j < 0) { sys.__setSysVar('対象', mae) return subS } const result = subS.substring(0, j) usiro = subS.substring(j + b.length) sys.__setSysVar('対象', mae + usiro) return result } }, '文字削除': { // @文字列SのA文字目からB文字分を削除して返す // @もじさくじょ type: 'func', josi: [['の'], ['から'], ['だけ', 'を', '']], pure: true, fn: function (s: string, a: number, b: number): string { s = '' + s const mae = s.substring(0, a - 1) const usi = s.substring((a - 1 + b)) return mae + usi } }, // @置換・トリム '置換': { // @文字列Sのうち文字列AをBに全部置換して返す // @ちかん type: 'func', josi: [['の', 'で'], ['を', 'から'], ['に', 'へ']], pure: true, fn: function (s: string, a: string, b: string) { return String(s).split(a).join(b) } }, '単置換': { // @文字列Sのうち、最初に出現するAだけをBに置換して返す // @たんちかん type: 'func', josi: [['の', 'で'], ['を'], ['に', 'へ']], pure: true, fn: function (s: string, a: string, b: string) { // replaceは最初の一度だけ置換する return String(s).replace(a, b) } }, 'トリム': { // @文字列Sの前後にある空白を削除する // @とりむ type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { s = String(s).replace(/^\s+/, '').replace(/\s+$/, '') return s } }, '空白除去': { // @文字列Sの前後にある空白を削除する // @くうはくじょきょ type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { s = String(s).replace(/^\s+/, '').replace(/\s+$/, '') return s } }, '右トリム': { // @文字列Sの末尾にある空白を削除する // @みぎとりむ type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { s = String(s).replace(/\s+$/, '') return s } }, '末尾空白除去': { // @文字列Sの末尾にある空白を削除する // @まつびくうはくじょきょ type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { s = String(s).replace(/\s+$/, '') return s } }, // @文字変換 '大文字変換': { // @アルファベットの文字列Sを大文字に変換 // @おおもじへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { return String(s).toUpperCase() } }, '小文字変換': { // @アルファベットの文字列Sを小文字に変換 // @こもじへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { return String(s).toLowerCase() } }, '平仮名変換': { // @文字列Sのカタカナをひらがなに変換 // @ひらがなへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { const kanaToHira = (str: string) => { return String(str).replace(/[\u30a1-\u30f6]/g, function (m) { const chr = m.charCodeAt(0) - 0x60 return String.fromCharCode(chr) }) } return kanaToHira('' + s) } }, 'カタカナ変換': { // @文字列Sのひらがなをカタカナに変換 // @かたかなへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { const hiraToKana = (str: string) => { return String(str).replace(/[\u3041-\u3096]/g, function (m) { const chr = m.charCodeAt(0) + 0x60 return String.fromCharCode(chr) }) } return hiraToKana('' + s) } }, '英数全角変換': { // @文字列Sの半角英数文字を全角に変換 // @えいすうぜんかくへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { return String(s).replace(/[A-Za-z0-9]/g, function (v: any) { return String.fromCharCode(v.charCodeAt(0) + 0xFEE0) }) } }, '英数半角変換': { // @文字列Sの全角英数文字を半角に変換 // @えいすうはんかくへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { return String(s).replace(/[A-Za-z0-9]/g, function (v: any) { return String.fromCharCode(v.charCodeAt(0) - 0xFEE0) }) } }, '英数記号全角変換': { // @文字列Sの半角英数記号文字を全角に変換 // @えいすうきごうぜんかくへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { return String(s).replace(/[\x20-\x7F]/g, function (v: any) { return String.fromCharCode(v.charCodeAt(0) + 0xFEE0) }) } }, '英数記号半角変換': { // @文字列Sの記号文字を半角に変換 // @えいすうきごうはんかくへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string): string { return String(s).replace(/[\uFF00-\uFF5F]/g, function (v: any) { return String.fromCharCode(v.charCodeAt(0) - 0xFEE0) }) } }, 'カタカナ全角変換': { // @文字列Sの半角カタカナを全角に変換 // @かたかなぜんかくへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string, sys: any) { // 半角カタカナ const zen1 = sys.__getSysVar('全角カナ一覧') const han1 = sys.__getSysVar('半角カナ一覧') const zen2 = sys.__getSysVar('全角カナ濁音一覧') const han2 = sys.__getSysVar('半角カナ濁音一覧') let str = '' let i = 0 while (i < s.length) { // 濁点の変換 const c2 = s.substring(i, i + 2) const n2 = han2.indexOf(c2) if (n2 >= 0) { str += zen2.charAt(n2 / 2) i += 2 continue } // 濁点以外の変換 const c = s.charAt(i) const n = han1.indexOf(c) if (n >= 0) { str += zen1.charAt(n) i++ continue } str += c i++ } return str } }, 'カタカナ半角変換': { // @文字列Sの全角カタカナを半角に変換 // @かたかなはんかくへんかん type: 'func', josi: [['の', 'を']], pure: true, fn: function (s: string, sys: any) { // 半角カタカナ const zen1 = sys.__getSysVar('全角カナ一覧') const han1 = sys.__getSysVar('半角カナ一覧') const zen2 = sys.__getSysVar('全角カナ濁音一覧') const han2 = sys.__getSysVar('半角カナ濁音一覧') return s.split('').map((c) => { const i = zen1.indexOf(c) if (i >= 0) { return han1.charAt(i) } const j = zen2.indexOf(c) if (j >= 0) { return han2.substring(j * 2, j * 2 + 2) } return c }).join('') } }, '全角変換': { // @文字列Sの半角文字を全角に変換 // @ぜんかくへんかん type: 'func', josi: [['の', 'を']], pure: false, fn: function (s: string, sys: any) { let result = s result = sys.__exec('カタカナ全角変換', [result, sys]) result = sys.__exec('英数記号全角変換', [result, sys]) return result } }, '半角変換': { // @文字列Sの全角文字を半角に変換 // @はんかくへんかん type: 'func', josi: [['の', 'を']], pure: false, fn: function (s: string, sys: any) { let result = s result = sys.__exec('カタカナ半角変換', [result, sys]) result = sys.__exec('英数記号半角変換', [result, sys]) return result } }, '全角カナ一覧': { type: 'const', value: 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ、。ー「」' }, // @ぜんかくかないちらん '全角カナ濁音一覧': { type: 'const', value: 'ガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ' }, // @ぜんかくかなだくおんいちらん '半角カナ一覧': { type: 'const', value: 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ、。ー「」゙゚' }, // @はんかくかないちらん '半角カナ濁音一覧': { type: 'const', value: 'ガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ' }, // @はんかくかなだくおんいちらん // @JSON 'JSONエンコード': { // @オブジェクトVをJSON形式にエンコードして返す // @JSONえんこーど type: 'func', josi: [['を', 'の']], pure: true, fn: function (v: any) { return JSON.stringify(v) } }, 'JSONエンコード整形': { // @オブジェクトVをJSON形式にエンコードして整形して返す // @JSONえんこーどせいけい type: 'func', josi: [['を', 'の']], pure: true, fn: function (v: any) { return JSON.stringify(v, null, 2) } }, 'JSONデコード': { // @JSON文字列Sをオブジェクトにデコードして返す // @JSONでこーど type: 'func', josi: [['を', 'の', 'から']], pure: true, fn: function (s: string): string { return JSON.parse(s) } }, 'JSON_E': { // @オブジェクトVをJSON形式にエンコードして返す(JSONエンコードと同じ) // @JSON_E type: 'func', josi: [['を', 'の']], pure: true, fn: function (v: any) { return JSON.stringify(v) } }, 'JSON_ES': { // @オブジェクトVをJSON形式にエンコードして整形して返す(JSONエンコード整形と同じ) // @JSON_ES type: 'func', josi: [['を', 'の']], pure: true, fn: function (v: any) { return JSON.stringify(v, null, 2) } }, 'JSON_D': { // @JSON文字列Sをオブジェクトにデコードして返す(JSONデコードと同じ) // @JSON_D type: 'func', josi: [['を', 'の', 'から']], pure: true, fn: function (s: string): string { return JSON.parse(s) } }, // @正規表現 '正規表現マッチ': { // @文字列Aを正規表現パターンBでマッチして結果を返す(パターンBは「/pat/opt」の形式で指定。optにgの指定がなければ部分マッチが『抽出文字列』に入る) // @せいきひょうげんまっち type: 'func', josi: [['を', 'が'], ['で', 'に']], pure: true, fn: function (a: any, b: any, sys: any): string { let re const f = ('' + b).match(/^\/(.+)\/([a-zA-Z]*)$/) // パターンがない場合 if (f === null) { re = new RegExp(b, 'g') } else { re = new RegExp(f[1], f[2]) } const sa: any[] = sys.__getSysVar('抽出文字列') sa.splice(0, sa.length) // clear const m = String(a).match(re) let result: any = m if (re.global) { // no groups } else if (m) { // has group? if (m.length > 0) { result = m[0] for (let i = 1; i < m.length; i++) { sa[i - 1] = m[i] } } } return result } }, '抽出文字列': { type: 'const', value: [] }, // @ちゅうしゅつもじれつ '正規表現置換': { // @文字列Sの正規表現パターンAをBに置換して結果を返す(パターンAは/pat/optで指定) // @せいきひょうげんちかん type: 'func', josi: [['の'], ['を', 'から'], ['で', 'に', 'へ']], pure: true, fn: function (s: string, a: string, b: string): string { let re const f = a.match(/^\/(.+)\/([a-zA-Z]*)/) if (f === null) { re = new RegExp(a, 'g') } else { re = new RegExp(f[1], f[2]) } return String(s).replace(re, b) } }, '正規表現区切': { // @文字列Sを正規表現パターンAで区切って配列で返す(パターンAは/pat/optで指定) // @せいきひょうげんくぎる type: 'func', josi: [['を'], ['で']], pure: true, fn: function (s: any, a: any) { let re const f = a.match(/^\/(.+)\/([a-zA-Z]*)/) if (f === null) { re = new RegExp(a, 'g') } else { re = new RegExp(f[1], f[2]) } return String(s).split(re) } }, // @指定形式 '通貨形式': { // @数値Vを三桁ごとにカンマで区切る // @つうかけいしき type: 'func', josi: [['を', 'の']], pure: true, fn: function (v: any) { return String(v).replace(/(?<!\.\d*?)(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') } }, 'ゼロ埋': { // @数値VをA桁の0で埋める // @ぜろうめ type: 'func', josi: [['を'], ['で']], pure: true, fn: function (v: any, a: any): string { v = String(v) let z = '0' for (let i = 0; i < a; i++) { z += '0' } a = parseInt(a) if (a < v.length) { a = v.length } const s = z + String(v) return s.substring(s.length - a, s.length) } }, '空白埋': { // @文字列VをA桁の空白で埋める // @くうはくうめ type: 'func', josi: [['を'], ['で']], pure: true, fn: function (v: any, a: any): string { v = String(v) let z = ' ' for (let i = 0; i < a; i++) { z += ' ' } a = parseInt(a) if (a < v.length) { a = v.length } const s = z + String(v) return s.substring(s.length - a, s.length) } }, // @文字種類 'かなか判定': { // @文字列Sの1文字目がひらがなか判定 // @かなかはんてい type: 'func', josi: [['を', 'の', 'が']], pure: true, fn: function (s: any): boolean { const c = String(s).charCodeAt(0) return (c >= 0x3041 && c <= 0x309F) } }, 'カタカナ判定': { // @文字列Sの1文字目がカタカナか判定 // @かたかなかはんてい type: 'func', josi: [['を', 'の', 'が']], pure: true, fn: function (s: any): boolean { const c = String(s).charCodeAt(0) return (c >= 0x30A1 && c <= 0x30FA) } }, '数字判定': { // @文字列Sの1文字目が数字か判定 // @すうじかはんてい type: 'func', josi: [['を', 'が']], pure: true, fn: function (s: any): boolean { const c = String(s).charAt(0) return ((c >= '0' && c <= '9') || (c >= '0' && c <= '9')) } }, '数列判定': { // @文字列S全部が数字か判定 // @すうれつかはんてい type: 'func', josi: [['を', 'が']], pure: true, fn: function (s: any): boolean { const checkerRE = /^[+\-+-]?([0-90-9]*)(([..][0-90-9]+)?|([..][0-90-9]+[eEeE][+\-+-]?[0-90-9]+)?)$/ return String(s).match(checkerRE) !== null } }, // @配列操作 '配列結合': { // @配列Aを文字列Sでつなげて文字列で返す // @はいれつけつごう type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a: any, s: string): string { // 配列ならOK if (a instanceof Array) { return a.join('' + s) } const a2 = String(a).split('\n') // 配列でなければ無理矢理改行で区切ってみる return a2.join('' + s) } }, '配列只結合': { // @配列Aの要素をただ結合して文字列で返す。(「」で配列結合と同じ) // @はいれつただけつごう type: 'func', josi: [['を']], pure: true, fn: function (a: any): string { if (a instanceof Array) { return a.join('') } const a2 = String(a).split('\n') // 配列でなければ無理矢理改行で区切ってみる return a2.join('') } }, '配列検索': { // @配列Aから文字列Sを探してインデックス番号(0起点)を返す。見つからなければ-1を返す。 // @はいれつけんさく type: 'func', josi: [['の', 'から'], ['を']], pure: true, fn: function (a: any, s: any) { if (a instanceof Array) { return a.indexOf(s) }// 配列ならOK return -1 } }, '配列要素数': { // @配列Aの要素数を返す // @はいれつようそすう type: 'func', josi: [['の']], pure: true, fn: function (a: any) { if (a instanceof Array) { return a.length }// 配列ならOK if (a instanceof Object) { return Object.keys(a).length } // オブジェクト if (typeof a === 'string') { return String(a).length } // 文字列 return 1 } }, '要素数': { // @Aの要素数を返す。Aには配列/辞書型/文字列を指定する。 // @ようそすう type: 'func', josi: [['の']], pure: true, fn: function (a: any, sys: any) { return sys.__exec('配列要素数', [a]) } }, 'LEN': { // @Aの要素数を返す。Aには配列/辞書型/文字列を指定する。 // @LEN type: 'func', josi: [['の']], pure: true, fn: function (a: any, sys: any) { return sys.__exec('配列要素数', [a]) } }, '配列挿入': { // @配列AのI番目(0起点)に要素Sを追加して返す(v1非互換) // @はいれつそうにゅう type: 'func', josi: [['の'], ['に', 'へ'], ['を']], pure: true, fn: function (a: any, i: any, s: any) { if (a instanceof Array) { return a.splice(i, 0, s) } // 配列ならOK throw new Error('『配列挿入』で配列以外の要素への挿入。') } }, '配列一括挿入': { // @配列AのI番目(0起点)に配列bを追加して返す(v1非互換) // @はいれついっかつそうにゅう type: 'func', josi: [['の'], ['に', 'へ'], ['を']], pure: true, fn: function (a: any, i: any, b: any) { if (a instanceof Array && b instanceof Array) { // 配列ならOK for (let j = 0; j < b.length; j++) { a.splice(i + j, 0, b[j]) } return a } throw new Error('『配列一括挿入』で配列以外の要素への挿入。') } }, '配列ソート': { // @配列Aをソートして返す(A自体を変更) // @はいれつそーと type: 'func', josi: [['の', 'を']], pure: true, fn: function (a: any) { if (a i