sprintf.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /**
  2. @license
  3. sprintf.js from the php.js project - https://github.com/kvz/phpjs
  4. Directly from https://github.com/kvz/phpjs/blob/master/functions/strings/sprintf.js
  5. php.js is copyright 2012 Kevin van Zonneveld.
  6. Portions copyright Brett Zamir (http://brett-zamir.me), Kevin van Zonneveld
  7. (http://kevin.vanzonneveld.net), Onno Marsman, Theriault, Michael White
  8. (http://getsprink.com), Waldo Malqui Silva, Paulo Freitas, Jack, Jonas
  9. Raoni Soares Silva (http://www.jsfromhell.com), Philip Peterson, Legaev
  10. Andrey, Ates Goral (http://magnetiq.com), Alex, Ratheous, Martijn Wieringa,
  11. Rafa? Kukawski (http://blog.kukawski.pl), lmeyrick
  12. (https://sourceforge.net/projects/bcmath-js/), Nate, Philippe Baumann,
  13. Enrique Gonzalez, Webtoolkit.info (http://www.webtoolkit.info/), Carlos R.
  14. L. Rodrigues (http://www.jsfromhell.com), Ash Searle
  15. (http://hexmen.com/blog/), Jani Hartikainen, travc, Ole Vrijenhoek,
  16. Erkekjetter, Michael Grier, Rafa? Kukawski (http://kukawski.pl), Johnny
  17. Mast (http://www.phpvrouwen.nl), T.Wild, d3x,
  18. http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript,
  19. Rafa? Kukawski (http://blog.kukawski.pl/), stag019, pilus, WebDevHobo
  20. (http://webdevhobo.blogspot.com/), marrtins, GeekFG
  21. (http://geekfg.blogspot.com), Andrea Giammarchi
  22. (http://webreflection.blogspot.com), Arpad Ray (mailto:arpad@php.net),
  23. gorthaur, Paul Smith, Tim de Koning (http://www.kingsquare.nl), Joris, Oleg
  24. Eremeev, Steve Hilder, majak, gettimeofday, KELAN, Josh Fraser
  25. (http://onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/),
  26. Marc Palau, Martin
  27. (http://www.erlenwiese.de/), Breaking Par Consulting Inc
  28. (http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CFB006C45F7),
  29. Chris, Mirek Slugen, saulius, Alfonso Jimenez
  30. (http://www.alfonsojimenez.com), Diplom@t (http://difane.com/), felix,
  31. Mailfaker (http://www.weedem.fr/), Tyler Akins (http://rumkin.com), Caio
  32. Ariede (http://caioariede.com), Robin, Kankrelune
  33. (http://www.webfaktory.info/), Karol Kowalski, Imgen Tata
  34. (http://www.myipdf.com/), mdsjack (http://www.mdsjack.bo.it), Dreamer,
  35. Felix Geisendoerfer (http://www.debuggable.com/felix), Lars Fischer, AJ,
  36. David, Aman Gupta, Michael White, Public Domain
  37. (http://www.json.org/json2.js), Steven Levithan
  38. (http://blog.stevenlevithan.com), Sakimori, Pellentesque Malesuada,
  39. Thunder.m, Dj (http://phpjs.org/functions/htmlentities:425#comment_134018),
  40. Steve Clay, David James, Francois, class_exists, nobbler, T. Wild, Itsacon
  41. (http://www.itsacon.net/), date, Ole Vrijenhoek (http://www.nervous.nl/),
  42. Fox, Raphael (Ao RUDLER), Marco, noname, Mateusz "loonquawl" Zalega, Frank
  43. Forte, Arno, ger, mktime, john (http://www.jd-tech.net), Nick Kolosov
  44. (http://sammy.ru), marc andreu, Scott Cariss, Douglas Crockford
  45. (http://javascript.crockford.com), madipta, Slawomir Kaniecki,
  46. ReverseSyntax, Nathan, Alex Wilson, kenneth, Bayron Guevara, Adam Wallner
  47. (http://web2.bitbaro.hu/), paulo kuong, jmweb, Lincoln Ramsay, djmix,
  48. Pyerre, Jon Hohle, Thiago Mata (http://thiagomata.blog.com), lmeyrick
  49. (https://sourceforge.net/projects/bcmath-js/this.), Linuxworld, duncan,
  50. Gilbert, Sanjoy Roy, Shingo, sankai, Oskar Larsson H?gfeldt
  51. (http://oskar-lh.name/), Denny Wardhana, 0m3r, Everlasto, Subhasis Deb,
  52. josh, jd, Pier Paolo Ramon (http://www.mastersoup.com/), P, merabi, Soren
  53. Hansen, Eugene Bulkin (http://doubleaw.com/), Der Simon
  54. (http://innerdom.sourceforge.net/), echo is bad, Ozh, XoraX
  55. (http://www.xorax.info), EdorFaus, JB, J A R, Marc Jansen, Francesco, LH,
  56. Stoyan Kyosev (http://www.svest.org/), nord_ua, omid
  57. (http://phpjs.org/functions/380:380#comment_137122), Brad Touesnard, MeEtc
  58. (http://yass.meetcweb.com), Peter-Paul Koch
  59. (http://www.quirksmode.org/js/beat.html), Olivier Louvignes
  60. (http://mg-crea.com/), T0bsn, Tim Wiel, Bryan Elliott, Jalal Berrami,
  61. Martin, JT, David Randall, Thomas Beaucourt (http://www.webapp.fr), taith,
  62. vlado houba, Pierre-Luc Paour, Kristof Coomans (SCK-CEN Belgian Nucleair
  63. Research Centre), Martin Pool, Kirk Strobeck, Rick Waldron, Brant Messenger
  64. (http://www.brantmessenger.com/), Devan Penner-Woelk, Saulo Vallory, Wagner
  65. B. Soares, Artur Tchernychev, Valentina De Rosa, Jason Wong
  66. (http://carrot.org/), Christoph, Daniel Esteban, strftime, Mick@el, rezna,
  67. Simon Willison (http://simonwillison.net), Anton Ongson, Gabriel Paderni,
  68. Marco van Oort, penutbutterjelly, Philipp Lenssen, Bjorn Roesbeke
  69. (http://www.bjornroesbeke.be/), Bug?, Eric Nagel, Tomasz Wesolowski,
  70. Evertjan Garretsen, Bobby Drake, Blues (http://tech.bluesmoon.info/), Luke
  71. Godfrey, Pul, uestla, Alan C, Ulrich, Rafal Kukawski, Yves Sucaet,
  72. sowberry, Norman "zEh" Fuchs, hitwork, Zahlii, johnrembo, Nick Callen,
  73. Steven Levithan (stevenlevithan.com), ejsanders, Scott Baker, Brian Tafoya
  74. (http://www.premasolutions.com/), Philippe Jausions
  75. (http://pear.php.net/user/jausions), Aidan Lister
  76. (http://aidanlister.com/), Rob, e-mike, HKM, ChaosNo1, metjay, strcasecmp,
  77. strcmp, Taras Bogach, jpfle, Alexander Ermolaev
  78. (http://snippets.dzone.com/user/AlexanderErmolaev), DxGx, kilops, Orlando,
  79. dptr1988, Le Torbi, James (http://www.james-bell.co.uk/), Pedro Tainha
  80. (http://www.pedrotainha.com), James, Arnout Kazemier
  81. (http://www.3rd-Eden.com), Chris McMacken, gabriel paderni, Yannoo,
  82. FGFEmperor, baris ozdil, Tod Gentille, Greg Frazier, jakes, 3D-GRAF, Allan
  83. Jensen (http://www.winternet.no), Howard Yeend, Benjamin Lupton, davook,
  84. daniel airton wermann (http://wermann.com.br), Atli T¨®r, Maximusya, Ryan
  85. W Tenney (http://ryan.10e.us), Alexander M Beedie, fearphage
  86. (http://http/my.opera.com/fearphage/), Nathan Sepulveda, Victor, Matteo,
  87. Billy, stensi, Cord, Manish, T.J. Leahy, Riddler
  88. (http://www.frontierwebdev.com/), Rafa? Kukawski, FremyCompany, Matt
  89. Bradley, Tim de Koning, Luis Salazar (http://www.freaky-media.com/), Diogo
  90. Resende, Rival, Andrej Pavlovic, Garagoth, Le Torbi
  91. (http://www.letorbi.de/), Dino, Josep Sanz (http://www.ws3.es/), rem,
  92. Russell Walker (http://www.nbill.co.uk/), Jamie Beck
  93. (http://www.terabit.ca/), setcookie, Michael, YUI Library:
  94. http://developer.yahoo.com/yui/docs/YAHOO.util.DateLocale.html, Blues at
  95. http://hacks.bluesmoon.info/strftime/strftime.js, Ben
  96. (http://benblume.co.uk/), DtTvB
  97. (http://dt.in.th/2008-09-16.string-length-in-bytes.html), Andreas, William,
  98. meo, incidence, Cagri Ekin, Amirouche, Amir Habibi
  99. (http://www.residence-mixte.com/), Luke Smith (http://lucassmith.name),
  100. Kheang Hok Chin (http://www.distantia.ca/), Jay Klehr, Lorenzo Pisani,
  101. Tony, Yen-Wei Liu, Greenseed, mk.keck, Leslie Hoare, dude, booeyOH, Ben
  102. Bryan
  103. Licensed under the MIT (MIT-LICENSE.txt) license.
  104. Permission is hereby granted, free of charge, to any person obtaining a
  105. copy of this software and associated documentation files (the
  106. "Software"), to deal in the Software without restriction, including
  107. without limitation the rights to use, copy, modify, merge, publish,
  108. distribute, sublicense, and/or sell copies of the Software, and to
  109. permit persons to whom the Software is furnished to do so, subject to
  110. the following conditions:
  111. The above copyright notice and this permission notice shall be included
  112. in all copies or substantial portions of the Software.
  113. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  114. OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  115. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  116. IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES
  117. OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  118. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  119. OTHER DEALINGS IN THE SOFTWARE.
  120. */
  121. /*global define*/
  122. define(function() {
  123. function sprintf () {
  124. // http://kevin.vanzonneveld.net
  125. // + original by: Ash Searle (http://hexmen.com/blog/)
  126. // + namespaced by: Michael White (http://getsprink.com)
  127. // + tweaked by: Jack
  128. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  129. // + input by: Paulo Freitas
  130. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  131. // + input by: Brett Zamir (http://brett-zamir.me)
  132. // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  133. // + improved by: Dj
  134. // + improved by: Allidylls
  135. // * example 1: sprintf("%01.2f", 123.1);
  136. // * returns 1: 123.10
  137. // * example 2: sprintf("[%10s]", 'monkey');
  138. // * returns 2: '[ monkey]'
  139. // * example 3: sprintf("[%'#10s]", 'monkey');
  140. // * returns 3: '[####monkey]'
  141. // * example 4: sprintf("%d", 123456789012345);
  142. // * returns 4: '123456789012345'
  143. var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g;
  144. var a = arguments,
  145. i = 0,
  146. format = a[i++];
  147. // pad()
  148. var pad = function (str, len, chr, leftJustify) {
  149. if (!chr) {
  150. chr = ' ';
  151. }
  152. var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
  153. return leftJustify ? str + padding : padding + str;
  154. };
  155. // justify()
  156. var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
  157. var diff = minWidth - value.length;
  158. if (diff > 0) {
  159. if (leftJustify || !zeroPad) {
  160. value = pad(value, minWidth, customPadChar, leftJustify);
  161. } else {
  162. value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
  163. }
  164. }
  165. return value;
  166. };
  167. // formatBaseX()
  168. var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
  169. // Note: casts negative numbers to positive ones
  170. var number = value >>> 0;
  171. prefix = prefix && number && {
  172. '2': '0b',
  173. '8': '0',
  174. '16': '0x'
  175. }[base] || '';
  176. value = prefix + pad(number.toString(base), precision || 0, '0', false);
  177. return justify(value, prefix, leftJustify, minWidth, zeroPad);
  178. };
  179. // formatString()
  180. var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
  181. if (precision != null) {
  182. value = value.slice(0, precision);
  183. }
  184. return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
  185. };
  186. // doFormat()
  187. var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {
  188. var number;
  189. var prefix;
  190. var method;
  191. var textTransform;
  192. var value;
  193. if (substring == '%%') {
  194. return '%';
  195. }
  196. // parse flags
  197. var leftJustify = false,
  198. positivePrefix = '',
  199. zeroPad = false,
  200. prefixBaseX = false,
  201. customPadChar = ' ';
  202. var flagsl = flags.length;
  203. for (var j = 0; flags && j < flagsl; j++) {
  204. switch (flags.charAt(j)) {
  205. case ' ':
  206. positivePrefix = ' ';
  207. break;
  208. case '+':
  209. positivePrefix = '+';
  210. break;
  211. case '-':
  212. leftJustify = true;
  213. break;
  214. case "'":
  215. customPadChar = flags.charAt(j + 1);
  216. break;
  217. case '0':
  218. zeroPad = true;
  219. break;
  220. case '#':
  221. prefixBaseX = true;
  222. break;
  223. }
  224. }
  225. // parameters may be null, undefined, empty-string or real valued
  226. // we want to ignore null, undefined and empty-string values
  227. if (!minWidth) {
  228. minWidth = 0;
  229. } else if (minWidth == '*') {
  230. minWidth = +a[i++];
  231. } else if (minWidth.charAt(0) == '*') {
  232. minWidth = +a[minWidth.slice(1, -1)];
  233. } else {
  234. minWidth = +minWidth;
  235. }
  236. // Note: undocumented perl feature:
  237. if (minWidth < 0) {
  238. minWidth = -minWidth;
  239. leftJustify = true;
  240. }
  241. if (!isFinite(minWidth)) {
  242. throw new Error('sprintf: (minimum-)width must be finite');
  243. }
  244. if (!precision) {
  245. precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined;
  246. } else if (precision == '*') {
  247. precision = +a[i++];
  248. } else if (precision.charAt(0) == '*') {
  249. precision = +a[precision.slice(1, -1)];
  250. } else {
  251. precision = +precision;
  252. }
  253. // grab value using valueIndex if required?
  254. value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
  255. switch (type) {
  256. case 's':
  257. return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
  258. case 'c':
  259. return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
  260. case 'b':
  261. return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
  262. case 'o':
  263. return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
  264. case 'x':
  265. return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
  266. case 'X':
  267. return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
  268. case 'u':
  269. return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
  270. case 'i':
  271. case 'd':
  272. number = +value || 0;
  273. number = Math.round(number - number % 1); // Plain Math.round doesn't just truncate
  274. prefix = number < 0 ? '-' : positivePrefix;
  275. value = prefix + pad(String(Math.abs(number)), precision, '0', false);
  276. return justify(value, prefix, leftJustify, minWidth, zeroPad);
  277. case 'e':
  278. case 'E':
  279. case 'f': // Should handle locales (as per setlocale)
  280. case 'F':
  281. case 'g':
  282. case 'G':
  283. number = +value;
  284. prefix = number < 0 ? '-' : positivePrefix;
  285. method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
  286. textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
  287. value = prefix + Math.abs(number)[method](precision);
  288. return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
  289. default:
  290. return substring;
  291. }
  292. };
  293. return format.replace(regex, doFormat);
  294. }
  295. return sprintf;
  296. });