Exemplo n.º 1
0
        // -----------------------------------------------------------------------
        // construction
        // -----------------------------------------------------------------------

        /*
         * Constructs a rule set.
         *
         * @param descriptions An array of Strings representing rule set
         * descriptions. On exit, this rule set's entry in the array will have been
         * stripped of its rule set name and any trailing whitespace.
         *
         * @param index The index into "descriptions" of the description for the
         * rule to be constructed
         */
        public NFRuleSet(String[] descriptions, int index)
        {
            this.negativeNumberRule = null;
            this.fractionRules      = new NFRule[3];
            this.isFractionRuleSet  = false;
            this.recursionCount     = 0;
            String description = descriptions[index];

            if (description.Length == 0)
            {
                throw new ArgumentException("Empty rule set description");
            }

            // if the description begins with a rule set name (the rule set
            // name can be omitted in formatter descriptions that consist
            // of only one rule set), copy it out into our "name" member
            // and delete it from the description
            if (description[0] == '%')
            {
                int pos = description.IndexOf(':');
                if (pos == -1)
                {
                    throw new ArgumentException(
                              "Rule set name doesn't end in colon");
                }
                else
                {
                    name = description.Substring(0, (pos) - (0));
                    while (pos < description.Length &&
                           IBM.ICU.Impl.UCharacterProperty.IsRuleWhiteSpace(description[++pos]))
                    {
                    }
                    description         = description.Substring(pos);
                    descriptions[index] = description;
                }

                // if the description doesn't begin with a rule set name, its
                // name is "%default"
            }
            else
            {
                name = "%default";
            }

            if (description.Length == 0)
            {
                throw new ArgumentException("Empty rule set description");
            }

            // all of the other members of NFRuleSet are initialized
            // by parseRules()
        }
Exemplo n.º 2
0
        /// <summary>
        /// Formats a double. Selects an appropriate rule and dispatches control to
        /// it.
        /// </summary>
        ///
        /// <param name="number">The number being formatted</param>
        /// <param name="toInsertInto">The string where the result is to be placed</param>
        /// <param name="pos">The position in toInsertInto where the result of thisoperation is to be inserted</param>
        public void Format(double number, StringBuilder toInsertInto, int pos)
        {
            NFRule applicableRule = FindRule(number);

            if (++recursionCount >= RECURSION_LIMIT)
            {
                recursionCount = 0;
                throw new InvalidOperationException(
                          "Recursion limit exceeded when applying ruleSet " + name);
            }
            applicableRule.DoFormat(number, toInsertInto, pos);
            --recursionCount;
        }
