ICU-4039 new rbnf syntax to spell out leading zeros in decimals
X-SVN-Rev: 16099
This commit is contained in:
parent
711cae9988
commit
183d55c13f
@ -126,8 +126,8 @@ final class NFRule {
|
||||
// then leave the description alone, initialize the rule's
|
||||
// rule text and substitutions, and return that rule
|
||||
if (brack1 == -1 || brack2 == -1 || brack1 > brack2
|
||||
|| rule1.getBaseValue() == PROPER_FRACTION_RULE
|
||||
|| rule1.getBaseValue() == NEGATIVE_NUMBER_RULE) {
|
||||
|| rule1.getBaseValue() == PROPER_FRACTION_RULE
|
||||
|| rule1.getBaseValue() == NEGATIVE_NUMBER_RULE) {
|
||||
rule1.ruleText = description;
|
||||
rule1.extractSubstitutions(owner, predecessor, ownersOwner);
|
||||
return rule1;
|
||||
@ -141,9 +141,9 @@ final class NFRule {
|
||||
// base value is an even multiple of its divisor (or it's one
|
||||
// of the special rules)
|
||||
if ((rule1.baseValue > 0
|
||||
&& rule1.baseValue % (Math.pow(rule1.radix, rule1.exponent)) == 0)
|
||||
|| rule1.baseValue == IMPROPER_FRACTION_RULE
|
||||
|| rule1.baseValue == MASTER_RULE) {
|
||||
&& rule1.baseValue % (Math.pow(rule1.radix, rule1.exponent)) == 0)
|
||||
|| rule1.baseValue == IMPROPER_FRACTION_RULE
|
||||
|| rule1.baseValue == MASTER_RULE) {
|
||||
|
||||
// if it passes that test, new up the second rule. If the
|
||||
// rule set both rules will belong to is a fraction rule
|
||||
@ -328,7 +328,7 @@ final class NFRule {
|
||||
radix = Integer.parseInt(tempValue.toString());
|
||||
if (radix == 0) {
|
||||
throw new IllegalArgumentException("Rule can't have radix of 0");
|
||||
}
|
||||
}
|
||||
exponent = expectedExponent();
|
||||
}
|
||||
|
||||
@ -407,7 +407,7 @@ final class NFRule {
|
||||
// at the end of the rule text
|
||||
if (subStart == -1) {
|
||||
return NFSubstitution.makeSubstitution(ruleText.length(), this, predecessor,
|
||||
owner, ownersOwner, "");
|
||||
owner, ownersOwner, "");
|
||||
}
|
||||
|
||||
// special-case the ">>>" token, since searching for the > at the
|
||||
@ -415,10 +415,19 @@ final class NFRule {
|
||||
if (ruleText.substring(subStart).startsWith(">>>")) {
|
||||
subEnd = subStart + 2;
|
||||
|
||||
// otherwise the substitution token ends with the same character
|
||||
// it began with
|
||||
// otherwise the substitution token ends with the same character
|
||||
// it began with
|
||||
} else {
|
||||
subEnd = ruleText.indexOf(ruleText.charAt(subStart), subStart + 1);
|
||||
char c = ruleText.charAt(subStart);
|
||||
subEnd = ruleText.indexOf(c, subStart + 1);
|
||||
// special case for '<%foo<<'
|
||||
if (c == '<' && subEnd != -1 && subEnd < ruleText.length() - 1 && ruleText.charAt(subEnd+1) == c) {
|
||||
// ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '==' in the middle
|
||||
// occurs because of the juxtaposition of two different rules. The check for '<' is a hack
|
||||
// to get around this. Having the duplicate at the front would cause problems with
|
||||
// rules like "<<%" to format, say, percents...
|
||||
++subEnd;
|
||||
}
|
||||
}
|
||||
|
||||
// if we don't find the end of the token (i.e., if we're on a single,
|
||||
@ -426,14 +435,14 @@ final class NFRule {
|
||||
// at the end of the rule
|
||||
if (subEnd == -1) {
|
||||
return NFSubstitution.makeSubstitution(ruleText.length(), this, predecessor,
|
||||
owner, ownersOwner, "");
|
||||
owner, ownersOwner, "");
|
||||
}
|
||||
|
||||
// if we get here, we have a real substitution token (or at least
|
||||
// some text bounded by substitution token characters). Use
|
||||
// makeSubstitution() to create the right kind of substitution
|
||||
result = NFSubstitution.makeSubstitution(subStart, this, predecessor, owner,
|
||||
ownersOwner, ruleText.substring(subStart, subEnd + 1));
|
||||
ownersOwner, ruleText.substring(subStart, subEnd + 1));
|
||||
|
||||
// remove the substitution from the rule text
|
||||
ruleText = ruleText.substring(0, subStart) + ruleText.substring(subEnd + 1);
|
||||
@ -471,8 +480,8 @@ final class NFRule {
|
||||
sub2.setDivisor(radix, exponent);
|
||||
}
|
||||
|
||||
// if this is a special rule, its radix and exponent are basically
|
||||
// ignored. Set them to "safe" default values
|
||||
// if this is a special rule, its radix and exponent are basically
|
||||
// ignored. Set them to "safe" default values
|
||||
} else {
|
||||
radix = 10;
|
||||
exponent = 0;
|
||||
@ -534,17 +543,17 @@ final class NFRule {
|
||||
* @return True if the two rules are functionally equivalent
|
||||
*/
|
||||
public boolean equals(Object that) {
|
||||
if (that instanceof NFRule) {
|
||||
if (that instanceof NFRule) {
|
||||
NFRule that2 = (NFRule)that;
|
||||
|
||||
return baseValue == that2.baseValue
|
||||
&& radix == that2.radix
|
||||
&& exponent == that2.exponent
|
||||
&& ruleText.equals(that2.ruleText)
|
||||
&& sub1.equals(that2.sub1)
|
||||
&& sub2.equals(that2.sub2);
|
||||
}
|
||||
return false;
|
||||
&& radix == that2.radix
|
||||
&& exponent == that2.exponent
|
||||
&& ruleText.equals(that2.ruleText)
|
||||
&& sub1.equals(that2.sub1)
|
||||
&& sub2.equals(that2.sub2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -701,7 +710,7 @@ final class NFRule {
|
||||
// multiple of 100. This is called the "rollback rule."
|
||||
if ((sub1.isModulusSubstitution()) || (sub2.isModulusSubstitution())) {
|
||||
return (number % Math.pow(radix, exponent)) == 0
|
||||
&& (baseValue % Math.pow(radix, exponent)) != 0;
|
||||
&& (baseValue % Math.pow(radix, exponent)) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -729,7 +738,7 @@ final class NFRule {
|
||||
* result is an integer and Double otherwise. The result is never null.
|
||||
*/
|
||||
public Number doParse(String text, ParsePosition parsePosition, boolean isFractionRule,
|
||||
double upperBound) {
|
||||
double upperBound) {
|
||||
|
||||
// internally we operate on a copy of the string being parsed
|
||||
// (because we're going to change it) and use our own ParsePosition
|
||||
@ -744,8 +753,8 @@ final class NFRule {
|
||||
int prefixLength = text.length() - workText.length();
|
||||
|
||||
if (pp.getIndex() == 0 && sub1.getPos() != 0) {
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// parsePosition.setErrorIndex(pp.getErrorIndex());
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// parsePosition.setErrorIndex(pp.getErrorIndex());
|
||||
return new Long(0);
|
||||
}
|
||||
|
||||
@ -790,8 +799,8 @@ final class NFRule {
|
||||
// the substitution, giving us a new partial parse result
|
||||
pp.setIndex(0);
|
||||
double partialResult = matchToDelimiter(workText, start, tempBaseValue,
|
||||
ruleText.substring(sub1.getPos(), sub2.getPos()), pp, sub1,
|
||||
upperBound).doubleValue();
|
||||
ruleText.substring(sub1.getPos(), sub2.getPos()), pp, sub1,
|
||||
upperBound).doubleValue();
|
||||
|
||||
// if we got a successful match (or were trying to match a
|
||||
// null substitution), pp is now pointing at the first unmatched
|
||||
@ -808,8 +817,8 @@ final class NFRule {
|
||||
// substitution if there's a successful match, giving us
|
||||
// a real result
|
||||
partialResult = matchToDelimiter(workText2, 0, partialResult,
|
||||
ruleText.substring(sub2.getPos()), pp2, sub2,
|
||||
upperBound).doubleValue();
|
||||
ruleText.substring(sub2.getPos()), pp2, sub2,
|
||||
upperBound).doubleValue();
|
||||
|
||||
// if we got a successful match on this second
|
||||
// matchToDelimiter() call, update the high-water mark
|
||||
@ -820,36 +829,36 @@ final class NFRule {
|
||||
result = partialResult;
|
||||
}
|
||||
}
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// else {
|
||||
// int temp = pp2.getErrorIndex() + sub1.getPos() + pp.getIndex();
|
||||
// if (temp> parsePosition.getErrorIndex()) {
|
||||
// parsePosition.setErrorIndex(temp);
|
||||
// }
|
||||
// }
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// else {
|
||||
// int temp = pp2.getErrorIndex() + sub1.getPos() + pp.getIndex();
|
||||
// if (temp> parsePosition.getErrorIndex()) {
|
||||
// parsePosition.setErrorIndex(temp);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// else {
|
||||
// int temp = sub1.getPos() + pp.getErrorIndex();
|
||||
// if (temp > parsePosition.getErrorIndex()) {
|
||||
// parsePosition.setErrorIndex(temp);
|
||||
// }
|
||||
// }
|
||||
// keep trying to match things until the outer matchToDelimiter()
|
||||
// call fails to make a match (each time, it picks up where it
|
||||
// left off the previous time)
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// else {
|
||||
// int temp = sub1.getPos() + pp.getErrorIndex();
|
||||
// if (temp > parsePosition.getErrorIndex()) {
|
||||
// parsePosition.setErrorIndex(temp);
|
||||
// }
|
||||
// }
|
||||
// keep trying to match things until the outer matchToDelimiter()
|
||||
// call fails to make a match (each time, it picks up where it
|
||||
// left off the previous time)
|
||||
} while (sub1.getPos() != sub2.getPos() && pp.getIndex() > 0 && pp.getIndex()
|
||||
< workText.length() && pp.getIndex() != start);
|
||||
< workText.length() && pp.getIndex() != start);
|
||||
|
||||
// update the caller's ParsePosition with our high-water mark
|
||||
// (i.e., it now points at the first character this function
|
||||
// didn't match-- the ParsePosition is therefore unchanged if
|
||||
// we didn't match anything)
|
||||
parsePosition.setIndex(highWaterMark);
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// if (highWaterMark > 0) {
|
||||
// parsePosition.setErrorIndex(0);
|
||||
// }
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// if (highWaterMark > 0) {
|
||||
// parsePosition.setErrorIndex(0);
|
||||
// }
|
||||
|
||||
// this is a hack for one unusual condition: Normally, whether this
|
||||
// rule belong to a fraction rule set or not is handled by its
|
||||
@ -901,7 +910,7 @@ final class NFRule {
|
||||
pp.setIndex(pp.getIndex() + pfl);
|
||||
return text.substring(pfl);
|
||||
|
||||
// if we didn't get a successful match, leave everything alone
|
||||
// if we didn't get a successful match, leave everything alone
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
@ -935,7 +944,7 @@ final class NFRule {
|
||||
* Double.
|
||||
*/
|
||||
private Number matchToDelimiter(String text, int startPos, double baseValue,
|
||||
String delimiter, ParsePosition pp, NFSubstitution sub, double upperBound) {
|
||||
String delimiter, ParsePosition pp, NFSubstitution sub, double upperBound) {
|
||||
// if "delimiter" contains real (i.e., non-ignorable) text, search
|
||||
// it for "delimiter" beginning at "start". If that succeeds, then
|
||||
// use "sub"'s doParse() method to match the text before the
|
||||
@ -958,7 +967,7 @@ final class NFRule {
|
||||
String subText = text.substring(0, dPos);
|
||||
if (subText.length() > 0) {
|
||||
tempResult = sub.doParse(subText, tempPP, baseValue, upperBound,
|
||||
formatter.lenientParseEnabled());
|
||||
formatter.lenientParseEnabled());
|
||||
|
||||
// if the substitution could match all the text up to
|
||||
// where we found "delimiter", then this function has
|
||||
@ -970,14 +979,14 @@ final class NFRule {
|
||||
pp.setIndex(dPos + dLen);
|
||||
return tempResult;
|
||||
}
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// else {
|
||||
// if (tempPP.getErrorIndex() > 0) {
|
||||
// pp.setErrorIndex(tempPP.getErrorIndex());
|
||||
// } else {
|
||||
// pp.setErrorIndex(tempPP.getIndex());
|
||||
// }
|
||||
// }
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// else {
|
||||
// if (tempPP.getErrorIndex() > 0) {
|
||||
// pp.setErrorIndex(tempPP.getErrorIndex());
|
||||
// } else {
|
||||
// pp.setErrorIndex(tempPP.getIndex());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// if we didn't match the substitution, search for another
|
||||
@ -993,10 +1002,10 @@ final class NFRule {
|
||||
pp.setIndex(0);
|
||||
return new Long(0);
|
||||
|
||||
// if "delimiter" is empty, or consists only of ignorable characters
|
||||
// (i.e., is semantically empty), thwe we obviously can't search
|
||||
// for "delimiter". Instead, just use "sub" to parse as much of
|
||||
// "text" as possible.
|
||||
// if "delimiter" is empty, or consists only of ignorable characters
|
||||
// (i.e., is semantically empty), thwe we obviously can't search
|
||||
// for "delimiter". Instead, just use "sub" to parse as much of
|
||||
// "text" as possible.
|
||||
} else {
|
||||
ParsePosition tempPP = new ParsePosition(0);
|
||||
Number result = new Long(0);
|
||||
@ -1004,7 +1013,7 @@ final class NFRule {
|
||||
|
||||
// try to match the whole string against the substitution
|
||||
tempResult = sub.doParse(text, tempPP, baseValue, upperBound,
|
||||
formatter.lenientParseEnabled());
|
||||
formatter.lenientParseEnabled());
|
||||
if (tempPP.getIndex() != 0 || sub.isNullSubstitution()) {
|
||||
// if there's a successful match (or it's a null
|
||||
// substitution), update pp to point to the first
|
||||
@ -1015,10 +1024,10 @@ final class NFRule {
|
||||
result = tempResult;
|
||||
}
|
||||
}
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// else {
|
||||
// pp.setErrorIndex(tempPP.getErrorIndex());
|
||||
// }
|
||||
// commented out because ParsePosition doesn't have error index in 1.1.x
|
||||
// else {
|
||||
// pp.setErrorIndex(tempPP.getErrorIndex());
|
||||
// }
|
||||
|
||||
// and if we get to here, then nothing matched, so we return
|
||||
// 0 and leave pp alone
|
||||
@ -1073,13 +1082,13 @@ final class NFRule {
|
||||
while (oPrefix != CollationElementIterator.NULLORDER) {
|
||||
// skip over ignorable characters in the target string
|
||||
while (CollationElementIterator.primaryOrder(oStr) == 0 && oStr !=
|
||||
CollationElementIterator.NULLORDER) {
|
||||
CollationElementIterator.NULLORDER) {
|
||||
oStr = strIter.next();
|
||||
}
|
||||
|
||||
// skip over ignorable characters in the prefix
|
||||
while (CollationElementIterator.primaryOrder(oPrefix) == 0 && oPrefix !=
|
||||
CollationElementIterator.NULLORDER) {
|
||||
CollationElementIterator.NULLORDER) {
|
||||
oPrefix = prefixIter.next();
|
||||
}
|
||||
|
||||
@ -1099,7 +1108,7 @@ final class NFRule {
|
||||
// (considering only primary differences). If we
|
||||
// get a mismatch, dump out and return 0
|
||||
if (CollationElementIterator.primaryOrder(oStr) != CollationElementIterator.
|
||||
primaryOrder(oPrefix)) {
|
||||
primaryOrder(oPrefix)) {
|
||||
return 0;
|
||||
}
|
||||
// otherwise, advance to the next character in each string
|
||||
@ -1118,47 +1127,47 @@ final class NFRule {
|
||||
return result;
|
||||
|
||||
/*
|
||||
//----------------------------------------------------------------
|
||||
// JDK 1.2-specific API call
|
||||
// return strIter.getOffset();
|
||||
//----------------------------------------------------------------
|
||||
// JDK 1.1 HACK (take out for 1.2-specific code)
|
||||
//----------------------------------------------------------------
|
||||
// JDK 1.2-specific API call
|
||||
// return strIter.getOffset();
|
||||
//----------------------------------------------------------------
|
||||
// JDK 1.1 HACK (take out for 1.2-specific code)
|
||||
|
||||
// if we make it to here, we have a successful match. Now we
|
||||
// have to find out HOW MANY characters from the target string
|
||||
// matched the prefix (there isn't necessarily a one-to-one
|
||||
// mapping between collation elements and characters).
|
||||
// In JDK 1.2, there's a simple getOffset() call we can use.
|
||||
// In JDK 1.1, on the other hand, we have to go through some
|
||||
// ugly contortions. First, use the collator to compare the
|
||||
// same number of characters from the prefix and target string.
|
||||
// If they're equal, we're done.
|
||||
collator.setStrength(Collator.PRIMARY);
|
||||
if (str.length() >= prefix.length()
|
||||
&& collator.equals(str.substring(0, prefix.length()), prefix)) {
|
||||
return prefix.length();
|
||||
}
|
||||
// if we make it to here, we have a successful match. Now we
|
||||
// have to find out HOW MANY characters from the target string
|
||||
// matched the prefix (there isn't necessarily a one-to-one
|
||||
// mapping between collation elements and characters).
|
||||
// In JDK 1.2, there's a simple getOffset() call we can use.
|
||||
// In JDK 1.1, on the other hand, we have to go through some
|
||||
// ugly contortions. First, use the collator to compare the
|
||||
// same number of characters from the prefix and target string.
|
||||
// If they're equal, we're done.
|
||||
collator.setStrength(Collator.PRIMARY);
|
||||
if (str.length() >= prefix.length()
|
||||
&& collator.equals(str.substring(0, prefix.length()), prefix)) {
|
||||
return prefix.length();
|
||||
}
|
||||
|
||||
// if they're not equal, then we have to compare successively
|
||||
// larger and larger substrings of the target string until we
|
||||
// get to one that matches the prefix. At that point, we know
|
||||
// how many characters matched the prefix, and we can return.
|
||||
int p = 1;
|
||||
while (p <= str.length()) {
|
||||
if (collator.equals(str.substring(0, p), prefix)) {
|
||||
return p;
|
||||
} else {
|
||||
++p;
|
||||
}
|
||||
}
|
||||
// if they're not equal, then we have to compare successively
|
||||
// larger and larger substrings of the target string until we
|
||||
// get to one that matches the prefix. At that point, we know
|
||||
// how many characters matched the prefix, and we can return.
|
||||
int p = 1;
|
||||
while (p <= str.length()) {
|
||||
if (collator.equals(str.substring(0, p), prefix)) {
|
||||
return p;
|
||||
} else {
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
// SHOULKD NEVER GET HERE!!!
|
||||
return 0;
|
||||
//----------------------------------------------------------------
|
||||
// SHOULKD NEVER GET HERE!!!
|
||||
return 0;
|
||||
//----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// If lenient parsing is turned off, forget all that crap above.
|
||||
// Just use String.startsWith() and be done with it.
|
||||
// If lenient parsing is turned off, forget all that crap above.
|
||||
// Just use String.startsWith() and be done with it.
|
||||
} else {
|
||||
if (str.startsWith(prefix)) {
|
||||
return prefix.length();
|
||||
@ -1206,8 +1215,8 @@ final class NFRule {
|
||||
if (!formatter.lenientParseEnabled()) {
|
||||
return new int[] { str.indexOf(key, startingAt), key.length() };
|
||||
|
||||
// but if lenient parsing is turned ON, we've got some work
|
||||
// ahead of us
|
||||
// but if lenient parsing is turned ON, we've got some work
|
||||
// ahead of us
|
||||
} else {
|
||||
//----------------------------------------------------------------
|
||||
// JDK 1.1 HACK (take out of 1.2-specific code)
|
||||
@ -1319,8 +1328,8 @@ final class NFRule {
|
||||
o = iter.next();
|
||||
}
|
||||
return o == CollationElementIterator.NULLORDER;
|
||||
// if lenient parsing is turned off, there is no such thing as
|
||||
// an ignorable character: return true only if the string is empty
|
||||
// if lenient parsing is turned off, there is no such thing as
|
||||
// an ignorable character: return true only if the string is empty
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ abstract class NFSubstitution {
|
||||
* Puts a copyright in the .class file
|
||||
*/
|
||||
private static final String copyrightNotice
|
||||
= "Copyright \u00a91997-1998 IBM Corp. All rights reserved.";
|
||||
= "Copyright \u00a91997-2004 IBM Corp. All rights reserved.";
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// data members
|
||||
@ -1564,6 +1564,11 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
*/
|
||||
double denominator;
|
||||
|
||||
/**
|
||||
* True if we format leading zeros (this is a hack for Hebrew spellout)
|
||||
*/
|
||||
boolean withZeros;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// construction
|
||||
//-----------------------------------------------------------------------
|
||||
@ -1578,12 +1583,20 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
NFRuleSet ruleSet,
|
||||
RuleBasedNumberFormat formatter,
|
||||
String description) {
|
||||
super(pos, ruleSet, formatter, description);
|
||||
super(pos, ruleSet, formatter, fixdesc(description));
|
||||
|
||||
// this substitution's behavior depends on the rule's base value
|
||||
// Rather than keeping a backpointer to the rule, we copy its
|
||||
// base value here
|
||||
this.denominator = denominator;
|
||||
|
||||
this.withZeros = description.endsWith("<<");
|
||||
}
|
||||
|
||||
static String fixdesc(String description) {
|
||||
return description.endsWith("<<")
|
||||
? description.substring(0,description.length()-1)
|
||||
: description;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -1608,6 +1621,50 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
// formatting
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Performs a mathematical operation on the number, formats it using
|
||||
* either ruleSet or decimalFormat, and inserts the result into
|
||||
* toInsertInto.
|
||||
* @param number The number being formatted.
|
||||
* @param toInsertInto The string we insert the result into
|
||||
* @param pos The position in toInsertInto where the owning rule's
|
||||
* rule text begins (this value is added to this substitution's
|
||||
* position to determine exactly where to insert the new text)
|
||||
*/
|
||||
public void doSubstitution(double number, StringBuffer toInsertInto, int pos) {
|
||||
// perform a transformation on the number being formatted that
|
||||
// is dependent on the type of substitution this is
|
||||
String s = toInsertInto.toString();
|
||||
double numberToFormat = transformNumber(number);
|
||||
|
||||
if (withZeros && ruleSet != null) {
|
||||
// if there are leading zeros in the decimal expansion then emit them
|
||||
long nf = (long)numberToFormat;
|
||||
int len = toInsertInto.length();
|
||||
while ((nf *= 10) < denominator) {
|
||||
toInsertInto.insert(pos + this.pos, ' ');
|
||||
ruleSet.format(0, toInsertInto, pos + this.pos);
|
||||
}
|
||||
pos += toInsertInto.length() - len;
|
||||
}
|
||||
|
||||
// if the result is an integer, from here on out we work in integer
|
||||
// space (saving time and memory and preserving accuracy)
|
||||
if (numberToFormat == Math.floor(numberToFormat) && ruleSet != null) {
|
||||
ruleSet.format((long)numberToFormat, toInsertInto, pos + this.pos);
|
||||
|
||||
// if the result isn't an integer, then call either our rule set's
|
||||
// format() method or our DecimalFormat's format() method to
|
||||
// format the result
|
||||
} else {
|
||||
if (ruleSet != null) {
|
||||
ruleSet.format(numberToFormat, toInsertInto, pos + this.pos);
|
||||
} else {
|
||||
toInsertInto.insert(pos + this.pos, numberFormat.format(numberToFormat));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number being formatted times the denominator.
|
||||
* @param number The number being formatted
|
||||
@ -1639,7 +1696,62 @@ class NumeratorSubstitution extends NFSubstitution {
|
||||
// we don't have to do anything special to do the parsing here,
|
||||
// but we have to turn lenient parsing off-- if we leave it on,
|
||||
// it SERIOUSLY messes up the algorithm
|
||||
return super.doParse(text, parsePosition, baseValue, upperBound, false);
|
||||
|
||||
// if withZeros is true, we need to count the zeros
|
||||
// and use that to adjust the parse result
|
||||
int zeroCount = 0;
|
||||
if (withZeros) {
|
||||
String workText = new String(text);
|
||||
ParsePosition workPos = new ParsePosition(1);
|
||||
int digit;
|
||||
|
||||
while (workText.length() > 0 && workPos.getIndex() != 0) {
|
||||
workPos.setIndex(0);
|
||||
digit = ruleSet.parse(workText, workPos, 1).intValue(); // parse zero or nothing at all
|
||||
if (workPos.getIndex() == 0) {
|
||||
// we failed, either there were no more zeros, or the number was formatted with digits
|
||||
// either way, we're done
|
||||
break;
|
||||
}
|
||||
|
||||
++zeroCount;
|
||||
parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
|
||||
workText = workText.substring(workPos.getIndex());
|
||||
while (workText.length() > 0 && workText.charAt(0) == ' ') {
|
||||
workText = workText.substring(1);
|
||||
parsePosition.setIndex(parsePosition.getIndex() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
text = text.substring(parsePosition.getIndex()); // arrgh!
|
||||
parsePosition.setIndex(0);
|
||||
}
|
||||
|
||||
// we've parsed off the zeros, now let's parse the rest from our current position
|
||||
Number result = super.doParse(text, parsePosition, withZeros ? 1 : baseValue, upperBound, false);
|
||||
|
||||
if (withZeros) {
|
||||
// any base value will do in this case. is there a way to
|
||||
// force this to not bother trying all the base values?
|
||||
|
||||
// compute the 'effective' base and prescale the value down
|
||||
long n = result.longValue();
|
||||
long d = 1;
|
||||
int pow = 0;
|
||||
while (d <= n) {
|
||||
d *= 10;
|
||||
++pow;
|
||||
}
|
||||
// now add the zeros
|
||||
while (zeroCount > 0) {
|
||||
d *= 10;
|
||||
--zeroCount;
|
||||
}
|
||||
// d is now our true denominator
|
||||
result = new Double(n/(double)d);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user