Commit | Line | Data |
bb66f8a1 |
1 | // from https://raw.github.com/kvz/phpjs/master/functions/strings/sprintf.js\r |
2 | function sprintf () {\r |
3 | // http://kevin.vanzonneveld.net\r |
4 | // + original by: Ash Searle (http://hexmen.com/blog/)\r |
5 | // + namespaced by: Michael White (http://getsprink.com)\r |
6 | // + tweaked by: Jack\r |
7 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\r |
8 | // + input by: Paulo Freitas\r |
9 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\r |
10 | // + input by: Brett Zamir (http://brett-zamir.me)\r |
11 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\r |
12 | // + improved by: Dj\r |
13 | // * example 1: sprintf("%01.2f", 123.1);\r |
14 | // * returns 1: 123.10\r |
15 | // * example 2: sprintf("[%10s]", 'monkey');\r |
16 | // * returns 2: '[ monkey]'\r |
17 | // * example 3: sprintf("[%'#10s]", 'monkey');\r |
18 | // * returns 3: '[####monkey]'\r |
19 | var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g;\r |
20 | var a = arguments,\r |
21 | i = 0,\r |
22 | format = a[i++];\r |
23 | \r |
24 | // pad()\r |
25 | var pad = function (str, len, chr, leftJustify) {\r |
26 | if (!chr) {\r |
27 | chr = ' ';\r |
28 | }\r |
29 | var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);\r |
30 | return leftJustify ? str + padding : padding + str;\r |
31 | };\r |
32 | \r |
33 | // justify()\r |
34 | var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {\r |
35 | var diff = minWidth - value.length;\r |
36 | if (diff > 0) {\r |
37 | if (leftJustify || !zeroPad) {\r |
38 | value = pad(value, minWidth, customPadChar, leftJustify);\r |
39 | } else {\r |
40 | value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);\r |
41 | }\r |
42 | }\r |
43 | return value;\r |
44 | };\r |
45 | \r |
46 | // formatBaseX()\r |
47 | var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {\r |
48 | // Note: casts negative numbers to positive ones\r |
49 | var number = value >>> 0;\r |
50 | prefix = prefix && number && {\r |
51 | '2': '0b',\r |
52 | '8': '0',\r |
53 | '16': '0x'\r |
54 | }[base] || '';\r |
55 | value = prefix + pad(number.toString(base), precision || 0, '0', false);\r |
56 | return justify(value, prefix, leftJustify, minWidth, zeroPad);\r |
57 | };\r |
58 | \r |
59 | // formatString()\r |
60 | var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {\r |
61 | if (precision != null) {\r |
62 | value = value.slice(0, precision);\r |
63 | }\r |
64 | return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);\r |
65 | };\r |
66 | \r |
67 | // doFormat()\r |
68 | var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {\r |
69 | var number;\r |
70 | var prefix;\r |
71 | var method;\r |
72 | var textTransform;\r |
73 | var value;\r |
74 | \r |
75 | if (substring == '%%') {\r |
76 | return '%';\r |
77 | }\r |
78 | \r |
79 | // parse flags\r |
80 | var leftJustify = false,\r |
81 | positivePrefix = '',\r |
82 | zeroPad = false,\r |
83 | prefixBaseX = false,\r |
84 | customPadChar = ' ';\r |
85 | var flagsl = flags.length;\r |
86 | for (var j = 0; flags && j < flagsl; j++) {\r |
87 | switch (flags.charAt(j)) {\r |
88 | case ' ':\r |
89 | positivePrefix = ' ';\r |
90 | break;\r |
91 | case '+':\r |
92 | positivePrefix = '+';\r |
93 | break;\r |
94 | case '-':\r |
95 | leftJustify = true;\r |
96 | break;\r |
97 | case "'":\r |
98 | customPadChar = flags.charAt(j + 1);\r |
99 | break;\r |
100 | case '0':\r |
101 | zeroPad = true;\r |
102 | break;\r |
103 | case '#':\r |
104 | prefixBaseX = true;\r |
105 | break;\r |
106 | }\r |
107 | }\r |
108 | \r |
109 | // parameters may be null, undefined, empty-string or real valued\r |
110 | // we want to ignore null, undefined and empty-string values\r |
111 | if (!minWidth) {\r |
112 | minWidth = 0;\r |
113 | } else if (minWidth == '*') {\r |
114 | minWidth = +a[i++];\r |
115 | } else if (minWidth.charAt(0) == '*') {\r |
116 | minWidth = +a[minWidth.slice(1, -1)];\r |
117 | } else {\r |
118 | minWidth = +minWidth;\r |
119 | }\r |
120 | \r |
121 | // Note: undocumented perl feature:\r |
122 | if (minWidth < 0) {\r |
123 | minWidth = -minWidth;\r |
124 | leftJustify = true;\r |
125 | }\r |
126 | \r |
127 | if (!isFinite(minWidth)) {\r |
128 | throw new Error('sprintf: (minimum-)width must be finite');\r |
129 | }\r |
130 | \r |
131 | if (!precision) {\r |
132 | precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined;\r |
133 | } else if (precision == '*') {\r |
134 | precision = +a[i++];\r |
135 | } else if (precision.charAt(0) == '*') {\r |
136 | precision = +a[precision.slice(1, -1)];\r |
137 | } else {\r |
138 | precision = +precision;\r |
139 | }\r |
140 | \r |
141 | // grab value using valueIndex if required?\r |
142 | value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];\r |
143 | \r |
144 | switch (type) {\r |
145 | case 's':\r |
146 | return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);\r |
147 | case 'c':\r |
148 | return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);\r |
149 | case 'b':\r |
150 | return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);\r |
151 | case 'o':\r |
152 | return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);\r |
153 | case 'x':\r |
154 | return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);\r |
155 | case 'X':\r |
156 | return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();\r |
157 | case 'u':\r |
158 | return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);\r |
159 | case 'i':\r |
160 | case 'd':\r |
161 | number = (+value) | 0;\r |
162 | prefix = number < 0 ? '-' : positivePrefix;\r |
163 | value = prefix + pad(String(Math.abs(number)), precision, '0', false);\r |
164 | return justify(value, prefix, leftJustify, minWidth, zeroPad);\r |
165 | case 'e':\r |
166 | case 'E':\r |
167 | case 'f': // Should handle locales (as per setlocale)\r |
168 | case 'F':\r |
169 | case 'g':\r |
170 | case 'G':\r |
171 | number = +value;\r |
172 | prefix = number < 0 ? '-' : positivePrefix;\r |
173 | method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];\r |
174 | textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];\r |
175 | value = prefix + Math.abs(number)[method](precision);\r |
176 | return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();\r |
177 | default:\r |
178 | return substring;\r |
179 | }\r |
180 | };\r |
181 | \r |
182 | return format.replace(regex, doFormat);\r |
183 | }\r |