StringFormatter,一个javascript编写的字符串格式化库
StringFormatter JS
是一个js编写的可扩展的javascript字符串格式化库,它的功能远远超出了ECMA6标准所规定的字符串格式化规则。
它的内置转换功能如下:
- 字符串
- 所有数值类型包括整数,小数,十六进制,八进制,百分比和金融符号以及对
NaN
和Infinity
的特殊处理 - 布尔型
- 数组和对象
- 函数
- 日期/时间
- 应用CSS样式
- 有条件的格式化
举一个例子:
format("The time is {Date:{format:'hh:mm'}} and I have {number:{fixed: 2,currency:'$'}}.",
new Date('2015-03-13T10:01:27.284Z'),
50.25)
返回结果如下:
The time is 10:01 and I have $50.25.
例子
格式化 | 结果 |
---|---|
Format | Result |
format('{number}',2) | 2 |
format('{number: {fixed: 2}}',2) | 2.00 |
format('{number: {precision: 3}}',2) | 2.00 |
format('{number: {as: '%'}}',2) | 2% |
format('{number: {as: 'h'}}',255) | 0xff |
format('{number: {as: 'h'}}',-255) | -0xff |
format('{number: {as: 'o'}}',255) | 0377 |
format('{number: {as: 'o'}}',-255) | -0377 |
format('{number: {as: 'b'}}',255) | 11111111 |
format('{number: {as: 'b'}}',-255) | -11111111 |
format('{number: {ifNaN: 'Not A Number'}}',null) | Not A Number |
format('{number: {ifInfinity: 'Bigger Than Google<br> blog.Gavinzh.com!'}}',null) | Bigger Than Google blog.Gavinzh.com! |
format('{number: {currency: '$', fixed:2}}',255) | $255.00 |
format('{number: {currency: '$', fixed:2}}',-255) | $-255.00 |
format('{number: {currency: '$', fixed:2, style:(@value < 0 ? 'color:red' : null)}}',-255) | $-255.00 |
format('{number: {currency: '$', fixed:2, accounting: true, style:(@value < 0 ? 'color:red' : null)}}',-255) | <span style='color:red'>($255.00)</span> |
format('{boolean}',true) | true |
format('{boolean: {as: 'string'}}',true) | yes |
format('{boolean: {as: 'string', style:(@value ? 'color:green' : 'color:red')}}',true) | <span style='color:green'>no</span> |
format('{boolean: {as: 'number'}}',true) | 1 |
format('{boolean}',2) | true |
format('{boolean}',false) | false |
format('{boolean: {as: 'string', style:(@value ? 'color:green' : 'color:red')}}',false) | <span style='color:red'>no</span> |
format('{boolean: {as: 'number'}}',false) | 0 |
format('{boolean}',null) | false |
format('{Array}',["a","b","c"]) | a,b,c |
format('{Array : {delimiter: ';'}}',["a","b","c"]) | a;b;c |
format('{Array : {container: ['[',']']}}',["a","b","c"]) | [a,b,c] |
format('{Array : {container: ['[',']'], quote:true}}',["a","b","c"]) | ['a','b','c'] |
format('{Array : {include: [0,2]}}',["a","b","c"]) | a,c |
format('{Array : {exclude: [0,2]}}',["a","b","c"]) | b |
format('{Array : {matchValue: /c/}}',["a","b","c"]) | c |
format('{Array}',[{"v1":"one"},2]) | {"v1":"one"},2 |
format('{Object}',{"v1":"one","v2":"two"}) | {"v1":"one","v2":"two"} |
format('{Object: {include: ['v1']}}',{"v1":"one","v2":"two"}) | {"v1":"one"} |
format('{Object: {exclude: ['v1']}}',{"v1":"one","v2":"two"}) | {"v2":"two"} |
format('{Object: {matchValue: /one/}}',{"v1":"one","v2":"two"}) | {"v1":"one"} |
format('{Date: {format: 'dddd, MMMM Do, YYYY'}}',new Date("2005-08-01T17:01:01.500Z")) | Monday, August 1st, 2005 |
format('{Date: {format: 'YYYY MM DD hh:mm:ss:SSS A'}}',new Date("2005-08-01T17:01:01.500Z")) | 2005 08 01 01:01:01:500 PM |
format('{Date: {format: 'U'}}',new Date("2005-08-01T17:01:01.500Z")) | Mon, 01 Aug 2005 17:01:01 UTC |
format('{Date: {format: 'G'}}',new Date("2005-08-01T17:01:01.500Z")) | Mon, 01 Aug 2005 17:01:01 GMT |
format('{Date: {format: 'I'}}',new Date("2005-08-01T17:01:01.500Z")) | 2005-08-01T17:01:01.500Z |
format('{Date: {format: 'L'}}',new Date("2005-08-01T17:01:01.500Z")) | 8/1/2005, 1:01:01 PM |
format('{Function: {format: 'N'}}',function MyFunction(arg1,arg2) { return 1;}) | MyFunction |
format('{Function: {format: 'N'}}',function (arg1,arg2) { return 1;}) | anonymous |
format('{Function: {format: 'n'}}',function (arg1,arg2) { return 1;}) | |
format('{Function: {format: 'h'}}',function MyFunction(arg1,arg2) { return 1;}) | function MyFunction(arg1,arg2) |
format('{Function: {format: 'a'}}',function MyFunction(arg1,arg2) { return 1;}) | arg1, arg2 |
format('{Function: {format: 'l'}}',function MyFunction(arg1,arg2) { return 1;}) | 2 |
format('{Function: {format: 'b'}}',function MyFunction(arg1,arg2) { return 1;}) | return 1; |
通用使用方法
StringFormatter
是一个单例化的类,他会在stringformatter.js
加载完成后自动实例化。
字符串的格式化是通过函数调用完成的。
StringFormatter.format(<format string>,vargs...).
你还有一个选择,当使用StringFormatter.polyfill()
方法后,String字符串类将会被加入一个原型方法用来支持<format string>.format(vargs...).
。
这个<format string>
可以是任何合法的javascript字符串,同时,也支持JSON对象:
eg:
{number: {fixed:3, ifNaN:'', currency: '$', accounting:true}}
特殊的类型格式化
字符串
字符串string
没有特别的用法,只需要使用{string}
即可。
数值类型
数值number
可以采用一下格式参数:
- fixed:
<number>
- 返回一个带固定长度小数的字符串, e.g.number: {fixed: 2}}
. - precision: - 返回一个带指定精度数字的字符串, e.g.
{number: {precision: 2}}
. - ifNaN:
<string>
- 如果出现NaN
则用<string>
替换. - ifInfinity:
<string>
- 如果是无限值Infinity
则用<string>
代替. - as:
<char>
- 返回一个和<char>
有关系的格式化后的字符串. 支持<char>
值的char有:"%"
百分比,"h"
十六进制,"o"
八进制,"b"
二进制, e.g.{number: {as: "%", fixed:2}}
>>>##.##%
. - currency:
<char>
返回一个数值前面带金融符号<char>
. - accounting:
<boolean>
- 如果<boolean>===true
或者数值为负数,返回指定的字符串.
最后,{number}
是最基本的格式化格式。
布尔类型
布尔类型的特殊转换主要依靠as
来实现:
{boolean}
- 结果是 "true" or "false".{boolean: {as: "string"}}
- 结果是 "yes" or "no".{boolean: {as: "number"}}
- 结果是 "1" or "0".
在javascript中,有0,null,false,undefined
会被理解为false,其他会被理解为true。
对象类型
对象类型会被转为json字符串。
- include:
<Array>
- 返回的json字符串中的key都在<Array>
中. - exclude:
<Array>
- 返回的json字符串中的key都不在<Array>
中. - matchValue:
<RegExp>
- 返回的json字符串中的key都应在<RegExp>
正则中.
如果key是Object
,则会被当作object
。
数组类型
数组的格式化将会返回每一个对象。有以下配置参数:
- delimiter:
<string>
- 返回一个以<string>
分隔开的包含所有数组对象的字符串。 默认的分隔符是逗号","
[原文是空格,实际经测试是逗号] 。 - container:
[<start string>,<stop string>]
- 返回的字符串被<start string>
和<stop string>
所包裹. 默认的container是 ["",""]. - quote:
<boolean>
- 如果值是true,返回的每个元素都会被'
包裹. - include:
<Array>
- 如果数组中的元素在<Array>
中,才会被格式化出来. - exclude:
<Array>
- 如果数组元素不在<Array>
中,会被格式化. - matchValue:
<RegExp>
- 如果元素符合<RegExp>
正则,才会被格式化.
函数类型
'function'
类型会返回函数结果或者源码内容以及入参属性,它提供了一个属性format
来决定格式化的方式。
{function}
- 返回整个函数代码.{function: {format: "v"}}
- 返回函数的运行结果,这个方式仅当函数没有入参时才可以使用.{function: {format: "h"}}
- 返回函数定义的头部信息,例如他的名字和入参名.{function: {format: "a"}}
- 返回函数的入参名,不包含括号.{function: {format: "b"}}
- 返回函数内容,不包括大括号.{function: {format: "l"}}
- 返回入参的个数.{function: {format: "n"}}
- 返回函数的名字,如果是匿名函数就返回空.{function: {format: "N"}}
- 同小n,但当是匿名函数时返回 "anonymous".
一个例子, {function {format: "v n"}}
, 将会生成函数运行结果和这个函数的名字.
日期类型
Date 类型和 MomentJS format 的处理方式很像, 通过很少的条件生成指定格式的字符串。 格式化所用到的条件有: U, G, I, L, T, 会分别生成 UTC, GTM, ISO, Local, 和 Time 字符串. 被删除不用的条件有: e-E,w-WW,g-GGGG,x.
通用的日期格式化和函数的格式化很像,只有一个参数。 例如: {Date: {format: <string spec>}}
.
更多用法
分为三部分:
- 使用样式表
- 使用嵌入的条件表达式
- 垃圾回收
使用样式表
所有的类型格式化都提供了一个可选的样式参数, 例如. {number: {style: 'color:red'}}
. 如果提供了这个参数,返回的结果将会被<span>
包围,span中将包含所写的style。例如. <span style="color:red">3</span>
.
使用嵌入的条件表达式
任何的参数都可以包含这样的条件表达式(<condition> ? <result> : <else>)
. 这些表达式的条件可以调用这两种内容@value
or @arguments[i]
,其内容将是引入将要被格式化的数据。
标准的使用方法是: {number: {style: (@value < 0 : 'color:red')}}
<!--@value
will dereference to the value of the argument being processed for the specific format specification, i.e. if it occurs in the second format specification of a format string, then @value
will resolve to the 3rd argument to StringFormatter.format
, since the format string itself is the first argument.
@arguments[i]
will dereference to the argument in position i to 'StringFormatter.format'. This means that @arguments[0]
will actually dereference to the format string itself.
Through the use of conditionals and styles, standard numeric color coding can be achieved, e.g. {number: {style: (@value < 0 : 'color:red')}}
. Note, embedding the conditional within a string will not result in evaluation of the conditional, e.g. {number: {style: 'font-weight:bold;(@value < 0 : 'color:red')'}}
will not work.-->
注意: 表达式不会被缓存并且也不会通过垃圾回收,所以使用条件表达式能够提高内存的利用。
垃圾回收
垃圾回收是根据StringFormatter的属性元素所决定的。
- StringFormatter.cache - 如果一个对象被格式化为字符串了,那么这个对象将会被缓存,以后其他的对象和缓存的对象相同,将会使用缓存中对象的格式化字符串。
- StringFormatter.gcOn - 默认是true,如果想要禁止任何垃圾回收,就设置为false。
- StringFormatter.hits - 格式化的次数
- StringFormatter.gcThreshold = hits超过这个限额才会开始尝试垃圾回收。默认值是1000。
- StringFormatter.gcPurgeLessThan = 缓存中少于该值命中次数的对象将会被清除,默认是1。
- StringFormatter.gc() - 强制启动gc,即使没有到达gcThreshold
StringFormatter JS的扩展
通过StringFormatter.register(<constructor>,<function>,<name string>)
方法使得指定类可以自动使用 StringFormatter
。 如果没有提供 <function>
, 类constructor 应当提供一个原型方法 formatstring(formatSpec,formatter)'
which will be called using the value of the currently processing argument as the this
reference,formatSpec
as the spec currently being processed, and formatter
' as a reference to the StringFormatter
object. 如果 <constructor>
是一个匿名的类或者其他,那么应当提供一个 <name string>
.
自己的扩展应当保证能够正确的格式化指定类型,如果不能处理,应当抛出TypeError
。
这里有一个日期格式化的例子,我们使用了新的方法和类型,从而不影响Date的原型:
function DateFormat(spec,date) {
if(!(date instanceof Date)) {
throw new TypeError("Attempt to create DateFormat with non Date " + JSON.stringify(date));
}
this.spec = spec;
this.date = date;
}
DateFormat.prototype.format = function() {
if(!this.spec) {
return this.date.toString();
}
// see source code of StringFormatter.js for more detail
}
function dateFormatter(spec) {
var dateformat = new DateFormat(spec.format,this);
return dateformat.format();
}
StringFormatter.register(Date,dateFormatter,"Date");