@soei/format
Version:
字符串格式化: format(`query:?-?-?-?-{[0]>+1,1,2}`, +new Date, 1 > 2) => query:1711361589087-false-false-false-2
212 lines (206 loc) • 6.54 kB
JavaScript
let {
isFunction,
isArray,
iList2Array,
isNil,
isString,
isSimplyType,
merge,
iSplit,
each,
runer: iRuner
} = require('@soei/tools');
var Nil,
COMMA = ',',
SPACE = '',
r_A_Z = /(\d+)\-(\d+)/;
/* @see iReplace(...) {\d-\d}匹配提前 $1 $2, 和{prop}部分匹配冲突, 当prop内含有 - 号时*/
var rFormat = /(?:{(\d+)\-(\d+)}|\[([\w-]+)\]|\{([^,{}\[\]]+)\}|\[([^\[\]\{\}'"]+)\]|([\w$\u4e00-\u9fa5]+)(\s*(?:=|:\s*))\?)|{([^,\}\{]+),([^,}]*),([^,}]*)}/g;
var rFormatSp = /(?:,)/;
var iInnerFunx = {
now: function () { return +new Date; }
}
// 关键词
var KEYWORD = /(?:\W|^)(?:var|let|const|in|while|for|of|this|true|false)\W+/ig;
/* (expr[+-!] | name [expr] | name ? [true] : [false]) name2*/
var rEXPR = /(?:[\+\-\!]+|[_$\w]+\s*[><=%\+\-\*/|&!^]|\?\s*[_$]*\w+\s*\:)\s*[_$\w]+/;
// 获取表达式对应的值
function _GetExp2funcValue(exp, data, propertys) {
var ex, invalid;
if (rEXPR.test(exp)) {
var afunArgs = exp.replace(KEYWORD, SPACE).match(/([a-z_$]+\w*)/ig) || [], picker = [];
each(afunArgs, function (_, k, picker, data) {
picker.push(data[k]);
}, picker, data);
ex = new Function(
// 参数
afunArgs.join(COMMA),
// 返回值
'return ' + exp
)/* 调用 */.apply(Nil, picker);
} else {
ex = (invalid = isNil(ex = data[exp])) && propertys && /^[_$]*[\w]+$/.test(exp) ? propertys : (!invalid ? ex : propertys || exp);
if (isFunction(ex)) {
ex = ex.apply(data, isArray(propertys) ? propertys : isNil(propertys) ? Nil : [propertys])
}
};
return ex;
}
function between(a, z, callback, brimless/* 无边缘 */) {
if (isString(a)) {
let az = a.match(r_A_Z);
if (az) {
z = az[2];
a = az[1];
}
}
var min, max, edge = +!!brimless;
if (+a < +z) {
min = +a;
max = +z;
} else {
min = +z;
max = +a;
}
var lof = (max - min) + 1 - 2 * edge;
if (isFunction(callback)) {
while (lof-- > 0) {
if (iRuner(callback, null, min + lof + edge, max, min)) break;
}
} else {
return (Math.random() * 1e6 >> 0) % lof + min;
}
}
/**
* 替换字符串中含有的 ? 按照顺序替换
* @param {String} mode
* @param {String|Array} args
* @returns
*/
function TextFormat(mode, args) {
var mat = /\?/;
if (mat.test(mode)) {
isArray(args) || (args = iList2Array(arguments), args.shift());
isString(args) && (args = iSplit(args));
var list = mode.match(/\?/g), pre;
for (var i = 0, lenth = list.length; i < lenth; i++) {
mode = mode.replace(mat, (pre = ((isNil(args[i]) ? pre : args[i]))));
}
}
return mode;
}
/**
* 字符串格式化
* 'key=?|[val]|{1-19}|[1,2,3]'.format({key:1,val:2})
* key=1|2|3(1-19随机)|2(1,2,3)随机一个
* @Time 2018-11-13
*/
function iStringFormat(args) {
var host = this, k2 = arguments.length,
/* 判断宿主是否依附在 String.prototype 下 */
notInString = !isString(host) && isString(args);
if (
/* 2022-11-07 判断参数是否为format(String, {key: value} | [...] | 1, 2, 3, 4, 'a') */
k2 > 1
|| isSimplyType(args)
) {
args = iList2Array(arguments);
if (notInString) {
// 获取处理对象字符串
host = args.shift();
if (args.length == 1 && !isSimplyType(args[0]) /* 非基本类型 */) args = args.shift();
}
/* 功能分流 处理 caller('?............? ?', 1, 2, 3) */
if (/[?]/.test(host) && isArray(args))
// return
host = TextFormat(host, args);
}
args || (args = {});
var has = !!args.now;
merge(args, iInnerFunx);
args._groups__ = {};
// 替换字符串内参数,区间等
var ret = (host + SPACE).replace(rFormat, iReplace.bind(args));
delete args._groups__;
has || (delete args.now);
return ret;
}
/**
* @see rFormat
* @returns String
*/
function iReplace(source /*正则匹配的字符串*/, a /*开始取值范围*/, z /*结束*/,
arg /*属性 [arg]*/, prpo/* {arg1}, {expr...} */,
list /*数组 [a, b, c]*/,
attr /*属性名称 attr=? 替换?为attr对应的属性值 配合后面 eq*/, eq /*等号*/,
_if, _true, _false
) {
var args = this, _G = args._groups__;
if (_G && source in _G) return _G[source];
// 判断是否为数值
if (/^\d+$/.test(a + z)) {
return between(a, z);
}
/* 处理类似三目运算 exp(?)true(:)fasle `{true|false|props, value1, value2}` */
if (_if) {
return _GetExp2funcValue(
_GetExp2funcValue(_if, args)
? _true
: _false,
args
);
}
var val;
/*是否为数组 处理 `[first, ...]`*/
if (list) {
list = iSplit(list, rFormatSp);
/* [first, 2, 3, ...] first instanceof Function ? first(2, 3, 4,...) */
val = isFunction(args[list[0]])
?
args[list.shift()].apply(args, list)
:
list[between(0, list.length - 1)];
return val;
}
var key = prpo || arg || attr;
attr || (attr = SPACE, eq || (eq = SPACE));
if (args && key) {
var r = Math.random();
val = _GetExp2funcValue(key, args, r);
return val == r ? source : attr + eq + val;
}
_G[source] = source;
return source;
}
/**
* 隐藏属性格式化输出
* @param {Array|String} data 如果是String 'attr[,|;]attr'
* @param {String} split 默认为 '/'
*/
function StringMap(data, split) {
if (isString(data)) {
data = iSplit(data, split || /,|\||;/)
}
var list = [], map = {};
each(data, function (k, v, host, map) {
map[k] = v;
host.push(iStringFormat('{!{0},,{0}}', v));
}, list, this.map = map);
this.$mode = list.join(this.split = (split || '/'));
this.$data = {};
}
StringMap.prototype.data = function (mode) {
if (isNil(mode)) return this.$data;
let ret = {};
each(mode.split(this.split), function (k, v, map, ret) {
ret[map[k]] = v;
}, this.map, ret)
return ret;
}
StringMap.prototype.toString = function (data) {
data = data || {};
merge(data, this.$data);
merge(this.$data, data, true);
return iStringFormat(this.$mode, data)
}
module.exports = { format: iStringFormat, between, StringMap }