oukunqing

原生JS写的仿C#的字符串format函数,在此基础上又增加了便于JS使用的字面量对象参数,且字面量对象可以嵌套调用。

参照C#中的规则,调用的时候会检测字符串格式,如果字符串格式不规范,或者传入的参数为null或undefined,则抛出异常,并且加入了console.trace,方便查找错误。

有了这个format函数,js拼接字符串的时候就方便多了。

源代码:

!function () {
    if (typeof String.prototype.format === \'function\') {
        return false;
    }
    var isUndefined = function(o){
            return typeof o === \'undefined\';
        },
        isNullOrUndefined = function(o){
            return typeof o === \'undefined\' || o === null;
        },
        throwFormatError = function (msg, str, args) {
            try {
                console.trace();
                if (typeof str !== \'undefined\') {
                    console.log(\'str:\r\n\t\', str, \'\r\nargs:\r\n\t\', args);
                }
            } catch (e) { }
            throw new Error(msg);
        },
        formatNumberZero = function (arv, arn) {
            var arr = [], idx = arn.length - 1;
            for (var i = arv.length - 1; i >= 0; i--) {
                arr.push(arv[i] === \'0\' ? (idx >= 0 ? arn[idx] : arv[i]) : (function () { ++idx; return arv[i]; })());
                idx--;
            }
            for (var i = idx; i >= 0; i--) {
                arr.push(arn[i]);
            }
            arr = arr.reverse();
            return arr.join(\'\');
        },
        formatNumberSwitch = function (v, f, n, dn, err, str, args) {
            var fu = f.toUpperCase();
            if (typeof dn[1] === \'undefined\' && (fu === \'C\' || fu === \'F\')) {
                dn[1] = \'\';
                v += n > 0 ? \'.\' : \'\';
            }
            switch (fu) {
                case \'C\':
                    vc = \'¥\' + v;
                    var m = dn[0].length % 3;
                    if (dn[0].length > 3) {
                        v = vc.substr(0, m + 1);
                        var pos = m + 1;
                        while (pos < dn[0].length - 1) {
                            v += \',\' + vc.substr(pos, 3);
                            pos += 3;
                        }
                        v += vc.substr(pos);
                    } else {
                        v = vc;
                    }
                    for (var i = 0, c = n - (dn[1]).length; i < c; i++) { v += \'0\'; }
                    break;
                case \'D\':
                    if (/([.])/g.test(v)) {
                        throwFormatError(err[3], str, args);
                    }
                    for (var i = 0, c = n - (\'\' + v).length; i < c; i++) { v = \'0\' + v; }
                    break;
                case \'E\':
                    var n = dn[0].length - 1, fn = parseInt((\'\' + v).substr(0, 1), 10), num = Math.pow(10, n), e = Math.pow(10, 5);
                    var cn = (Math.round((v - num) / num * e) / e + \'\').split(\'.\')[1]||\'\', ln = \'\';
                    for (var i = (\'\' + cn).length; i < 5; i++) { cn += \'0\'; }
                    for (var i = (\'\' + n).length; i < 3; i++) { n = \'0\' + n; }
                    v = fn + \'.\' + cn + f + \'+\' + n;
                    break;
                case \'F\':
                    for (var i = 0, c = n - dn[1].length; i < c; i++) { v += \'0\'; }
                    break;
            }
            return v;
        },
        formatNumber = function (mv, v, err, str, args) {
            if (!/[:]/g.test(mv)) {
                return v;
            }
            var isNum = typeof v === \'number\', sc = mv.match(/(:)/g).length;
            if (sc > 1) {
                if (isNum) {
                    var nv = Math.round(v, 10), pos = mv.indexOf(\':\'), arv = mv.substr(pos + 1).split(\'\'), arn = (\'\' + nv).split(\'\');
                    v = formatNumberZero(arv, arn);
                } else {
                    v = mv.substr(mv.indexOf(\':\') + 1);
                }
            } else if (isNum) {
                var ss = mv.split(\':\')[1], p1 = /([CDEFG])/ig, p2 = /([A-Z])/ig, p3 = /^([CDEFG][\d]+)$/ig, p4 = /^([A-Z]{1}[\d]+)$/ig;
                if ((ss.length === 1 && p1.test(ss)) || (ss.length >= 2 && p3.test(ss))) {
                    var f = ss.substr(0, 1), n = parseInt(ss.substr(1), 10) || (f.toUpperCase() === \'D\' ? 0 : 2), dn = (\'\' + v).split(\'.\');
                    v = formatNumberSwitch(v, f, n, dn, err, str, args);
                } else if ((ss.length === 1 && p2.test(ss)) || (ss.length >= 2 && p4.test(ss))) {
                    throwFormatError(err[3], str, args);
                } else if (/([0]+)/g.test(ss)) {
                    var nv = Math.round(v, 10), arv = ss.split(\'\'), arn = (\'\' + nv).split(\'\');
                    v = formatNumberZero(arv, arn);
                } else {
                    v = ss;
                }
            }
            return v;
        },
        distillObjVal = function (key, obj, err, vals) {
            var v;
            if (typeof obj[key] !== \'undefined\') {
                v = obj[key];
            } else if (key.indexOf(\'.\') > 0 || key.indexOf(\'|\') > 0) {
                //嵌套对象,格式: obj.key.key|dv(默认值,因某些key可能不存在或允许为空)
                var arr = key.split(\'|\'), dv = arr[1], ks = arr[0].split(\'.\'), o = obj;
                //console.log(\'o: \', o, \', ks: \', ks, \', dv: \', dv);
                for (var i in ks) {
                    if(typeof o === \'object\'){
                        o = o[ks[i]], v = o;
                    }
                    if (typeof o === \'undefined\') {
                        v = typeof dv != \'undefined\' ? dv : throwFormatError(err[0], s, vals);
                    }
                }
            } else {
                throwFormatError(err[0], s, vals);
            }
            return v;
        };

    String.prototype.format = function (args) {
        var s = this, vals = [], rst = [], pattern = /({|})/g, ms = s.match(pattern);
        if (null === ms) {
            return s.toString() || s;
        }
        var err = [\'输入字符串的格式不正确。\', \'索引(从零开始)必须大于或等于零,且小于参数列表的大小。\',
            \'值不能为null(或undefined)。\', \'格式说明符无效。\'];

        if (arguments.length > 1) {
            for (var i = 0, c = arguments.length; i < c; i++) {
                if (arguments[i] !== undefined && arguments[i] !== null) {
                    vals.push(arguments[i]);
                } else {
                    var err = err[2] + \'第\' + (i + 1) + \'个参数值为:\' + arguments[i];
                    throwFormatError(err, s, args);
                }
            }
        } else if (Object.prototype.toString.call(args) === \'[object Array]\') {
            vals = args;
        } else if (args != undefined && args != null) {
            vals.push(args);
        }
        if (ms.length % 2 !== 0) {
            throwFormatError(err[0], s, vals);
        }
        var matchs = s.match(/({+[-\d]+(:[\D\d]*?)*?}+)|({+([\D]*?|[:\d]*?)}+)|({+([\w\.\|]*?)}+)|([{]{1,2}[\w]*?)|([\w]*?[}]{1,2})/g);
        if (null === matchs) {
            return s.toString() || s;
        }
        var len = vals.length, mc = matchs.length, isObject = typeof vals[0] === \'object\', obj = isObject ? vals[0] : {};

        for (var i = 0; i < mc; i++) {
            var m = matchs[i], mv = m.replace(pattern, \'\'), p = s.indexOf(m), idx = parseInt(mv, 10);
            var c = /{/g.test(m) ? m.match(/{/g).length : 0, d = /}/g.test(m) ? m.match(/}/g).length : 0;
            if ((c + d) % 2 != 0) {
                throwFormatError(err[0], s, vals);
            }
            var m2 = m.replace(/{{/g, \'{\').replace(/}}/g, \'}\');
            var odd = c % 2 != 0 || d % 2 != 0, single = c <= 2 && d <= 2;

            if (!isNaN(idx)) {
                var v = formatNumber(mv, vals[idx], err, s, vals);
                if (typeof v === \'boolean\' && !v) {
                    return false;
                }
                if (/^-\d$/g.test(mv) && odd) {
                    throwFormatError(err[0], s, vals);
                } else if (idx >= len) {
                    throwFormatError(err[1], s, vals);
                } else if (typeof v === \'undefined\' || v === null) {
                    throwFormatError(err[2], s, vals);
                }
                rst.push(s.substr(0, p) + (c > 1 || d > 1 ? (c % 2 != 0 || d % 2 != 0 ? m2.replace(\'{\' + idx + \'}\', v) : m2) : v));
            } else if (odd) {
               if (c === 1 && d === 1) {
                    if (!isObject || !single) {
                        throwFormatError(err[0], s, vals);
                    }
                    v = distillObjVal(mv, obj, err, vals);
                    rst.push(s.substr(0, p) + (c > 1 || d > 1 ? (c % 2 !== 0 || d % 2 !== 0 ? m2.replace(\'{\' + idx + \'}\', v) : m2) : v));
                } else {
                    var mcs = m2.match(/({[\w\.\|]+})/g);
                    if (mcs != null && mcs.length > 0) {
                        rst.push(s.substr(0, p) + m2.replace(mcs[0], distillObjVal(mcs[0].replace(/({|})/g, \'\'), obj, err)));
                    } else {
                        throwFormatError(err[0], s, vals);
                    }
                }
            } else {
                rst.push(s.substr(0, p) + m2);
            }
            s = s.substr(p + m.length);
        }
        rst.push(s);

        return rst.join(\'\');
    };
    
    String.Format = String.format = function (s) {
        if (typeof s === \'string\') {
            var a = [], c = arguments.length;
            for (var i = 1; i < c; i++) {
                a.push(arguments[i]);
            }
            return s.format(a);
        }
        throwFormatError((typeof o) + \'.format is not a function\');
    };
}();

压缩后的代码:

eval(function(p,a,c,k,e,r){e=function(c){return(c<a?\'\':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!\'\'.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return\'\\w+\'};c=1};while(c--)if(k[c])p=p.replace(new RegExp(\'\\b\'+e(c)+\'\\b\',\'g\'),k[c]);return p}(\'!y(){6(q 11.14.T===\\'y\\'){u 1x}4 l=y(o){u q o===\\'G\\'},1M=y(o){u q o===\\'G\\'||o===L},x=y(a,b,c){1I{1r.1D();6(q b!==\\'G\\'){1r.1B(\\'1P:\\r\\n\\t\\',b,\\'\\r\\1R:\\r\\n\\t\\',c)}}1Q(e){}1N 1A 1S(a);},16=y(a,b){4 c=[],B=b.7-1;H(4 i=a.7-1;i>=0;i--){c.I(a[i]===\\'0\\'?(B>=0?b[B]:a[i]):(y(){++B;u a[i]})());B--}H(4 i=B;i>=0;i--){c.I(b[i])}c=c.1O();u c.1s(\\'\\')},1p=y(v,f,n,a,b,d,g){4 h=f.1o();6(q a[1]===\\'G\\'&&(h===\\'C\\'||h===\\'F\\')){a[1]=\\'\\';v+=n>0?\\'.\\':\\'\\'}1F(h){Y\\'C\\':U=\\'¥\\'+v;4 m=a[0].7%3;6(a[0].7>3){v=U.z(0,m+1);4 j=m+1;1H(j<a[0].7-1){v+=\\',\\'+U.z(j,3);j+=3}v+=U.z(j)}9{v=U}H(4 i=0,c=n-(a[1]).7;i<c;i++){v+=\\'0\\'}W;Y\\'D\\':6(/([.])/g.J(v)){x(b[3],d,g);}H(4 i=0,c=n-(\\'\\'+v).7;i<c;i++){v=\\'0\\'+v}W;Y\\'E\\':4 n=a[0].7-1,1k=1a((\\'\\'+v).z(0,1),10),15=Q.1q(10,n),e=Q.1q(10,5);4 k=(Q.17((v-15)/15*e)/e+\\'\\').K(\\'.\\')[1]||\\'\\',1E=\\'\\';H(4 i=(\\'\\'+k).7;i<5;i++){k+=\\'0\\'}H(4 i=(\\'\\'+n).7;i<3;i++){n=\\'0\\'+n}v=1k+\\'.\\'+k+f+\\'+\\'+n;W;Y\\'F\\':H(4 i=0,c=n-a[1].7;i<c;i++){v+=\\'0\\'}W}u v},1t=y(a,v,b,c,d){6(!/[:]/g.J(a)){u v}4 e=q v===\\'1G\\',1v=a.P(/(:)/g).7;6(1v>1){6(e){4 g=Q.17(v,10),1w=a.R(\\':\\'),V=a.z(1w+1).K(\\'\\'),12=(\\'\\'+g).K(\\'\\');v=16(V,12)}9{v=a.z(a.R(\\':\\')+1)}}9 6(e){4 h=a.K(\\':\\')[1],1i=/([1j])/X,1h=/([A-Z])/X,1n=/^([1j][\\d]+)$/X,1l=/^([A-Z]{1}[\\d]+)$/X;6((h.7===1&&1i.J(h))||(h.7>=2&&1n.J(h))){4 f=h.z(0,1),n=1a(h.z(1),10)||(f.1o()===\\'D\\'?0:2),1m=(\\'\\'+v).K(\\'.\\');v=1p(v,f,n,1m,b,c,d)}9 6((h.7===1&&1h.J(h))||(h.7>=2&&1l.J(h))){x(b[3],c,d);}9 6(/([0]+)/g.J(h)){4 g=Q.17(v,10),V=h.K(\\'\\'),12=(\\'\\'+g).K(\\'\\');v=16(V,12)}9{v=h}}u v},18=y(a,b,c,d){4 v;6(q b[a]!==\\'G\\'){v=b[a]}9 6(a.R(\\'.\\')>0||a.R(\\'|\\')>0){4 e=a.K(\\'|\\'),19=e[1],13=e[0].K(\\'.\\'),o=b;H(4 i 1z 13){6(q o===\\'1b\\'){o=o[13[i]],v=o}6(q o===\\'G\\'){v=q 19!=\\'G\\'?19:x(c[0],s,d);}}}9{x(c[0],s,d);}u v};11.14.T=y(a){4 s=1C,8=[],O=[],1c=/({|})/g,1d=s.P(1c);6(L===1d){u s.1e()||s}4 b=[\\'输入字符串的格式不正确。\\',\\'索引(从零开始)必须大于或等于零,且小于参数列表的大小。\\',\\'值不能为L(或G)。\\',\\'格式说明符无效。\\'];6(M.7>1){H(4 i=0,c=M.7;i<c;i++){6(M[i]!==G&&M[i]!==L){8.I(M[i])}9{4 b=b[2]+\\'第\\'+(i+1)+\\'个参数值为:\\'+M[i];x(b,s,a);}}}9 6(1J.14.1e.1K(a)===\\'[1b 1L]\\'){8=a}9 6(a!=G&&a!=L){8.I(a)}6(1d.7%2!==0){x(b[0],s,8);}4 e=s.P(/({+[-\\d]+(:[\\D\\d]*?)*?}+)|({+([\\D]*?|[:\\d]*?)}+)|({+([\\w\\.\\|]*?)}+)|([{]{1,2}[\\w]*?)|([\\w]*?[}]{1,2})/g);6(L===e){u s.1e()||s}4 f=8.7,1u=e.7,1f=q 8[0]===\\'1b\\',1g=1f?8[0]:{};H(4 i=0;i<1u;i++){4 m=e[i],S=m.N(1c,\\'\\'),p=s.R(m),B=1a(S,10);4 c=/{/g.J(m)?m.P(/{/g).7:0,d=/}/g.J(m)?m.P(/}/g).7:0;6((c+d)%2!=0){x(b[0],s,8);}4 g=m.N(/{{/g,\\'{\\').N(/}}/g,\\'}\\');4 h=c%2!=0||d%2!=0,1y=c<=2&&d<=2;6(!1T(B)){4 v=1t(S,8[B],b,s,8);6(q v===\\'1U\\'&&!v){u 1x}6(/^-\\d$/g.J(S)&&h){x(b[0],s,8);}9 6(B>=f){x(b[1],s,8);}9 6(q v===\\'G\\'||v===L){x(b[2],s,8);}O.I(s.z(0,p)+(c>1||d>1?(c%2!=0||d%2!=0?g.N(\\'{\\'+B+\\'}\\',v):g):v))}9 6(h){6(c===1&&d===1){6(!1f||!1y){x(b[0],s,8);}v=18(S,1g,b,8);O.I(s.z(0,p)+(c>1||d>1?(c%2!==0||d%2!==0?g.N(\\'{\\'+B+\\'}\\',v):g):v))}9{4 j=g.P(/({[\\w\\.\\|]+})/g);6(j!=L&&j.7>0){O.I(s.z(0,p)+g.N(j[0],18(j[0].N(/({|})/g,\\'\\'),1g,b)))}9{x(b[0],s,8);}}}9{O.I(s.z(0,p)+g)}s=s.z(p+m.7)}O.I(s);u O.1s(\\'\\')};11.1V=11.T=y(s){6(q s===\\'1W\\'){4 a=[],c=M.7;H(4 i=1;i<c;i++){a.I(M[i])}u s.T(a)}x((q o)+\\'.T 1X 1Y a y\\');}}();\',62,123,\'||||var||if|length|vals|else|||||||||||||||||typeof||||return|||throwFormatError|function|substr||idx|||||undefined|for|push|test|split|null|arguments|replace|rst|match|Math|indexOf|mv|format|vc|arv|break|ig|case|||String|arn|ks|prototype|num|formatNumberZero|round|distillObjVal|dv|parseInt|object|pattern|ms|toString|isObject|obj|p2|p1|CDEFG|fn|p4|dn|p3|toUpperCase|formatNumberSwitch|pow|console|join|formatNumber|mc|sc|pos|false|single|in|new|log|this|trace|ln|switch|number|while|try|Object|call|Array|isNullOrUndefined|throw|reverse|str|catch|nargs|Error|isNaN|boolean|Format|string|is|not\'.split(\'|\'),0,{}))

  

示例:

//常规格式化
console.log(\'abc\'.format(20));

console.log(\'{0:D4}\'.format(20));

console.log(String.format(\'{0:D4}\', 20));
console.log(String.Format(\'{0:e4}\', 20));

var str = \'你好:{0},这是用{0}写的一个仿C#的{1}函数\';

console.log(str.format([\'JS\', \'format\']));
console.log(str.format(\'JS\', \'format\'));

console.log("{0}{{正则{0:F5}{{表达式}}{1:F4}".format(123.5, 12.5))

console.log("{0}{{正则{0:F5}{{表达式}}{1:0D12}".format(123.5, 2))

console.log("{0:00:00:00}".format(1234567));

console.log("{0:0000年00月00日 00:00:00}".format(20160824172215));

console.log("{0:0000年00月00日}".format(20160824));

console.log("{0:0DF5}".format(1234567));
console.log("{0:0000}".format(2));

console.log(\'<tr lang="{{id:{0},pid:{1},level:{2}}}">\'.format([1, 2, 0]));


//增加了字面量对象参数,这个字面量对象参数必须放在参数的第0个位置,如果加了字面量对象参数,则数字参数索引必须从1开始

var data = { id: 123, name: \'张三\', obj: { num: 321, con: { val: \'acc\' } } };
var s = \'Id:{id}, Val:{obj.con.val3|asd}, Code:{1}, Name:{name}\'.format(data, \'Test\');
console.log(s);
var s = \'Id:{id}, Val:{obj.con.val3|12}, Code:{1}, Name:{name}\'.format(data, \'Test\');
console.log(s);
var s = \'Id:{id}, Val:{obj.con.val|ABC}, Code:{1}, Num:{obj.num}, Name:{name}\'.format(data, \'Test\');
console.log(s);

var s = \'lang="{{id:{obj.id},pid:{obj.pid},level:{obj.level}}}"\'.format({ obj: { id: 12, pid: 1, level: 1 } });
console.log(s);
var s = \'lang="{{id:{id},pid:{pid},level:{level}}}"\'.format({ id: 12, pid: 1, level: 1 });
console.log(s);
var s = \'lang="{{id:{id},pid:{pid},level:{level|0}}}"\'.format({ id: 12, pid: 0 });
console.log(s);

 

//增加 String.format 和 String.Format 方法
var str = \'{0:D4},{1}\';
console.log(String.format(str, 20, \'abc\'));
console.log(String.Format(str, 20, \'abc\'));

 

示例结果:

abc
0020
0020
2.00000e+001
你好:JS,这是用JS写的一个仿C#的format函数
你好:JS,这是用JS写的一个仿C#的format函数
123.5{正则123.50000{表达式}12.5000
123.5{正则123.50000{表达式}2D12
123:45:67
2016年08月24日 17:22:15
2016年08月24日
1234567DF5
0002
<tr lang="{id:1,pid:2,level:0}">

Id:123, Val:asd, Code:Test, Name:张三
Id:123, Val:12, Code:Test, Name:张三
Id:123, Val:acc, Code:Test, Num:321, Name:张三
lang="{id:12,pid:1,level:1}"
lang="{id:12,pid:1,level:1}"
lang="{id:12,pid:0,level:0}"
0020,abc
0020,abc

分类:

技术点:

相关文章: