예제 #1
0
        public void Parse_NotAPattern()
        {
            var locale = Locale.Create("en");
            var path   = $"ldml/numbers/decimalFormats[@numberSystem='latn']/decimalFormatLength[@type='long']/decimalFormat";

            ExceptionAssert.Throws <Exception>(() => NumberPattern.Parse(locale.Find(path)));
        }
예제 #2
0
        public void Adjust_Simple()
        {
            var pattern = new NumberPattern {
                FormatString = "#,##0"
            };

            Assert.AreEqual(12345, pattern.Adjust(12345));
        }
예제 #3
0
        public void Parse_Simple()
        {
            var locale  = Locale.Create("en");
            var path    = $"ldml/numbers/decimalFormats[@numberSystem='latn']/decimalFormatLength[not(@type)]/decimalFormat/pattern";
            var pattern = NumberPattern.Parse(locale.Find(path));

            Assert.AreEqual("", pattern.Count);
            Assert.IsFalse(pattern.MinValue.HasValue);
            Assert.AreEqual("#,##0.###", pattern.FormatString);
        }
예제 #4
0
        public void Adjust_ValueRange()
        {
            var pattern = new NumberPattern
            {
                MinValue     = 10000,
                Count        = "other",
                FormatString = "00 K"
            };

            Assert.AreEqual(12, pattern.Adjust(12345));
        }
예제 #5
0
        public void Parse_ValueRange()
        {
            var locale  = Locale.Create("en");
            var path    = $"ldml/numbers/decimalFormats[@numberSystem='latn']/decimalFormatLength[@type='long']/decimalFormat/pattern";
            var pattern = NumberPattern.Parse(locale.Find(path));

            Assert.AreEqual("one", pattern.Count);
            Assert.IsTrue(pattern.MinValue.HasValue);
            Assert.AreEqual(1000L, pattern.MinValue.Value);
            Assert.AreEqual("0 thousand", pattern.FormatString);
        }
예제 #6
0
        /// <summary>
        ///   Create a number pattern from the specified <see cref="XPathNavigator"/>.
        /// </summary>
        /// <param name="xml">
        ///   The XML representation of a number pattern.
        /// </param>
        /// <returns>
        ///   A new number pattern,
        /// </returns>
        /// <remarks>
        ///   The <paramref name="xml"/> must be on a "pattern" element.
        /// </remarks>
        public static NumberPattern Parse(XPathNavigator xml)
        {
            if (xml.LocalName != "pattern")
            {
                throw new Exception($"Expected a 'pattern' element, not '{xml.LocalName}'.");
            }

            var pattern = new NumberPattern
            {
                Count        = xml.GetAttribute("count", ""),
                FormatString = xml.Value
            };
            var s = xml.GetAttribute("type", "");

            if (s != String.Empty)
            {
                pattern.MinValue = decimal.Parse(s, CultureInfo.InvariantCulture);
            }

            return(pattern);
        }
예제 #7
0
        NumberPattern FindPattern(decimal value, NumberLength?nl = null)
        {
            if (!nl.HasValue)
            {
                nl = Options.Length;
            }
            value = Math.Abs(value);

            // Determine the format length type.
            var flt = nl == NumberLength.Default
                ? "[not(@type)]"
                : $"[@type='{nl.ToString().ToLowerInvariant()}']";

            // Determine the path in the ldml to the pattern(s)
            var path = String.Empty;

            if (Options.Style == NumberStyle.Decimal)
            {
                path = $"ldml/numbers/decimalFormats[@numberSystem='{NumberingSystem.Id}']/decimalFormatLength{flt}/decimalFormat";
            }
            else if (Options.Style == NumberStyle.Percent)
            {
                path = $"ldml/numbers/percentFormats[@numberSystem='{NumberingSystem.Id}']/percentFormatLength{flt}/percentFormat";
            }
            else if (Options.Style == NumberStyle.Scientific)
            {
                path = $"ldml/numbers/scientificFormats[@numberSystem='{NumberingSystem.Id}']/scientificFormatLength{flt}/scientificFormat";
            }
            else if (Options.Style == NumberStyle.CurrencyStandard)
            {
                path = $"ldml/numbers/currencyFormats[@numberSystem='{NumberingSystem.Id}']/currencyFormatLength{flt}/currencyFormat[@type='standard']";
            }
            else if (Options.Style == NumberStyle.CurrencyAccounting)
            {
                path = $"ldml/numbers/currencyFormats[@numberSystem='{NumberingSystem.Id}']/currencyFormatLength{flt}/currencyFormat[@type='accounting']";
            }
            else
            {
                throw new NotImplementedException($"Unknown NumberStyle '{Options.Style}'.");
            }

            var xml = Locale.FindOrDefault(path);

            // Fall back to default number length;
            if (xml == null && nl != NumberLength.Default)
            {
                return(FindPattern(value, NumberLength.Default));
            }

            // Should not happen.
            if (xml == null)
            {
                throw new KeyNotFoundException($"Cannot find CLDR '{path}'.");
            }

            // Get the best pattern.
            var           category = Plural.Create(Locale).Category(value);
            NumberPattern best     = null;
            NumberPattern previous = null;
            var           pattern  = xml.SelectChildren("pattern", "");

            while (pattern.MoveNext())
            {
                var p = NumberPattern.Parse(pattern.Current);

                // If not a value range, then this is the best pattern.
                if (!p.MinValue.HasValue)
                {
                    best = p;
                    break;
                }

                // Only consider a pattern with the correct count.
                if (p.Count != category)
                {
                    continue;
                }

                // Get closest value in the range.
                if (p.MinValue.Value > value)
                {
                    best = previous;
                    break;
                }

                previous = p;
            }
            best = best ?? previous ?? new NumberPattern {
                FormatString = "0"
            };

            return(best);
        }
예제 #8
0
        NumberFormatInfo NumberInfo(string currencyCode, int nDigits, NumberPattern pattern)
        {
            var nfi = new NumberFormatInfo
            {
                NaNSymbol              = Symbols.NotANumber,
                NegativeSign           = Symbols.MinusSign,
                NegativeInfinitySymbol = Symbols.MinusSign + Symbols.Infinity,
                NumberDecimalSeparator = Symbols.Decimal,
                NumberGroupSeparator   = Symbols.Group,
                // NativeDigits is NOT by used the C# formatter!!
                //NativeDigits = NumberingSystem.Digits,
                PercentDecimalSeparator = Symbols.Decimal,
                PercentSymbol           = Symbols.PercentSign,
                PerMilleSymbol          = Symbols.PerMille,
                PositiveInfinitySymbol  = Symbols.Infinity,
                PositiveSign            = Symbols.PlusSign
            };

            if (Options.Style == NumberStyle.Scientific && pattern.FormatString == "#E0")
            {
                pattern.FormatString = "0.0######E0";
            }

            else if (Options.Style == NumberStyle.CurrencyStandard || Options.Style == NumberStyle.CurrencyAccounting)
            {
                nfi.NumberDecimalSeparator = Symbols.CurrencyDecimal;
                nfi.NumberGroupSeparator   = Symbols.CurrencyGroup;

                // Apply currency decimal places
                if (currencyCode == null)
                {
                    currencyCode = Locale.CurrencyCode;
                }
                var digits = Cldr.Instance
                             .GetDocuments("common/supplemental/supplementalData.xml")
                             .FirstElementOrDefault($"supplementalData/currencyData/fractions/info[@iso4217='{currencyCode}']/@digits");
                if (digits != null)
                {
                    int significantDigits = Int32.Parse(digits.Value);
                    pattern.FormatString = significantDigitsPattern.Replace(pattern.FormatString, "." + new String('0', significantDigits));
                }
            }

            // Grouping of digits.
            var useGrouping = Options.UseGrouping;

            if (useGrouping)
            {
                // Grouping digits, "#,##,##0" => [3, 2, 1]
                var parts = pattern.FormatString.Split(';');
                nfi.NumberGroupSizes = groupingPattern
                                       .Matches(parts[0])
                                       .Cast <Match>()
                                       .Skip(1)
                                       .Reverse()
                                       .Select(m => m.Length - 1)
                                       .DefaultIfEmpty(3)
                                       .ToArray();

                // Don't group if min grouping digits is not met.
                var minElement = Locale.FindOrDefault("ldml/numbers/minimumGroupingDigits");
                if (minElement != null)
                {
                    var minDigits = Int32.Parse(minElement.Value) + nfi.NumberGroupSizes[0];
                    useGrouping = nDigits > minDigits;
                }
            }

            if (!useGrouping)
            {
                nfi.NumberGroupSeparator = "";
            }
            nfi.PercentGroupSizes     = nfi.NumberGroupSizes;
            nfi.PercentGroupSeparator = nfi.NumberGroupSeparator;

            return(nfi);
        }