Exemplo n.º 3
0
        /// <summary>
        /// If the value passed to findRule() is a positive integer, findRule() uses
        /// this function to select the appropriate rule. The result will generally
        /// be the rule with the highest base value less than or equal to the number.
        /// There is one exception to this: If that rule has two substitutions and a
        /// base value that is not an even multiple of its divisor, and the number
        /// itself IS an even multiple of the rule's divisor, then the result will be
        /// the rule that preceded the original result in the rule list. (This
        /// behavior is known as the "rollback rule", and is used to handle optional
        /// text: a rule with optional text is represented internally as two rules,
        /// and the rollback rule selects appropriate between them. This avoids
        /// things like "two hundred zero".)
        /// </summary>
        ///
        /// <param name="number">The number being formatted</param>
        /// <returns>The rule to use to format this number</returns>
        private NFRule FindNormalRule(long number)
        {
            // if this is a fraction rule set, use findFractionRuleSetRule()
            // to find the rule (we should only go into this clause if the
            // value is 0)
            if (isFractionRuleSet)
            {
                return(FindFractionRuleSetRule(number));
            }

            // if the number is negative, return the negative-number rule
            // (if there isn't one, pretend the number is positive)
            if (number < 0)
            {
                if (negativeNumberRule != null)
                {
                    return(negativeNumberRule);
                }
                else
                {
                    number = -number;
                }
            }

            // we have to repeat the preceding two checks, even though we
            // do them in findRule(), because the version of format() that
            // takes a long bypasses findRule() and goes straight to this
            // function. This function does skip the fraction rules since
            // we know the value is an integer (it also skips the master
            // rule, since it's considered a fraction rule. Skipping the
            // master rule in this function is also how we avoid infinite
            // recursion)

            // binary-search the rule list for the applicable rule
            // (a rule is used for all values from its base value to
            // the next rule's base value)
            int lo = 0;
            int hi = rules.Length;

            if (hi > 0)
            {
                while (lo < hi)
                {
                    int mid = (lo + hi) / 2;
                    if (rules[mid].GetBaseValue() == number)
                    {
                        return(rules[mid]);
                    }
                    else if (rules[mid].GetBaseValue() > number)
                    {
                        hi = mid;
                    }
                    else
                    {
                        lo = mid + 1;
                    }
                }
                if (hi == 0)       // bad rule set
                {
                    throw new InvalidOperationException("The rule set " + name
                                                        + " cannot format the value " + number);
                }
                NFRule result = rules[hi - 1];

                // use shouldRollBack() to see whether we need to invoke the
                // rollback rule (see shouldRollBack()'s documentation for
                // an explanation of the rollback rule). If we do, roll back
                // one rule and return that one instead of the one we'd normally
                // return
                if (result.ShouldRollBack(number))
                {
                    if (hi == 1)       // bad rule set
                    {
                        throw new InvalidOperationException("The rule set " + name
                                                            + " cannot roll back from the rule '" + result
                                                            + "'");
                    }
                    result = rules[hi - 2];
                }
                return(result);
            }
            // else use the master rule
            return(fractionRules[2]);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Construct the subordinate data structures used by this object. This
        /// function is called by the RuleBasedNumberFormat constructor after all the
        /// rule sets have been created to actually parse the description and build
        /// rules from it. Since any rule set can refer to any other rule set, we
        /// have to have created all of them before we can create anything else.
        /// </summary>
        ///
        /// <param name="description">The textual description of this rule set</param>
        /// <param name="owner">The formatter that owns this rule set</param>
        public void ParseRules(String description, RuleBasedNumberFormat owner)
        {
            // start by creating a Vector whose elements are Strings containing
            // the descriptions of the rules (one rule per element). The rules
            // are separated by semicolons (there's no escape facility: ALL
            // semicolons are rule delimiters)
            ArrayList ruleDescriptions = new ArrayList();

            int oldP = 0;
            int p    = description.IndexOf(';');

            while (oldP != -1)
            {
                if (p != -1)
                {
                    ruleDescriptions.Add(description.Substring(oldP, (p) - (oldP)));
                    oldP = p + 1;
                }
                else
                {
                    if (oldP < description.Length)
                    {
                        ruleDescriptions.Add(description.Substring(oldP));
                    }
                    oldP = p;
                }
                p = description.IndexOf(';', p + 1);
            }

            // now go back through and build a vector of the rules themselves
            // (the number of elements in the description list isn't necessarily
            // the number of rules-- some descriptions may expend into two rules)
            ArrayList tempRules = new ArrayList();

            // we keep track of the rule before the one we're currently working
            // on solely to support >>> substitutions
            NFRule predecessor = null;

            for (int i = 0; i < ruleDescriptions.Count; i++)
            {
                // makeRules (a factory method on NFRule) will return either
                // a single rule or an array of rules. Either way, add them
                // to our rule vector
                Object temp = IBM.ICU.Text.NFRule.MakeRules(
                    (String)ruleDescriptions[i], this, predecessor,
                    owner);

                if (temp  is  NFRule)
                {
                    tempRules.Add(temp);
                    predecessor = (NFRule)temp;
                }
                else if (temp  is  NFRule[])
                {
                    NFRule[] rulesToAdd = (NFRule[])temp;

                    for (int j = 0; j < rulesToAdd.Length; j++)
                    {
                        tempRules.Add(rulesToAdd[j]);
                        predecessor = rulesToAdd[j];
                    }
                }
            }
            // now we can bag the description list
            ruleDescriptions = null;

            // for rules that didn't specify a base value, their base values
            // were initialized to 0. Make another pass through the list and
            // set all those rules' base values. We also remove any special
            // rules from the list and put them into their own member variables
            long defaultBaseValue = 0;

            // (this isn't a for loop because we might be deleting items from
            // the vector-- we want to make sure we only increment i when
            // we _didn't_ delete aything from the vector)
            int i_0 = 0;

            while (i_0 < tempRules.Count)
            {
                NFRule rule = (NFRule)tempRules[i_0];

                switch ((int)rule.GetBaseValue())
                {
                // if the rule's base value is 0, fill in a default
                // base value (this will be 1 plus the preceding
                // rule's base value for regular rule sets, and the
                // same as the preceding rule's base value in fraction
                // rule sets)
                case 0:
                    rule.SetBaseValue(defaultBaseValue);
                    if (!isFractionRuleSet)
                    {
                        ++defaultBaseValue;
                    }
                    ++i_0;
                    break;

                // if it's the negative-number rule, copy it into its own
                // data member and delete it from the list
                case IBM.ICU.Text.NFRule.NEGATIVE_NUMBER_RULE:
                    negativeNumberRule = rule;
                    ILOG.J2CsMapping.Collections.Collections.RemoveAt(tempRules, i_0);
                    break;

                // if it's the improper fraction rule, copy it into the
                // correct element of fractionRules
                case IBM.ICU.Text.NFRule.IMPROPER_FRACTION_RULE:
                    fractionRules[0] = rule;
                    ILOG.J2CsMapping.Collections.Collections.RemoveAt(tempRules, i_0);
                    break;

                // if it's the proper fraction rule, copy it into the
                // correct element of fractionRules
                case IBM.ICU.Text.NFRule.PROPER_FRACTION_RULE:
                    fractionRules[1] = rule;
                    ILOG.J2CsMapping.Collections.Collections.RemoveAt(tempRules, i_0);
                    break;

                // if it's the master rule, copy it into the
                // correct element of fractionRules
                case IBM.ICU.Text.NFRule.MASTER_RULE:
                    fractionRules[2] = rule;
                    ILOG.J2CsMapping.Collections.Collections.RemoveAt(tempRules, i_0);
                    break;

                // if it's a regular rule that already knows its base value,
                // check to make sure the rules are in order, and update
                // the default base value for the next rule
                default:
                    if (rule.GetBaseValue() < defaultBaseValue)
                    {
                        throw new ArgumentException(
                                  "Rules are not in order, base: "
                                  + rule.GetBaseValue() + " < "
                                  + defaultBaseValue);
                    }
                    defaultBaseValue = rule.GetBaseValue();
                    if (!isFractionRuleSet)
                    {
                        ++defaultBaseValue;
                    }
                    ++i_0;
                    break;
                }
            }

            // finally, we can copy the rules from the vector into a
            // fixed-length array
            rules = new NFRule[tempRules.Count];
            tempRules.CopyTo((Object[])rules);
        }