nadesiko3
Version:
Japanese Programming Language
1,812 lines (1,787 loc) • 129 kB
text/typescript
import { NakoRuntimeError } from './nako_errors.mjs'
import { NakoGlobal } from './nako_global.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.pathSeparator = '/' // パス記号 #2185
sys.engine = '?' // エンジン名
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' + String(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 String(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 = String(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を使うことに
sys.__evalJS = (src: string, sys?: NakoSystem) => {
try {
// まず従来通りevalで評価(式の値を返す互換性を維持)
return eval(src)
} catch (e) {
// return文によるSyntaxErrorの場合のみIIFEで再試行 (#NE-006)
if (e instanceof SyntaxError && e.message.includes('return')) {
try {
return (new Function('sys', `return (function(sys){\n${src}\n})(sys)`))(sys)
} catch (e2) {
console.warn('[eval]', e2)
return null
}
}
console.warn('[eval]', e)
return null
}
}
// Propアクセス支援
sys.__registPropAccessor = (f: any, 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: true }, // @はい
'いいえ': { type: 'const', value: false }, // @いいえ
'真': { type: 'const', value: true }, // @しん
'偽': { type: 'const', value: false }, // @ぎ
'永遠': { type: 'const', value: true }, // @えいえん
'オン': { type: 'const', value: true }, // @おん
'オフ': { type: 'const', value: false }, // @おふ
'改行': { 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])
}
},
'真偽判定': { // @引数bが真(true)ならば「真」を偽(false)ならば「偽」を返す // @しんぎはんてい
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function(b: any): string {
return b ? '真' : '偽'
}
},
// @標準出力
'表示': { // @Sを表示 // @ひょうじ
type: 'func',
josi: [['を', 'と']],
pure: true,
fn: function(s: string, sys: any) {
// 継続表示の一時プールを出力
s = String(sys.__printPool) + s
sys.__printPool = ''
//
sys.__setSysVar('表示ログ', String(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) {
if (typeof (a) === 'bigint' || typeof (b) === 'bigint') {
return BigInt(a) + BigInt(b)
}
return parseFloat(a) + parseFloat(b)
}
},
'合計': { // @引数(可変)に指定した値を全て合計して返す // @ごうけい
type: 'func',
josi: [['と', 'を', 'の']],
isVariableJosi: true,
pure: true,
fn: function(...a: any) {
const sys = a.pop() // remove NakoSystem
if (a.length >= 1 && a[0] instanceof Array) {
return sys.__exec('配列合計', [a[0], sys])
}
let isBigInt = false
let sum = 0
for (const v of a) {
if (typeof (v) === 'bigint') {
isBigInt = true
break
}
sum += parseFloat(v)
}
if (isBigInt) {
let bigsum = 0n
for (const v of a) {
bigsum += BigInt(v)
}
return bigsum
}
return sum
}
},
'引': { // @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して関数を得る
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実行する // @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して関数を得る
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,
asyncFn: true,
fn: async function(code: string, sys: any) {
const options = {
resetEnv: false,
resetAll: true,
nakoGlobal: sys
}
const tmpLog = String(sys.__getSysVar('表示ログ', ''))
sys.__setSysVar('表示ログ', '')
await sys.__self.runAsync(code, sys.__modName, options)
const outLog = String(sys.__getSysVar('表示ログ'))
sys.__setSysVar('表示ログ', tmpLog + outLog)
return outLog
}
},
'ナデシコ続': { // @なでしこのコードCODEを実行する // @なでしこつづける
type: 'func',
josi: [['を', 'で']],
pure: false,
asyncFn: true,
fn: async function(code: string, sys: any) {
const options = {
resetEnv: false,
resetAll: false,
nakoGlobal: sys.__self
}
const tmpLog = sys.__getSysVar('表示ログ', '')
sys.__setSysVar('表示ログ', '')
await sys.__self.runAsync(code, sys.__modName, options)
const outLog = String(sys.__getSysVar('表示ログ'))
if (outLog) {
sys.logger.trace(outLog)
}
sys.__setSysVar('表示ログ', tmpLog + outLog)
return outLog
}
},
'実行': { // @ 無名関数(あるいは、文字列で関数名を指定)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(String(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): any {
return (a || b)
}
},
'論理AND': { // @AとBの論理積を返す(v1非互換)。日本語の「AかつB」に相当する // @ろんりAND
type: 'func',
josi: [['と'], ['の']],
pure: true,
fn: function(a: any, b: any): boolean {
return (a && b)
}
},
'論理NOT': { // @値Vが0や空ならばtrue、それ以外ならばfalseを返す(v1非互換) // @ろんりNOT
type: 'func',
josi: [['の']],
pure: true,
fn: function(v: any): boolean {
return (!v)
}
},
// @ビット演算
'OR': { // @(ビット演算で)AとBの論理和を返す。 // @OR
type: 'func',
josi: [['と'], ['の']],
pure: true,
fn: function(a: any, b: any): any {
return (a | b)
}
},
'AND': { // @(ビット演算で)AとBの論理積を返す。日本語の「AかつB」に相当する // @AND
type: 'func',
josi: [['と'], ['の']],
pure: true,
fn: function(a: any, b: any): any {
return (a & b)
}
},
'XOR': { // @(ビット演算で)AとBの排他的論理和を返す。// @XOR
type: 'func',
josi: [['と'], ['の']],
pure: true,
fn: function(a: any, b: any): any {
return (a ^ b)
}
},
'NOT': { // @(ビット演算で)Vの各ビットを反転して返す。// @NOT
type: 'func',
josi: [['の']],
pure: true,
fn: function(v: any): any {
return (~v)
}
},
'SHIFT_L': { // @VをAビット左へシフトして返す // @SHIFT_L
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function(v: number, a: number): number {
return (v << a)
}
},
'SHIFT_R': { // @VをAビット右へシフトして返す(符号を維持する) // @SHIFT_R
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function(v: number, a: number): number {
return (v >> a)
}
},
'SHIFT_UR': { // @VをAビット右へシフトして返す(符号を維持しない、0で埋める) // @SHIFT_UR
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function(v: number, a: number): number {
return (v >>> a)
}
},
// @文字列処理
'文字数': { // @文字列Vの文字数を返す // @もじすう
type: 'func',
josi: [['の']],
pure: true,
fn: function(v: any): number {
if (!Array.from) { return String(v).length }
// Unicodeのサロゲートペアを考慮して文字数をカウント #1954 を参照
return Array.from(v).length
}
},
'何文字目': { // @文字列SでAが何文字目にあるか調べて返す。見つからなければ0を返す。 // @なんもじめ
type: 'func',
josi: [['で', 'の'], ['が']],
pure: true,
fn: function(s: string, a: string): number {
// Unicodeのサロゲートペアを考慮して、文字列を検索 #1954 を参照
// return String(s).indexOf(a) + 1 // サロゲートペアを無視した場合
const strArray = Array.from(s)
const searchArray = Array.from(a)
for (let i = 0; i < strArray.length; i++) {
if (strArray.slice(i, i + searchArray.length).join('') === searchArray.join('')) {
return i + 1
}
}
return 0
}
},
'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 strArray = Array.from(s)
strArray.splice(i - 1, 0, a)
return strArray.join('')
}
},
'文字検索': { // @文字列SでA文字目から文字列Bを検索。見つからなければ0を返す。(類似命令に『何文字目』がある)(v1非互換) // @もじけんさく
type: 'func',
josi: [['で', 'の'], ['から'], ['を']],
pure: true,
fn: function(s: string, a: number, b: string): number {
// サロゲートペアを考慮して文字列を検索する
// return String(s).indexOf(b, a - 1) + 1
if (a <= 0) { a = 1 }
const strArray = Array.from(s)
const searchArray = Array.from(b)
// Unicode単位で検索
for (let i = a - 1; i < strArray.length; i++) {
if (strArray.slice(i, i + searchArray.length).join('') === searchArray.join('')) {
// 合致した
return i + 1
}
}
return 0
}
},
'追加': { // @文字列または配列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'
}
},
'連結': { // @引数(可変)に指定した文字列を連結して文字列を返す // @れんけつ
type: 'func',
josi: [['と', 'を']],
pure: true,
isVariableJosi: true,
fn: function(...a: any) {
a.pop() // NakoSystemを取り除く
return a.join('')
}
},
'文字列連結': { // @引数(可変)に指定した文字列を連結して文字列を返す // @もじれつれんけつ
type: 'func',
josi: [['と', 'を']],
pure: true,
isVariableJosi: true,
fn: function(...a: any) {
a.pop() // NakoSystemを取り除く
return a.join('')
}
},
'文字列分解': { // @文字列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, sys: NakoSystem) {
return sys.__exec('文字抜出', [s, a, cnt])
}
},
'文字抜出': { // @文字列SのA文字目からCNT文字を抽出する(Aが0未満の時は後ろからA文字目からCNT文字を抽出) // @もじぬきだす
type: 'func',
josi: [['で', 'の'], ['から'], ['を', '']],
pure: true,
fn: function(s: any, a: number, cnt: number) {
// 引数の型チェック #1995
if (typeof a === 'string') { a = parseInt(a) }
if (typeof cnt === 'string') { cnt = parseInt(cnt) }
// もし、cntが0以下なら空文字を返す
if (cnt <= 0) { return '' }
// サロゲートペアを考慮した処理を行う
const strArray = Array.from(s)
// もし、aの値が0未満の時は後ろからa文字目からcnt文字を抽出
if (a < 0) {
a = strArray.length + a + 1
if (a < 0) { a = 1 }
}
return strArray.slice(a - 1, a + cnt - 1).join('')
}
},
'LEFT': { // @文字列Sの左端からCNT文字を抽出する // @LEFT
type: 'func',
josi: [['の', 'で'], ['だけ']],
pure: true,
fn: function(s: string, cnt: number, sys: NakoSystem): string {
return sys.__exec('文字左部分', [s, cnt])
}
},
'文字左部分': { // @文字列Sの左端からCNT文字を抽出する // @もじひだりぶぶん
type: 'func',
josi: [['の', 'で'], ['だけ', '']],
pure: true,
fn: function(s: string, cnt: number): string {
// return (String(s).substring(0, cnt))
// サロゲートペアを考慮
const strArray = Array.from(s)
return strArray.slice(0, cnt).join('')
}
},
'RIGHT': { // @文字列Sの右端からCNT文字を抽出する(『文字右部分』と同じ) // @RIGHT
type: 'func',
josi: [['の', 'で'], ['だけ']],
pure: true,
fn: function(s: string, cnt: number, sys: NakoSystem): string {
return sys.__exec('文字右部分', [s, cnt])
}
},
'文字右部分': { // @文字列Sの右端からCNT文字を抽出する // @もじみぎぶぶん
type: 'func',
josi: [['の', 'で'], ['だけ', '']],
pure: true,
fn: function(s: string, cnt: number): string {
// return (s.substring(s.length - cnt, s.length))
// サロゲートペアを考慮
const strArray = Array.from(s)
let index = strArray.length - cnt
if (index < 0) { index = 0 }
return strArray.slice(index, strArray.length).join('')
}
},
'区切': { // @文字列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 {
// サロゲートペアを考慮
const strArray = Array.from(s)
strArray.splice(a - 1, b)
return strArray.join('')
}
},
'文字始': { // @文字列SがAから始まるならば真を返す // @もじはじまる
type: 'func',
josi: [['が'], ['で', 'から']],
pure: true,
fn: function(s: string, a: string): boolean {
return s.startsWith(a)
}
},
'文字終': { // @文字列SがAで終わるならば真を返す // @もじおわる
type: 'func',
josi: [['が'], ['で']],
pure: true,
fn: function(s: string, a: string): boolean {
return s.endsWith(a)
}
},
'出現': { // @文字列(配列)SにAが出現する場合に真を返す // @しゅつげん
type: 'func',
josi: [['に','で'], ['が']],
pure: true,
fn: function(s: any, a: string): boolean {
if (typeof(s) === 'string') {
return s.includes(a)
}
if (s instanceof Array) {
return s.includes(a)
}
const ss = String(s)
return ss.includes(a)
}
},
// @置換・トリム
'置換': { // @文字列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 {
return String(s).replace(/^\s+/, '').replace(/\s+$/, '')
}
},
'空白除去': { // @文字列Sの前後にある空白を削除する // @くうはくじょきょ
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function(s: string): string {
return String(s).replace(/^\s+/, '').replace(/\s+$/, '')
}
},
'右トリム': { // @文字列Sの末尾にある空白を削除する // @みぎとりむ
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function(s: string): string {
return String(s).replace(/\s+$/, '')
}
},
'左トリム': { // @文字列Sの先頭にある空白を削除する // @ひだりとりむ
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function(s: string): string {
return String(s).replace(/^\s+/, '')
}
},
'末尾空白除去': { // @文字列Sの末尾にある空白を削除する // @まつびくうはくじょきょ
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function(s: string): string {
return String(s).replace(/\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: string) {
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: string) {
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: string) {
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: string) {
return String.fromCharCode(v.charCodeAt(0) - 0xFEE0)
})
}
},
'英数記号全角変換': { // @文字列Sの半角英数記号文字を全角に変換 // @えいすうきごうぜんかくへんかん
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function(s: string): string {
return String(s).replace(/[\x20-\x7E]/g, function(v: string) {
if (v === ' ') { return ' ' } // 半角スペース(0x20)を全角スペース(U+3000)に
return String.fromCharCode(v.charCodeAt(0) + 0xFEE0)
})
}
},
'英数記号半角変換': { // @文字列Sの記号文字を半角に変換 // @えいすうきごうはんかくへんかん
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function(s: string): string {
return String(s).replace(/[\u3000\uFF00-\uFF5F]/g, function(v: string) {
if (v === ' ') { return ' ' } // 全角スペース(U+3000)を半角スペース(U+0020)
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取得': { // @JSON文字列をパースして、なでしこのオブジェクトとして返す // @JSONしゅとく
type: 'func',
josi: [['を', 'の', 'から']],
pure: true,
fn: function(v: any) {
return JSON.parse(v)
}
},
'JSONエンコード': { // @オブジェクトVをJSON形式に変換して返す(『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取得』と同じ) // @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: string, b: string, 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
}
},
'正規表現抽出': { // @文字列Sを正規表現パターンREで正規表現マッチし、すべてのキャプチャグループ( )を一次元配列として返す。抽出文字列には二次元配列を返す// @せいきひょうげんちゅうしゅつ
type: 'func',
josi: [['から','を'], ['で']],
pure: true,
fn: function(a: string, b: string, sys: any): any[] {
let pattern = '' + b
let flags = 'g'
const f = pattern.match(/^\/(.+)\/([a-zA-Z]*)