UNPKG

nadesiko3

Version:
1,806 lines 108 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import { NakoRuntimeError } from './nako_errors.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) { // システム変数の初期化 const system = sys; sys.isDebug = false; // システム変数にアクセスするための関数を定義 sys.__setSysVar = (name, value) => system.__v0.set(name, value); sys.__getSysVar = (name, defaultValue = undefined) => { const v = system.__v0.get(name); if (v === undefined) { return defaultValue; } return v; }; sys.__setSore = (v) => { sys.__vars.set('それ', v); return v; }; sys.__getSore = () => sys.__vars.get('それ'); sys.tags = {}; // タグ - プラグイン側で自由に使えるオブジェクト // 言語バージョンを設定 sys.__setSysVar('ナデシコバージョン', sys.version); sys.__setSysVar('ナデシコ言語バージョン', sys.coreVersion); if (!system.__namespaceList) { system.__namespaceList = []; } // なでしこの関数や変数を探して返す sys.__findVar = function (nameStr, def) { 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, parentFunc) { const f = sys.__findVar(nameStr); if (typeof f === 'function') { return f; } throw new Error(`『${parentFunc}』に実行できない関数が指定されました。`); }; // システム関数を実行 sys.__exec = function (func, params) { // システム命令を優先 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) => { s = '00' + s; return s.substring(s.length - 2); }; sys.__zero = (s, keta) => { let zeroS = ''; for (let i = 0; i < keta; i++) { zeroS += '0'; } s = zeroS + s; return s.substring(s.length - keta); }; sys.__formatDate = (t) => { return t.getFullYear() + '/' + z2(t.getMonth() + 1) + '/' + z2(t.getDate()); }; sys.__formatTime = (t) => { return z2(t.getHours()) + ':' + z2(t.getSeconds()) + ':' + z2(t.getMinutes()); }; sys.__formatDateTime = (t, fmt) => { 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) => { // 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) => { return (typeof v) === 'bigint' ? v : parseFloat(v); }; // undefinedチェック system.chk = (value, constId) => { 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) => { // 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, sys) => { 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, getProp, setProp) => { system.__propAccessor.push({ target: f, getProp, setProp }); }; sys.__checkPropAccessor = (mode, obj) => { 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) { 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 () { return []; } }, '空辞書': { type: 'func', josi: [], pure: true, fn: function () { return {}; } }, '空ハッシュ': { type: 'func', josi: [], pure: true, fn: function () { return {}; } }, '空オブジェクト': { type: 'func', josi: [], pure: false, fn: function (sys) { return sys.__exec('空ハッシュ', [sys]); } }, // @標準出力 '表示': { type: 'func', josi: [['を', 'と']], pure: true, fn: function (s, sys) { // 継続表示の一時プールを出力 s = sys.__printPool + s; sys.__printPool = ''; // sys.__setSysVar('表示ログ', sys.__getSysVar('表示ログ') + s + '\n'); sys.logger.send('stdout', s + ''); }, return_none: true }, '継続表示': { type: 'func', josi: [['を', 'と']], pure: true, fn: function (s, sys) { sys.__printPool += s; }, return_none: true }, '連続表示': { type: 'func', josi: [['と', 'を']], isVariableJosi: true, pure: true, fn: function (...a) { 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) { 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) { sys.__setSysVar('表示ログ', ''); }, return_none: true }, '言': { type: 'func', josi: [['を', 'と']], pure: true, fn: function (s, sys) { sys.logger.send('stdout', s + ''); }, return_none: true }, 'コンソール表示': { type: 'func', josi: [['を', 'と']], pure: true, fn: function (s) { console.log(s); }, return_none: true }, // @四則演算 '足': { type: 'func', josi: [['に', 'と'], ['を']], isVariableJosi: false, pure: true, fn: function (a, b) { return a + b; } }, '引': { type: 'func', josi: [['から'], ['を']], pure: true, fn: function (a, b) { return a - b; } }, '掛': { type: 'func', josi: [['に', 'と'], ['を']], pure: true, fn: function (a, b) { // 数値の掛け算 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 = []; for (let i = 0; i < parseInt(b); i++) { aa.push(...a); } return aa; } return a * b; } }, '倍': { type: 'func', josi: [['の', 'を'], ['']], pure: true, fn: function (a, b) { return a * b; } }, '割': { type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a, b) { return a / b; } }, '割余': { type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a, b) { return a % b; } }, '偶数': { type: 'func', josi: [['が']], pure: true, fn: function (a) { return (parseInt(a) % 2 === 0); } }, '奇数': { type: 'func', josi: [['が']], pure: true, fn: function (a) { return (parseInt(a) % 2 === 1); } }, '二乗': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (a) { return a * a; } }, 'べき乗': { type: 'func', josi: [['の'], ['の']], pure: true, fn: function (a, b) { return Math.pow(a, b); } }, '以上': { type: 'func', josi: [['が'], ['']], pure: true, fn: function (a, b) { return a >= b; } }, '以下': { type: 'func', josi: [['が'], ['']], pure: true, fn: function (a, b) { return a <= b; } }, '未満': { type: 'func', josi: [['が'], ['']], pure: true, fn: function (a, b) { return a < b; } }, '超': { type: 'func', josi: [['が'], ['']], pure: true, fn: function (a, b) { return a > b; } }, '等': { type: 'func', josi: [['が'], ['と']], pure: true, fn: function (a, b) { return a === b; } }, '等無': { type: 'func', josi: [['が'], ['と']], pure: true, fn: function (a, b) { return a !== b; } }, '一致': { type: 'func', josi: [['が'], ['と']], pure: true, fn: function (a, b) { // オブジェクトの場合、JSONに変換して比較 if (typeof (a) === 'object') { const jsonA = JSON.stringify(a); const jsonB = JSON.stringify(b); return jsonA === jsonB; } return a === b; } }, '不一致': { type: 'func', josi: [['が'], ['と']], pure: true, fn: function (a, b) { // オブジェクトの場合、JSONに変換して比較 if (typeof (a) === 'object') { const jsonA = JSON.stringify(a); const jsonB = JSON.stringify(b); return jsonA !== jsonB; } return a !== b; } }, '範囲内': { type: 'func', josi: [['が'], ['から'], ['の', 'までの']], pure: true, fn: function (v, a, b) { return (a <= v) && (v <= b); } }, '範囲': { type: 'func', josi: [['から'], ['の', 'までの']], pure: true, fn: function (a, b) { return { '先頭': a, '末尾': b }; } }, '連続加算': { type: 'func', josi: [['を'], ['に', 'と']], isVariableJosi: true, pure: true, fn: function (b, ...a) { a.pop(); // 必ず末尾に sys があるので、末尾のシステム変数を除外 a.push(b); return a.reduce((p, c) => p + c); } }, 'MAX': { type: 'func', josi: [['の'], ['と']], isVariableJosi: true, pure: true, fn: function (b, ...a) { const sys = a.pop(); return sys.__exec('最大値', [b, ...a, sys]); } }, '最大値': { type: 'func', josi: [['の'], ['と']], isVariableJosi: true, pure: true, fn: function (b, ...a) { a.pop(); // 必ず末尾に sys があるので、末尾のシステム変数を除外 a.push(b); return a.reduce((p, c) => Math.max(p, c)); } }, 'MIN': { type: 'func', josi: [['の'], ['と']], isVariableJosi: true, pure: true, fn: function (b, ...a) { const sys = a.pop(); return sys.__exec('最小値', [b, ...a, sys]); } }, '最小値': { type: 'func', josi: [['の'], ['と']], isVariableJosi: true, pure: true, fn: function (b, ...a) { a.pop(); // 必ず末尾に sys があるので、末尾のシステム変数を除外 a.push(b); return a.reduce((p, c) => Math.min(p, c)); } }, 'CLAMP': { type: 'func', josi: [['の', 'を'], ['から'], ['までの', 'で']], pure: true, fn: function (x, a, b) { return Math.min(Math.max(x, a), b); } }, // @敬語 'ください': { type: 'func', josi: [], pure: true, fn: function (sys) { if (!sys.__reisetu) { sys.__reisetu = 0; } sys.__reisetu++; }, return_none: true }, 'お願': { type: 'func', josi: [], pure: true, fn: function (sys) { if (!sys.__reisetu) { sys.__reisetu = 0; } sys.__reisetu++; }, return_none: true }, 'です': { type: 'func', josi: [], pure: true, fn: function (sys) { if (!sys.__reisetu) { sys.__reisetu = 0; } sys.__reisetu++; }, return_none: true }, '拝啓': { type: 'func', josi: [], pure: true, fn: function (sys) { sys.__reisetu = 0; }, return_none: true }, '敬具': { type: 'func', josi: [], pure: true, fn: function (sys) { sys.__reisetu += 100; // bonus point }, return_none: true }, '礼節レベル取得': { type: 'func', josi: [], pure: true, fn: function (sys) { if (!sys.__reisetu) { sys.__reisetu = 0; } return sys.__reisetu; } }, // @特殊命令 'JS実行': { type: 'func', josi: [['を', 'で']], pure: true, fn: function (src, sys) { return sys.__evalJS(src, sys); // #1733 } }, 'JSオブジェクト取得': { type: 'func', josi: [['の']], pure: false, fn: function (name, sys) { return sys.__findVar(name, null); } }, 'JS関数実行': { type: 'func', josi: [['を'], ['で']], fn: function (name, args, sys) { // 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': { type: 'func', josi: [], asyncFn: true, pure: true, fn: async function () { // empty }, return_none: true }, 'AWAIT実行': { type: 'func', josi: [['を'], ['で']], pure: true, asyncFn: true, fn: async function (f, args, sys) { // 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メソッド実行': { type: 'func', josi: [['の'], ['を'], ['で']], fn: function (obj, m, args, sys) { // 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); } }, 'ナデシコ': { type: 'func', josi: [['を', 'で']], pure: false, fn: function (code, sys) { sys.__setSysVar('表示ログ', ''); sys.__self.runEx(code, sys.__modName, { resetEnv: false, resetLog: true }); const outLog = sys.__getSysVar('表示ログ') + ''; if (outLog) { sys.logger.trace(outLog); } return outLog; } }, 'ナデシコ続': { type: 'func', josi: [['を', 'で']], fn: function (code, sys) { sys.__self.runEx(code, sys.__modName, { resetEnv: false, resetAll: false }); const out = sys.__getSysVar('表示ログ') + ''; if (out) { sys.logger.trace(out); } return out; } }, '実行': { type: 'func', josi: [['を', 'に', 'で']], pure: false, fn: function (f, sys) { // #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; } }, '実行時間計測': { type: 'func', josi: [['の']], pure: false, fn: function (f, sys) { 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) { // デバッグモードでなければ例外を投げることでプログラムを終了させる sys.__setSysVar('__forceClose', true); if (!sys.__getSysVar('__useDebug')) { throw new Error('__終わる__'); } } }, // @型変換 '変数型確認': { type: 'func', josi: [['の']], pure: true, fn: function (v) { return (typeof v); } }, 'TYPEOF': { type: 'func', josi: [['の']], pure: true, fn: function (v) { return (typeof v); } }, '文字列変換': { type: 'func', josi: [['を']], pure: true, fn: function (v) { return String(v); } }, 'TOSTR': { type: 'func', josi: [['を']], pure: true, fn: function (v) { return String(v); } }, '整数変換': { type: 'func', josi: [['を']], pure: true, fn: function (v) { return parseInt(v); } }, 'TOINT': { type: 'func', josi: [['を']], pure: true, fn: function (v) { return parseInt(v); } }, '実数変換': { type: 'func', josi: [['を']], pure: true, fn: function (v) { return parseFloat(v); } }, 'TOFLOAT': { type: 'func', josi: [['を']], pure: true, fn: function (v) { return parseFloat(v); } }, 'INT': { type: 'func', josi: [['の']], pure: true, fn: function (v) { return parseInt(v); } }, 'FLOAT': { type: 'func', josi: [['の']], pure: true, fn: function (v) { return parseFloat(v); } }, 'NAN判定': { type: 'func', josi: [['を']], pure: true, fn: function (v) { return isNaN(v); } }, '非数判定': { type: 'func', josi: [['を']], pure: true, fn: function (v) { // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN return Number.isNaN(v); } }, 'HEX': { type: 'func', josi: [['の']], pure: true, fn: function (a) { return parseInt(a).toString(16); } }, '進数変換': { type: 'func', josi: [['を', 'の'], ['']], pure: true, fn: function (v, n) { return parseInt(v).toString(n); } }, '二進': { type: 'func', josi: [['を', 'の', 'から']], pure: true, fn: function (v) { return parseInt(v).toString(2); } }, '二進表示': { type: 'func', josi: [['を', 'の', 'から']], pure: true, fn: function (v, sys) { const s = parseInt(v).toString(2); sys.__exec('表示', [s, sys]); } }, 'RGB': { type: 'func', josi: [['と'], ['の'], ['で']], pure: true, fn: function (r, g, b) { const z2 = (v) => { const v2 = '00' + (parseInt('' + v).toString(16)); return v2.substring(v2.length - 2, v2.length); }; return '#' + z2(r) + z2(g) + z2(b); } }, // @論理演算 '論理OR': { type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a, b) { return (a || b); } }, '論理AND': { type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a, b) { return (a && b); } }, '論理NOT': { type: 'func', josi: [['の']], pure: true, fn: function (v) { return (!v) ? 1 : 0; } }, // @ビット演算 'OR': { type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a, b) { return (a | b); } }, 'AND': { type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a, b) { return (a & b); } }, 'XOR': { type: 'func', josi: [['と'], ['の']], pure: true, fn: function (a, b) { return (a ^ b); } }, 'NOT': { type: 'func', josi: [['の']], pure: true, fn: function (v) { return (~v); } }, 'SHIFT_L': { type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a, b) { return (a << b); } }, 'SHIFT_R': { type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a, b) { return (a >> b); } }, 'SHIFT_UR': { type: 'func', josi: [['を'], ['で']], pure: true, fn: function (a, b) { return (a >>> b); } }, // @文字列処理 '文字数': { type: 'func', josi: [['の']], pure: true, fn: function (v) { if (!Array.from) { return String(v).length; } return Array.from(v).length; } }, '何文字目': { type: 'func', josi: [['で', 'の'], ['が']], pure: true, fn: function (s, a) { return String(s).indexOf(a) + 1; } }, 'CHR': { type: 'func', josi: [['の']], pure: true, fn: function (v) { if (typeof v === 'number') { if (!String.fromCodePoint) { return String.fromCharCode(v); } return String.fromCodePoint(v); } const res = []; for (const s of v) { if (!String.fromCodePoint) { res.push(String.fromCharCode(s)); } res.push(String.fromCodePoint(s)); } return res; } }, 'ASC': { type: 'func', josi: [['の']], pure: true, fn: function (v) { if (typeof v === 'string') { if (!String.prototype.codePointAt) { return String(v).charCodeAt(0); } return String(v).codePointAt(0) || 0; } const res = []; for (const s of v) { if (!String.prototype.codePointAt) { res.push(String(s).charCodeAt(0)); } res.push(String(s).codePointAt(0) || 0); } return res; } }, '文字挿入': { type: 'func', josi: [['で', 'の'], ['に', 'へ'], ['を']], pure: true, fn: function (s, i, a) { 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; } }, '文字検索': { type: 'func', josi: [['で', 'の'], ['から'], ['を']], pure: true, fn: function (s, a, b) { let str = String(s); str = str.substring(a); const res = str.indexOf(b); if (res === -1) { return 0; } return res + 1 + a; } }, '追加': { type: 'func', josi: [['で', 'に', 'へ'], ['を']], pure: true, fn: function (s, a) { if (s instanceof Array) { s.push(a); return s; } return String(s) + String(a); } }, '一行追加': { type: 'func', josi: [['で', 'に', 'へ'], ['を']], pure: true, fn: function (s, a) { if (s instanceof Array) { s.push(a); return s; } return String(s) + String(a) + '\n'; } }, '文字列分解': { type: 'func', josi: [['を', 'の', 'で']], pure: true, fn: function (v) { if (!Array.from) { return String(v).split(''); } return Array.from(v); } }, 'リフレイン': { type: 'func', josi: [['を', 'の'], ['で']], pure: true, fn: function (v, cnt) { let s = ''; for (let i = 0; i < cnt; i++) { s += String(v); } return s; } }, '出現回数': { type: 'func', josi: [['で'], ['の']], pure: true, fn: function (s, a) { s = '' + s; a = '' + a; return s.split(a).length - 1; } }, 'MID': { type: 'func', josi: [['で', 'の'], ['から'], ['を']], pure: true, fn: function (s, a, cnt) { cnt = cnt || 1; return (String(s).substring(a - 1, a + cnt - 1)); } }, '文字抜出': { type: 'func', josi: [['で', 'の'], ['から'], ['を', '']], pure: true, fn: function (s, a, cnt) { cnt = cnt || 1; return (String(s).substring(a - 1, a + cnt - 1)); } }, 'LEFT': { type: 'func', josi: [['の', 'で'], ['だけ']], pure: true, fn: function (s, cnt) { return (String(s).substring(0, cnt)); } }, '文字左部分': { type: 'func', josi: [['の', 'で'], ['だけ', '']], pure: true, fn: function (s, cnt) { return (String(s).substring(0, cnt)); } }, 'RIGHT': { type: 'func', josi: [['の', 'で'], ['だけ']], pure: true, fn: function (s, cnt) { s = '' + s; return (s.substring(s.length - cnt, s.length)); } }, '文字右部分': { type: 'func', josi: [['の', 'で'], ['だけ', '']], pure: true, fn: function (s, cnt) { s = '' + s; return (s.substring(s.length - cnt, s.length)); } }, '区切': { type: 'func', josi: [['の', 'を'], ['で']], pure: true, fn: function (s, a) { return ('' + s).split('' + a); } }, '文字列分割': { type: 'func', josi: [['を'], ['で']], pure: true, fn: function (s, a) { s = '' + s; a = '' + a; const i = s.indexOf(a); if (i < 0) { return [s]; } return [s.substring(0, i), s.substring(i + a.length)]; } }, '切取': { type: 'func', josi: [['から', 'の'], ['まで', 'を']], pure: true, fn: function (s, a, sys) { 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); } }, '範囲切取': { type: 'func', josi: [['で', 'の'], ['から'], ['まで', 'を']], pure: true, fn: function (s, a, b, sys) { 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; } }, '文字削除': { type: 'func', josi: [['の'], ['から'], ['だけ', 'を', '']], pure: true, fn: function (s, a, b) { s = '' + s; const mae = s.substring(0, a - 1); const usi = s.substring((a - 1 + b)); return mae + usi; } }, // @置換・トリム '置換': { type: 'func', josi: [['の', 'で'], ['を', 'から'], ['に', 'へ']], pure: true, fn: function (s, a, b) { return String(s).split(a).join(b); } }, '単置換': { type: 'func', josi: [['の', 'で'], ['を'], ['に', 'へ']], pure: true, fn: function (s, a, b) { // replaceは最初の一度だけ置換する return String(s).replace(a, b); } }, 'トリム': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { s = String(s).replace(/^\s+/, '').replace(/\s+$/, ''); return s; } }, '空白除去': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { s = String(s).replace(/^\s+/, '').replace(/\s+$/, ''); return s; } }, '右トリム': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { s = String(s).replace(/\s+$/, ''); return s; } }, '末尾空白除去': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { s = String(s).replace(/\s+$/, ''); return s; } }, // @文字変換 '大文字変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { return String(s).toUpperCase(); } }, '小文字変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { return String(s).toLowerCase(); } }, '平仮名変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { const kanaToHira = (str) => { return String(str).replace(/[\u30a1-\u30f6]/g, function (m) { const chr = m.charCodeAt(0) - 0x60; return String.fromCharCode(chr); }); }; return kanaToHira('' + s); } }, 'カタカナ変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { const hiraToKana = (str) => { return String(str).replace(/[\u3041-\u3096]/g, function (m) { const chr = m.charCodeAt(0) + 0x60; return String.fromCharCode(chr); }); }; return hiraToKana('' + s); } }, '英数全角変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { return String(s).replace(/[A-Za-z0-9]/g, function (v) { return String.fromCharCode(v.charCodeAt(0) + 0xFEE0); }); } }, '英数半角変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { return String(s).replace(/[A-Za-z0-9]/g, function (v) { return String.fromCharCode(v.charCodeAt(0) - 0xFEE0); }); } }, '英数記号全角変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { return String(s).replace(/[\x20-\x7F]/g, function (v) { return String.fromCharCode(v.charCodeAt(0) + 0xFEE0); }); } }, '英数記号半角変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s) { return String(s).replace(/[\uFF00-\uFF5F]/g, function (v) { return String.fromCharCode(v.charCodeAt(0) - 0xFEE0); }); } }, 'カタカナ全角変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s, sys) { // 半角カタカナ 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; } }, 'カタカナ半角変換': { type: 'func', josi: [['の', 'を']], pure: true, fn: function (s, sys) { // 半角カタカナ 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(''); } }, '全角変換': { type: 'func', josi: [['の', 'を']], pure: false, fn: function (s, sys) { let result = s; result = sys.__exec('カタカナ全角変換', [result, sys]); result = sys.__exec('英数記号全角変換', [result, sys]); return result; } }, '半角変換': { type: 'func', josi: [['の', 'を']], pure: false, fn: function (s, sys) { 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エンコード': { type: 'func', josi: [['を', 'の']], pure: true, fn: function (v) { return JSON.stringify(v); } }, 'JSONエンコード整形': { type: 'func', josi: [['を', 'の']], pure: true, fn: function (v) { return JSON.stringify(v, null, 2); } }, 'JSONデコード': { type: 'func', josi: [['を', 'の', 'から']], pure: true, fn: function (s) { return JSON.parse(s); } }, 'JSON_E': { type: 'func', josi: [['を', 'の']], pure: true, fn: function (v) { return JSON.stringify(v); } }, 'JSON_ES': { type: 'func', josi: [['を', 'の']], pure: true, fn: function (v) { return JSON.stringify(v, null, 2); } }, 'JSON_D': { type: 'func', josi: [['を', 'の', 'から']], pure: true, fn: function (s) { return JSON.parse(s); } }, // @正規表現 '正規表現マッチ': { type: 'func', josi: [['を', 'が'], ['で', 'に']], pure: true, fn: function (a, b, sys) { 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 = sys.__getSysVar('抽出文字列'); sa.splice(0, sa.length); // clear const m = String(a).match(re); let result = 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: [] }, // @ちゅうしゅつもじれつ '正規表現置換': { type: 'func', josi: [['の'], ['を', 'から'], ['で', 'に', 'へ']], pure: true, fn: function (s, a, b) { 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); } }, '正規表現区切': { type: 'func', josi: [['を'], ['で']], pure: true, fn: function (s, a) { 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); } }, // @指定形式 '通貨形式': { type: 'func', josi: [['を', 'の']], pure: true, fn: function (v) { return String(v).replace(/(?<!\.\d*?)(\d)(?=(\d\d\d)+(?!\d))/g, '$1,'); } }, 'ゼロ埋': { type: 'func', josi: [['を'], ['で']], pure: true, fn: function (v, a) { 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); } }, '空白埋': { type: 'func', josi: [['を'], ['で']], pure: true, fn: function (v, a) { 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); } }, // @文字種類 'かなか判定': { type: 'func', josi: [['を', 'の', 'が']], pure: true, fn: function (s) { const c = String(s).charCodeAt(0); return (c >= 0x3041 && c <= 0x309F); } }, 'カタカナ判定': { type: 'func', josi: [['を', 'の', 'が']], pure: true, fn: function (s) { const c = String(s).charCodeAt(0); return (c >= 0x30A1 && c <= 0x30FA); } }, '数字判定': { type: 'func', josi: [['を', 'が']], pure: true, fn: function (s) { const c = String(s).charAt(0); return ((c >= '0' && c <= '9') || (c >= '0' && c <= '9')); } }, '数列判定': { type: 'func', josi: [['を', 'が']], pure: true, fn: function (s) { const checkerRE = /^[+\-+-]?([0-90-9]*)(([..][0-90-9]+)?|([..][0-90-9]+[eEeE][+\-+-]?[0-90-9]+)?)$/; return String(s).match(checkerRE) !== null; } }, // @配列操作 '配列結