Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: charted/lib/locale/format/number_format.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « charted/lib/locale/format.dart ('k') | charted/lib/locale/format/time_format.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://developers.google.com/open-source/licenses/bsd
7 */
8 part of charted.locale.format;
9
10 /**
11 * The number formatter of a given locale. Applying the locale specific
12 * number format, number grouping and currency symbol, etc.. The format
13 * function in the NumberFormat class is used to format a number by the given
14 * specifier with the number properties of the locale.
15 */
16 class NumberFormat {
17
18 // [[fill]align][sign][symbol][0][width][,][.precision][type]
19 static RegExp FORMAT_REGEX =
20 new RegExp(r'(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?'
21 r'(\.-?\d+)?([a-z%])?', caseSensitive: false);
22
23 String localeDecimal;
24 String localeThousands;
25 List localeGrouping;
26 List localeCurrency;
27 Function formatGroup;
28
29 NumberFormat(Locale locale) {
30 localeDecimal = locale.decimal;
31 localeThousands = locale.thousands;
32 localeGrouping = locale.grouping;
33 localeCurrency = locale.currency;
34 formatGroup = (localeGrouping != null) ? (value) {
35 var i = value.length,
36 t = [],
37 j = 0,
38 g = localeGrouping[0];
39 while (i > 0 && g > 0) {
40 if (i - g >= 0) {
41 i = i - g;
42 } else {
43 g = i;
44 i = 0;
45 }
46 var length = (i + g) < value.length ? (i + g) : value.length;
47 t.add(value.substring(i, length));
48 g = localeGrouping[j = (j + 1) % localeGrouping.length];
49 }
50 return t.reversed.join(localeThousands);
51 } : (x) => x;
52 }
53
54 /**
55 * Returns a new format function with the given string specifier. A format
56 * function takes a number as the only argument, and returns a string
57 * representing the formatted number. The format specifier is modeled after
58 * Python 3.1's built-in format specification mini-language. The general form
59 * of a specifier is:
60 * [​[fill]align][sign][symbol][0][width][,][.precision][type].
61 *
62 * @see <a href="http://docs.python.org/release/3.1.3/library/string.html#form atspec">format specification mini-language</a>
63 */
64 FormatFunction format(String specifier) {
65 Match match = FORMAT_REGEX.firstMatch(specifier);
66 var fill = match.group(1) != null ? match.group(1) : ' ',
67 align = match.group(2) != null ? match.group(2) : '>',
68 sign = match.group(3) != null ? match.group(3) : '',
69 symbol = match.group(4) != null ? match.group(4) : '',
70 zfill = match.group(5),
71 width = match.group(6) != null ? int.parse(match.group(6)) : 0,
72 comma = match.group(7) != null,
73 precision = match.group(8) != null ?
74 int.parse(match.group(8).substring(1)) : null,
75 type = match.group(9),
76 scale = 1,
77 prefix = '',
78 suffix = '',
79 integer = false;
80
81 if (zfill != null || fill == '0' && align == '=') {
82 zfill = fill = '0';
83 align = '=';
84 if (comma) {
85 width -= ((width - 1) / 4).floor();
86 }
87 }
88
89 switch (type) {
90 case 'n': comma = true; type = 'g'; break;
91 case '%': scale = 100; suffix = '%'; type = 'f'; break;
92 case 'p': scale = 100; suffix = '%'; type = 'r'; break;
93 case 'b':
94 case 'o':
95 case 'x':
96 case 'X': if (symbol == '#') prefix = '0' + type.toLowerCase(); break;
97 case 'c':
98 case 'd': integer = true; precision = 0; break;
99 case 's': scale = -1; type = 'r'; break;
100 }
101
102 if (symbol == '\$') {
103 prefix = localeCurrency[0];
104 suffix = localeCurrency[1];
105 }
106
107 // If no precision is specified for r, fallback to general notation.
108 if (type == 'r' && precision == null) {
109 type = 'g';
110 }
111
112 // Ensure that the requested precision is in the supported range.
113 if (precision != null) {
114 if (type == 'g') {
115 precision = math.max(1, math.min(21, precision));
116 } else if (type == 'e' || type == 'f') {
117 precision = math.max(0, math.min(20, precision));
118 }
119 }
120
121 NumberFormatFunction formatFunction = _getFormatFunction(type);
122
123 var zcomma = (zfill != null) && comma;
124
125 return (value) {
126 var fullSuffix = suffix;
127
128 // Return the empty string for floats formatted as ints.
129 if (integer && (value % 1) > 0) return '';
130
131 // Convert negative to positive, and record the sign prefix.
132 var negative;
133 if (value < 0 || value == 0 && 1 / value < 0) {
134 value = -value;
135 negative = '-';
136 } else {
137 negative = sign;
138 }
139
140 // Apply the scale, computing it from the value's exponent for si
141 // format. Preserve the existing suffix, if any, such as the
142 // currency symbol.
143 if (scale < 0) {
144 FormatPrefix unit = new FormatPrefix(value,
145 (precision != null) ? precision : 0);
146 value = unit.scale(value);
147 fullSuffix = unit.symbol + suffix;
148 } else {
149 value *= scale;
150 }
151
152 // Convert to the desired precision.
153 if (precision != null) {
154 value = formatFunction(value, precision);
155 } else {
156 value = formatFunction(value);
157 }
158
159 // Break the value into the integer part (before) and decimal part
160 // (after).
161 var i = value.lastIndexOf('.'),
162 before = i < 0 ? value : value.substring(0, i),
163 after = i < 0 ? '' : localeDecimal + value.substring(i + 1);
164
165 // If the fill character is not '0', grouping is applied before
166 //padding.
167 if (zfill == null && comma) {
168 before = formatGroup(before);
169 }
170
171 var length = prefix.length + before.length + after.length +
172 (zcomma ? 0 : negative.length),
173 padding = length < width ? new List.filled(
174 (length = width - length + 1), '').join(fill) : '';
175
176 // If the fill character is '0', grouping is applied after padding.
177 if (zcomma) {
178 before = formatGroup(padding + before);
179 }
180
181 // Apply prefix.
182 negative += prefix;
183
184 // Rejoin integer and decimal parts.
185 value = before + after;
186
187 // Apply any padding and alignment attributes before returning the string.
188 return (align == '<' ? negative + value + padding
189 : align == '>' ? padding + negative + value
190 : align == '^' ? padding.substring(0, length >>= 1) + negative +
191 value + padding.substring(length)
192 : negative + (zcomma ? value : padding + value)) + fullSuffix;
193 };
194 }
195
196 // Gets the format function by given type.
197 NumberFormatFunction _getFormatFunction(String type) {
198 switch(type) {
199 case 'b':
200 return (num x, [int p = 0]) => x.toInt().toRadixString(2);
201 case 'c':
202 return (num x, [int p = 0]) => new String.fromCharCodes([x]);
203 case 'o':
204 return (num x, [int p = 0]) => x.toInt().toRadixString(8);
205 case 'x':
206 return (num x, [int p = 0]) => x.toInt().toRadixString(16);
207 case 'X':
208 return (num x, [int p = 0]) =>
209 x.toInt().toRadixString(16).toUpperCase();
210 case 'g':
211 return (num x, [int p = 1]) => x.toStringAsPrecision(p);
212 case 'e':
213 return (num x, [int p = 0]) => x.toStringAsExponential(p);
214 case 'f':
215 return (num x, [int p = 0]) => x.toStringAsFixed(p);
216 case 'r':
217 default:
218 return (num x, [int p = 0]) => x.toString();
219 }
220 }
221 }
OLDNEW
« no previous file with comments | « charted/lib/locale/format.dart ('k') | charted/lib/locale/format/time_format.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698