Changeset 7361

Show
Ignore:
Timestamp:
02/19/07 18:31:49 (23 months ago)
Author:
peller
Message:

Use regular expressions to parse in dojo.number, expose method to get the regular expression. References #2475

Location:
trunk/src
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/src/number.js

    r6926 r7361  
    77dojo.require("dojo.string.common"); 
    88dojo.require("dojo.string.extras"); 
    9 dojo.require("dojo.regexp"); // should we eliminate this dependency or try to make use of regexp number routines? 
     9dojo.require("dojo.regexp"); 
    1010 
    1111dojo.number.format = function(/*Number*/value, /*Object?*/options){ 
     
    3535}; 
    3636 
    37 dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0]+(?:\.0*#*)?/; // not precise, but good enough 
     37//dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough 
     38dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough 
    3839 
    3940dojo.number.applyPattern = function(/*Number*/value, /*String*/pattern, /*Object?*/options){ 
     
    161162}; 
    162163 
     164dojo.number.regexp = function(/*Object?*/options){ 
     165// 
     166// summary: 
     167//              Builds the regular needed to parse a number 
     168// 
     169// description: 
     170//              returns regular expression with positive and negative match, group and decimal separators 
     171// 
     172// options: object {pattern: String, type: String locale: String, strict: Boolean, places: mixed} 
     173//              pattern- override pattern with this string 
     174//              type- choose a format type based on the locale from the following: decimal, scientific, percent, currency. decimal by default. 
     175//              locale- override the locale used to determine formatting rules 
     176//              strict- strict parsing, false by default 
     177//              places- number of decimal places to accept: Infinity, a positive number, or a range "n,m" 
     178        return dojo.number._parseInfo(options).regexp; // String 
     179} 
     180 
     181dojo.number._parseInfo = function(/*Object?*/options){ 
     182        options = options || {}; 
     183        var locale = dojo.hostenv.normalizeLocale(options.locale); 
     184        var bundle = dojo.i18n.getLocalization("dojo.i18n.cldr", "number", locale); 
     185        var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"]; 
     186//TODO: memoize? 
     187        var group = bundle.group; 
     188//      if(!options.strict){ group = [group,""]; } 
     189        var decimal = bundle.decimal; 
     190 
     191        //TODO: handle quoted escapes 
     192        var patternList = pattern.split(';'); 
     193        if (patternList.length == 1){ 
     194                patternList.push("-" + patternList[0]); // substitute negative sign? 
     195        } 
     196 
     197        var re = dojo.regexp.buildGroupRE(patternList, function(pattern){ 
     198                pattern = "(?:"+dojo.string.escape('regexp', pattern, '.')+")"; 
     199                return pattern.replace(dojo.number._numberPatternRE, function(format){ 
     200                        var flags = { 
     201                                signed: false, 
     202                                separator: options.strict ? group : [group,""], 
     203                                decimal: decimal, 
     204                                exponent: false}; 
     205                        var parts = format.split('.'); 
     206                        if(parts.length == 1){parts.fractional = false;} 
     207                        else{ 
     208                                var places = options.places; 
     209                                if(typeof places == "undefined"){ places = parts[1].lastIndexOf('0')+1; } 
     210                                if(places){parts.fractional = true;} // required fraction 
     211                                flags.places = places; 
     212                                if(places < parts[1].length){ flags.places += "," + parts[1].length; } 
     213                        } 
     214                        var groups = parts[0].split(','); 
     215                        if(groups.length>1){ 
     216                                flags.groupSize = groups.pop().length; 
     217                                if(groups.length>1){ 
     218                                        flags.groupSize2 = groups.pop().length; 
     219                                } 
     220                        } 
     221                        return "("+dojo.regexp.realNumber(flags)+")"; 
     222                }); 
     223        }, true); 
     224 
     225        if(!options.strict){ 
     226                // TODO: handle .### with no leading integer? 
     227                //TODO: !strict: make currency symbol too 
     228        } 
     229 
     230        return {regexp: re, group: group, decimal: decimal}; // Object 
     231} 
     232 
    163233dojo.number.parse = function(/*String*/expression, /*Object?*/options){ 
    164234// 
     
    176246// options: object {pattern: string, locale: string, strict: boolean} 
    177247//              pattern- override pattern with this string 
     248//              type- choose a format type based on the locale from the following: decimal, scientific, percent, currency. decimal by default. 
    178249//              locale- override the locale used to determine formatting rules 
    179250//              strict- strict parsing, false by default 
    180251 
    181         options = options || {}; 
    182         var locale = dojo.hostenv.normalizeLocale(options.locale); 
    183         var bundle = dojo.i18n.getLocalization("dojo.i18n.cldr", "number", locale); 
    184         var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"]; 
    185         var group = bundle.group; 
    186         var decimal = bundle.decimal; 
    187  
    188         //TODO: handle quoted escapes 
    189         var patternList = pattern.split(';'); 
    190         if (patternList.length == 1){ 
    191                 patternList.push("-" + patternList[0]); // substitute negative sign? 
    192         } 
    193  
    194         if(options.strict && !dojo.number._buildNumberFormatRE(pattern, {/*TODO*/}).test(expression)){ 
    195                 return NaN; //NaN 
    196         } 
    197  
    198         var re = dojo.regexp.buildGroupRE(patternList, function(pattern){ 
    199                 pattern = dojo.regexp.group(dojo.string.escape('regexp', pattern, '.'), true); 
    200                 return pattern.replace(dojo.number._numberPatternRE, "([\\d\\"+group+"]+(?:\\"+decimal+"\\d+)?)"); // also handle .### with no leading integer? 
    201         }, true); 
     252        var info = dojo.number._parseInfo(options); 
     253        var group = info.group; 
     254        var decimal = info.decimal; 
     255        var re = info.regexp; 
    202256 
    203257//TODO: substitute currency symbol, percent/permille/etc. 
     
    220274                //TODO: handle exponent 
    221275        } 
    222  
    223276        return value; 
    224277}; 
    225  
    226 dojo.number._buildNumberFormatRE = function(/*String*/pattern, /*Object*/options){ 
    227 //TODO: sign 
    228 //TODO: currency 
    229 //TODO: exp? 
    230 //TODO: number groups 
    231         dojo.unimplemented("dojo.number._buildNumberFormatRE"); 
    232         var numberPatternRE = dojo.number._numberPatternRE; 
    233         var numberPattern = pattern.match(numberPatternRE); 
    234         if(!numberPattern){ 
    235                 dojo.raise("unable to find a number expression in pattern: "+pattern); 
    236         } 
    237         //TODO: escape special chars in regexp 
    238         pattern = pattern.replace(numberPatternRE, "\\d..."); 
    239         return new RegExp("^" + pattern + "$"); // RegExp 
    240 //TODO: memoize? 
    241 }; 
  • trunk/src/regexp.js

    r6985 r7361  
    256256        // build sign RE 
    257257        var signRE = dojo.regexp.buildGroupRE(flags.signed, 
    258                 function(q) { return q ? "[-+]" : ""; } 
     258                function(q) { return q ? "[-+]" : ""; }, 
     259                true 
    259260        ); 
    260261 
     
    262263        var numberRE = dojo.regexp.buildGroupRE(flags.separator, 
    263264                function(sep){  
    264                         if(sep == ""){  
    265                                 return "(0|[1-9]\\d*)"; 
     265                        if(!sep){  
     266                                return "(?:0|[1-9]\\d*)"; 
    266267                        } 
    267268                        var grp = flags.groupSize, grp2 = flags.groupSize2; 
    268                         if(typeof grp2 != "undefined"){ 
    269                                 var grp2RE = "(0|[1-9]\\d{0," + (grp2-1) + "}([" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})"; 
    270                                 return ((grp-grp2) > 0) ? "(" + grp2RE + "|(0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE; 
     269                        if(grp2){ 
     270                                var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})"; 
     271                                return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE; 
    271272                        } 
    272                         return  "(0|[1-9]\\d{0," + (grp-1) + "}([" + sep + "]\\d{" + grp + "})*)"; 
    273                 } 
     273                        return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)"; 
     274                }, 
     275                true 
    274276        ); 
    275277 
     
    282284        // 
    283285        // flags:An object 
    284         //    flags.places  The integer number of decimal places. 
     286        //    flags.places  The integer number of decimal places or a range given as "n,m" 
    285287        //      If not given, the decimal part is optional and the number of places is unlimited. 
    286288        //    flags.decimal  A string for the character used as the decimal point.  Default is ".". 
     
    295297        // assign default values to missing paramters 
    296298        flags = (typeof flags == "object") ? flags : {}; 
    297         if(typeof flags.places != "number"){ flags.places = Infinity; } 
     299        if(typeof flags.places == "undefined"){ flags.places = Infinity; } 
    298300        if(typeof flags.decimal != "string"){ flags.decimal = "."; } 
    299301        if(typeof flags.fractional == "undefined"){ flags.fractional = [true, false]; } 
     
    308310                function(q){ 
    309311                        var re = ""; 
    310                         if(q && (flags.places > 0)){ 
     312                        if(q && (flags.places!==0)){ 
    311313                                re = "\\" + flags.decimal; 
    312314                                if(flags.places == Infinity){  
    313                                         re = "(" + re + "\\d+)?";  
    314                                 }else{  
    315                                         re = re + "\\d{" + flags.places + "}";  
     315                                        re = "(?:" + re + "\\d+)?";  
     316                                }else{ 
     317                                        re += "\\d{" + flags.places + "}";  
    316318                                } 
    317319                        } 
    318  
    319320                        return re; 
    320                 } 
     321                }, 
     322                true 
    321323        ); 
    322324