number.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojo.number"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojo.number"] = true;
  8. dojo.provide("dojo.number");
  9. dojo.require("dojo.i18n");
  10. dojo.requireLocalization("dojo.cldr", "number", null, "ROOT,af,af-na,ak,am,ar,ar-qa,ar-sa,ar-sy,ar-tn,ar-ye,as,asa,az,az-cyrl,be,bem,bez,bg,bm,bn,bo,brx,bs,ca,cgg,chr,cs,da,dav,de,de-at,de-ch,de-li,ebu,ee,el,el-cy,en,en-au,en-be,en-bw,en-bz,en-gb,en-ie,en-in,en-jm,en-mt,en-na,en-nz,en-tt,en-us-posix,en-za,en-zw,eo,es,es-419,es-cl,es-do,es-ec,es-gt,es-hn,es-mx,es-ni,es-pa,es-pe,es-pr,es-py,es-sv,es-us,es-uy,es-ve,et,eu,fa,fa-af,ff,fi,fil,fo,fr,fr-be,fr-ca,fr-ch,fr-lu,ga,gl,gsw,gu,guz,gv,ha,haw,he,hi,hr,hu,hy,id,ig,ii,in,is,it,it-ch,iw,ja,jmc,ka,kab,kam,kde,kea,khq,ki,kk,kl,kln,km,kn,ko,kok,ksb,kw,lg,lt,luo,luy,lv,mas,mer,mfe,mg,mk,ml,mo,mr,ms,ms-bn,mt,my,naq,nb,nd,ne,nl,nl-be,nn,no,nr,nso,nyn,om,or,pa,pl,ps,pt,pt-pt,rm,ro,rof,ru,rw,rwk,saq,seh,ses,sg,sh,shi,shi-tfng,si,sk,sl,sn,so,sq,sr,sr-latn-me,sr-me,ss,st,sv,sw,sw-ke,ta,te,teo,th,ti,tl,tn,tr,ts,tzm,uk,ur,ur-in,uz-af,uz-arab,ve,vi,vun,xh,xog,yo,zh,zh-hant,zh-hant-hk,zh-hk,zu");
  11. dojo.require("dojo.string");
  12. dojo.require("dojo.regexp");
  13. dojo.getObject("number", true, dojo);
  14. /*=====
  15. dojo.number = {
  16. // summary: localized formatting and parsing routines for Number
  17. }
  18. dojo.number.__FormatOptions = function(){
  19. // pattern: String?
  20. // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  21. // with this string. Default value is based on locale. Overriding this property will defeat
  22. // localization. Literal characters in patterns are not supported.
  23. // type: String?
  24. // choose a format type based on the locale from the following:
  25. // decimal, scientific (not yet supported), percent, currency. decimal by default.
  26. // places: Number?
  27. // fixed number of decimal places to show. This overrides any
  28. // information in the provided pattern.
  29. // round: Number?
  30. // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
  31. // means do not round.
  32. // locale: String?
  33. // override the locale used to determine formatting rules
  34. // fractional: Boolean?
  35. // If false, show no decimal places, overriding places and pattern settings.
  36. this.pattern = pattern;
  37. this.type = type;
  38. this.places = places;
  39. this.round = round;
  40. this.locale = locale;
  41. this.fractional = fractional;
  42. }
  43. =====*/
  44. dojo.number.format = function(/*Number*/value, /*dojo.number.__FormatOptions?*/options){
  45. // summary:
  46. // Format a Number as a String, using locale-specific settings
  47. // description:
  48. // Create a string from a Number using a known localized pattern.
  49. // Formatting patterns appropriate to the locale are chosen from the
  50. // [Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and
  51. // delimiters.
  52. // If value is Infinity, -Infinity, or is not a valid JavaScript number, return null.
  53. // value:
  54. // the number to be formatted
  55. options = dojo.mixin({}, options || {});
  56. var locale = dojo.i18n.normalizeLocale(options.locale),
  57. bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);
  58. options.customs = bundle;
  59. var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
  60. if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null
  61. return dojo.number._applyPattern(value, pattern, options); // String
  62. };
  63. //dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
  64. dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough
  65. dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatOptions?*/options){
  66. // summary:
  67. // Apply pattern to format value as a string using options. Gives no
  68. // consideration to local customs.
  69. // value:
  70. // the number to be formatted.
  71. // pattern:
  72. // a pattern string as described by
  73. // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  74. // options: dojo.number.__FormatOptions?
  75. // _applyPattern is usually called via `dojo.number.format()` which
  76. // populates an extra property in the options parameter, "customs".
  77. // The customs object specifies group and decimal parameters if set.
  78. //TODO: support escapes
  79. options = options || {};
  80. var group = options.customs.group,
  81. decimal = options.customs.decimal,
  82. patternList = pattern.split(';'),
  83. positivePattern = patternList[0];
  84. pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);
  85. //TODO: only test against unescaped
  86. if(pattern.indexOf('%') != -1){
  87. value *= 100;
  88. }else if(pattern.indexOf('\u2030') != -1){
  89. value *= 1000; // per mille
  90. }else if(pattern.indexOf('\u00a4') != -1){
  91. group = options.customs.currencyGroup || group;//mixins instead?
  92. decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead?
  93. pattern = pattern.replace(/\u00a4{1,3}/, function(match){
  94. var prop = ["symbol", "currency", "displayName"][match.length-1];
  95. return options[prop] || options.currency || "";
  96. });
  97. }else if(pattern.indexOf('E') != -1){
  98. throw new Error("exponential notation not supported");
  99. }
  100. //TODO: support @ sig figs?
  101. var numberPatternRE = dojo.number._numberPatternRE;
  102. var numberPattern = positivePattern.match(numberPatternRE);
  103. if(!numberPattern){
  104. throw new Error("unable to find a number expression in pattern: "+pattern);
  105. }
  106. if(options.fractional === false){ options.places = 0; }
  107. return pattern.replace(numberPatternRE,
  108. dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round}));
  109. };
  110. dojo.number.round = function(/*Number*/value, /*Number?*/places, /*Number?*/increment){
  111. // summary:
  112. // Rounds to the nearest value with the given number of decimal places, away from zero
  113. // description:
  114. // Rounds to the nearest value with the given number of decimal places, away from zero if equal.
  115. // Similar to Number.toFixed(), but compensates for browser quirks. Rounding can be done by
  116. // fractional increments also, such as the nearest quarter.
  117. // NOTE: Subject to floating point errors. See dojox.math.round for experimental workaround.
  118. // value:
  119. // The number to round
  120. // places:
  121. // The number of decimal places where rounding takes place. Defaults to 0 for whole rounding.
  122. // Must be non-negative.
  123. // increment:
  124. // Rounds next place to nearest value of increment/10. 10 by default.
  125. // example:
  126. // >>> dojo.number.round(-0.5)
  127. // -1
  128. // >>> dojo.number.round(162.295, 2)
  129. // 162.29 // note floating point error. Should be 162.3
  130. // >>> dojo.number.round(10.71, 0, 2.5)
  131. // 10.75
  132. var factor = 10 / (increment || 10);
  133. return (factor * +value).toFixed(places) / factor; // Number
  134. };
  135. if((0.9).toFixed() == 0){
  136. // (isIE) toFixed() bug workaround: Rounding fails on IE when most significant digit
  137. // is just after the rounding place and is >=5
  138. (function(){
  139. var round = dojo.number.round;
  140. dojo.number.round = function(v, p, m){
  141. var d = Math.pow(10, -p || 0), a = Math.abs(v);
  142. if(!v || a >= d || a * Math.pow(10, p + 1) < 5){
  143. d = 0;
  144. }
  145. return round(v, p, m) + (v > 0 ? d : -d);
  146. };
  147. })();
  148. }
  149. /*=====
  150. dojo.number.__FormatAbsoluteOptions = function(){
  151. // decimal: String?
  152. // the decimal separator
  153. // group: String?
  154. // the group separator
  155. // places: Number?|String?
  156. // number of decimal places. the range "n,m" will format to m places.
  157. // round: Number?
  158. // 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
  159. // means don't round.
  160. this.decimal = decimal;
  161. this.group = group;
  162. this.places = places;
  163. this.round = round;
  164. }
  165. =====*/
  166. dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatAbsoluteOptions?*/options){
  167. // summary:
  168. // Apply numeric pattern to absolute value using options. Gives no
  169. // consideration to local customs.
  170. // value:
  171. // the number to be formatted, ignores sign
  172. // pattern:
  173. // the number portion of a pattern (e.g. `#,##0.00`)
  174. options = options || {};
  175. if(options.places === true){options.places=0;}
  176. if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit
  177. var patternParts = pattern.split("."),
  178. comma = typeof options.places == "string" && options.places.indexOf(","),
  179. maxPlaces = options.places;
  180. if(comma){
  181. maxPlaces = options.places.substring(comma + 1);
  182. }else if(!(maxPlaces >= 0)){
  183. maxPlaces = (patternParts[1] || []).length;
  184. }
  185. if(!(options.round < 0)){
  186. value = dojo.number.round(value, maxPlaces, options.round);
  187. }
  188. var valueParts = String(Math.abs(value)).split("."),
  189. fractional = valueParts[1] || "";
  190. if(patternParts[1] || options.places){
  191. if(comma){
  192. options.places = options.places.substring(0, comma);
  193. }
  194. // Pad fractional with trailing zeros
  195. var pad = options.places !== undefined ? options.places : (patternParts[1] && patternParts[1].lastIndexOf("0") + 1);
  196. if(pad > fractional.length){
  197. valueParts[1] = dojo.string.pad(fractional, pad, '0', true);
  198. }
  199. // Truncate fractional
  200. if(maxPlaces < fractional.length){
  201. valueParts[1] = fractional.substr(0, maxPlaces);
  202. }
  203. }else{
  204. if(valueParts[1]){ valueParts.pop(); }
  205. }
  206. // Pad whole with leading zeros
  207. var patternDigits = patternParts[0].replace(',', '');
  208. pad = patternDigits.indexOf("0");
  209. if(pad != -1){
  210. pad = patternDigits.length - pad;
  211. if(pad > valueParts[0].length){
  212. valueParts[0] = dojo.string.pad(valueParts[0], pad);
  213. }
  214. // Truncate whole
  215. if(patternDigits.indexOf("#") == -1){
  216. valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);
  217. }
  218. }
  219. // Add group separators
  220. var index = patternParts[0].lastIndexOf(','),
  221. groupSize, groupSize2;
  222. if(index != -1){
  223. groupSize = patternParts[0].length - index - 1;
  224. var remainder = patternParts[0].substr(0, index);
  225. index = remainder.lastIndexOf(',');
  226. if(index != -1){
  227. groupSize2 = remainder.length - index - 1;
  228. }
  229. }
  230. var pieces = [];
  231. for(var whole = valueParts[0]; whole;){
  232. var off = whole.length - groupSize;
  233. pieces.push((off > 0) ? whole.substr(off) : whole);
  234. whole = (off > 0) ? whole.slice(0, off) : "";
  235. if(groupSize2){
  236. groupSize = groupSize2;
  237. delete groupSize2;
  238. }
  239. }
  240. valueParts[0] = pieces.reverse().join(options.group || ",");
  241. return valueParts.join(options.decimal || ".");
  242. };
  243. /*=====
  244. dojo.number.__RegexpOptions = function(){
  245. // pattern: String?
  246. // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  247. // with this string. Default value is based on locale. Overriding this property will defeat
  248. // localization.
  249. // type: String?
  250. // choose a format type based on the locale from the following:
  251. // decimal, scientific (not yet supported), percent, currency. decimal by default.
  252. // locale: String?
  253. // override the locale used to determine formatting rules
  254. // strict: Boolean?
  255. // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
  256. // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
  257. // places: Number|String?
  258. // number of decimal places to accept: Infinity, a positive number, or
  259. // a range "n,m". Defined by pattern or Infinity if pattern not provided.
  260. this.pattern = pattern;
  261. this.type = type;
  262. this.locale = locale;
  263. this.strict = strict;
  264. this.places = places;
  265. }
  266. =====*/
  267. dojo.number.regexp = function(/*dojo.number.__RegexpOptions?*/options){
  268. // summary:
  269. // Builds the regular needed to parse a number
  270. // description:
  271. // Returns regular expression with positive and negative match, group
  272. // and decimal separators
  273. return dojo.number._parseInfo(options).regexp; // String
  274. };
  275. dojo.number._parseInfo = function(/*Object?*/options){
  276. options = options || {};
  277. var locale = dojo.i18n.normalizeLocale(options.locale),
  278. bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale),
  279. pattern = options.pattern || bundle[(options.type || "decimal") + "Format"],
  280. //TODO: memoize?
  281. group = bundle.group,
  282. decimal = bundle.decimal,
  283. factor = 1;
  284. if(pattern.indexOf('%') != -1){
  285. factor /= 100;
  286. }else if(pattern.indexOf('\u2030') != -1){
  287. factor /= 1000; // per mille
  288. }else{
  289. var isCurrency = pattern.indexOf('\u00a4') != -1;
  290. if(isCurrency){
  291. group = bundle.currencyGroup || group;
  292. decimal = bundle.currencyDecimal || decimal;
  293. }
  294. }
  295. //TODO: handle quoted escapes
  296. var patternList = pattern.split(';');
  297. if(patternList.length == 1){
  298. patternList.push("-" + patternList[0]);
  299. }
  300. var re = dojo.regexp.buildGroupRE(patternList, function(pattern){
  301. pattern = "(?:"+dojo.regexp.escapeString(pattern, '.')+")";
  302. return pattern.replace(dojo.number._numberPatternRE, function(format){
  303. var flags = {
  304. signed: false,
  305. separator: options.strict ? group : [group,""],
  306. fractional: options.fractional,
  307. decimal: decimal,
  308. exponent: false
  309. },
  310. parts = format.split('.'),
  311. places = options.places;
  312. // special condition for percent (factor != 1)
  313. // allow decimal places even if not specified in pattern
  314. if(parts.length == 1 && factor != 1){
  315. parts[1] = "###";
  316. }
  317. if(parts.length == 1 || places === 0){
  318. flags.fractional = false;
  319. }else{
  320. if(places === undefined){ places = options.pattern ? parts[1].lastIndexOf('0') + 1 : Infinity; }
  321. if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified
  322. if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; }
  323. flags.places = places;
  324. }
  325. var groups = parts[0].split(',');
  326. if(groups.length > 1){
  327. flags.groupSize = groups.pop().length;
  328. if(groups.length > 1){
  329. flags.groupSize2 = groups.pop().length;
  330. }
  331. }
  332. return "("+dojo.number._realNumberRegexp(flags)+")";
  333. });
  334. }, true);
  335. if(isCurrency){
  336. // substitute the currency symbol for the placeholder in the pattern
  337. re = re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g, function(match, before, target, after){
  338. var prop = ["symbol", "currency", "displayName"][target.length-1],
  339. symbol = dojo.regexp.escapeString(options[prop] || options.currency || "");
  340. before = before ? "[\\s\\xa0]" : "";
  341. after = after ? "[\\s\\xa0]" : "";
  342. if(!options.strict){
  343. if(before){before += "*";}
  344. if(after){after += "*";}
  345. return "(?:"+before+symbol+after+")?";
  346. }
  347. return before+symbol+after;
  348. });
  349. }
  350. //TODO: substitute localized sign/percent/permille/etc.?
  351. // normalize whitespace and return
  352. return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object
  353. };
  354. /*=====
  355. dojo.number.__ParseOptions = function(){
  356. // pattern: String?
  357. // override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  358. // with this string. Default value is based on locale. Overriding this property will defeat
  359. // localization. Literal characters in patterns are not supported.
  360. // type: String?
  361. // choose a format type based on the locale from the following:
  362. // decimal, scientific (not yet supported), percent, currency. decimal by default.
  363. // locale: String?
  364. // override the locale used to determine formatting rules
  365. // strict: Boolean?
  366. // strict parsing, false by default. Strict parsing requires input as produced by the format() method.
  367. // Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
  368. // fractional: Boolean?|Array?
  369. // Whether to include the fractional portion, where the number of decimal places are implied by pattern
  370. // or explicit 'places' parameter. The value [true,false] makes the fractional portion optional.
  371. this.pattern = pattern;
  372. this.type = type;
  373. this.locale = locale;
  374. this.strict = strict;
  375. this.fractional = fractional;
  376. }
  377. =====*/
  378. dojo.number.parse = function(/*String*/expression, /*dojo.number.__ParseOptions?*/options){
  379. // summary:
  380. // Convert a properly formatted string to a primitive Number, using
  381. // locale-specific settings.
  382. // description:
  383. // Create a Number from a string using a known localized pattern.
  384. // Formatting patterns are chosen appropriate to the locale
  385. // and follow the syntax described by
  386. // [unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
  387. // Note that literal characters in patterns are not supported.
  388. // expression:
  389. // A string representation of a Number
  390. var info = dojo.number._parseInfo(options),
  391. results = (new RegExp("^"+info.regexp+"$")).exec(expression);
  392. if(!results){
  393. return NaN; //NaN
  394. }
  395. var absoluteMatch = results[1]; // match for the positive expression
  396. if(!results[1]){
  397. if(!results[2]){
  398. return NaN; //NaN
  399. }
  400. // matched the negative pattern
  401. absoluteMatch =results[2];
  402. info.factor *= -1;
  403. }
  404. // Transform it to something Javascript can parse as a number. Normalize
  405. // decimal point and strip out group separators or alternate forms of whitespace
  406. absoluteMatch = absoluteMatch.
  407. replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), "").
  408. replace(info.decimal, ".");
  409. // Adjust for negative sign, percent, etc. as necessary
  410. return absoluteMatch * info.factor; //Number
  411. };
  412. /*=====
  413. dojo.number.__RealNumberRegexpFlags = function(){
  414. // places: Number?
  415. // The integer number of decimal places or a range given as "n,m". If
  416. // not given, the decimal part is optional and the number of places is
  417. // unlimited.
  418. // decimal: String?
  419. // A string for the character used as the decimal point. Default
  420. // is ".".
  421. // fractional: Boolean?|Array?
  422. // Whether decimal places are used. Can be true, false, or [true,
  423. // false]. Default is [true, false] which means optional.
  424. // exponent: Boolean?|Array?
  425. // Express in exponential notation. Can be true, false, or [true,
  426. // false]. Default is [true, false], (i.e. will match if the
  427. // exponential part is present are not).
  428. // eSigned: Boolean?|Array?
  429. // The leading plus-or-minus sign on the exponent. Can be true,
  430. // false, or [true, false]. Default is [true, false], (i.e. will
  431. // match if it is signed or unsigned). flags in regexp.integer can be
  432. // applied.
  433. this.places = places;
  434. this.decimal = decimal;
  435. this.fractional = fractional;
  436. this.exponent = exponent;
  437. this.eSigned = eSigned;
  438. }
  439. =====*/
  440. dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*/flags){
  441. // summary:
  442. // Builds a regular expression to match a real number in exponential
  443. // notation
  444. // assign default values to missing parameters
  445. flags = flags || {};
  446. //TODO: use mixin instead?
  447. if(!("places" in flags)){ flags.places = Infinity; }
  448. if(typeof flags.decimal != "string"){ flags.decimal = "."; }
  449. if(!("fractional" in flags) || /^0/.test(flags.places)){ flags.fractional = [true, false]; }
  450. if(!("exponent" in flags)){ flags.exponent = [true, false]; }
  451. if(!("eSigned" in flags)){ flags.eSigned = [true, false]; }
  452. var integerRE = dojo.number._integerRegexp(flags),
  453. decimalRE = dojo.regexp.buildGroupRE(flags.fractional,
  454. function(q){
  455. var re = "";
  456. if(q && (flags.places!==0)){
  457. re = "\\" + flags.decimal;
  458. if(flags.places == Infinity){
  459. re = "(?:" + re + "\\d+)?";
  460. }else{
  461. re += "\\d{" + flags.places + "}";
  462. }
  463. }
  464. return re;
  465. },
  466. true
  467. );
  468. var exponentRE = dojo.regexp.buildGroupRE(flags.exponent,
  469. function(q){
  470. if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }
  471. return "";
  472. }
  473. );
  474. var realRE = integerRE + decimalRE;
  475. // allow for decimals without integers, e.g. .25
  476. if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
  477. return realRE + exponentRE; // String
  478. };
  479. /*=====
  480. dojo.number.__IntegerRegexpFlags = function(){
  481. // signed: Boolean?
  482. // The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
  483. // Default is `[true, false]`, (i.e. will match if it is signed
  484. // or unsigned).
  485. // separator: String?
  486. // The character used as the thousands separator. Default is no
  487. // separator. For more than one symbol use an array, e.g. `[",", ""]`,
  488. // makes ',' optional.
  489. // groupSize: Number?
  490. // group size between separators
  491. // groupSize2: Number?
  492. // second grouping, where separators 2..n have a different interval than the first separator (for India)
  493. this.signed = signed;
  494. this.separator = separator;
  495. this.groupSize = groupSize;
  496. this.groupSize2 = groupSize2;
  497. }
  498. =====*/
  499. dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){
  500. // summary:
  501. // Builds a regular expression that matches an integer
  502. // assign default values to missing parameters
  503. flags = flags || {};
  504. if(!("signed" in flags)){ flags.signed = [true, false]; }
  505. if(!("separator" in flags)){
  506. flags.separator = "";
  507. }else if(!("groupSize" in flags)){
  508. flags.groupSize = 3;
  509. }
  510. var signRE = dojo.regexp.buildGroupRE(flags.signed,
  511. function(q){ return q ? "[-+]" : ""; },
  512. true
  513. );
  514. var numberRE = dojo.regexp.buildGroupRE(flags.separator,
  515. function(sep){
  516. if(!sep){
  517. return "(?:\\d+)";
  518. }
  519. sep = dojo.regexp.escapeString(sep);
  520. if(sep == " "){ sep = "\\s"; }
  521. else if(sep == "\xa0"){ sep = "\\s\\xa0"; }
  522. var grp = flags.groupSize, grp2 = flags.groupSize2;
  523. //TODO: should we continue to enforce that numbers with separators begin with 1-9? See #6933
  524. if(grp2){
  525. var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
  526. return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
  527. }
  528. return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
  529. },
  530. true
  531. );
  532. return signRE + numberRE; // String
  533. };
  534. }