ICU-10837 Add ScientificFormatHelper class.

X-SVN-Rev: 35669
This commit is contained in:
Travis Keep 2014-04-30 20:36:11 +00:00
parent fd676bb762
commit b76ad017cb
5 changed files with 292 additions and 3 deletions

2
.gitattributes vendored
View File

@ -263,6 +263,7 @@ icu4j/main/classes/core/.settings/edu.umd.cs.findbugs.core.prefs -text
icu4j/main/classes/core/.settings/org.eclipse.core.resources.prefs -text
icu4j/main/classes/core/.settings/org.eclipse.jdt.core.prefs -text
icu4j/main/classes/core/manifest.stub -text
icu4j/main/classes/core/src/com/ibm/icu/text/ScientificFormatHelper.java -text
icu4j/main/classes/currdata/.externalToolBuilders/copy-data-currdata.launch -text
icu4j/main/classes/currdata/.settings/org.eclipse.core.resources.prefs -text
icu4j/main/classes/currdata/.settings/org.eclipse.jdt.core.prefs -text
@ -323,6 +324,7 @@ icu4j/main/tests/core/manifest.stub -text
icu4j/main/tests/core/src/com/ibm/icu/dev/data/rbbi/english.dict -text
icu4j/main/tests/core/src/com/ibm/icu/dev/data/resources/testmessages.properties -text
icu4j/main/tests/core/src/com/ibm/icu/dev/data/thai6.ucs -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/ScientificFormatHelperTest.java -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.OlsonTimeZone.dat -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.TimeZoneAdapter.dat -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.math.BigDecimal.dat -text

View File

@ -2279,7 +2279,7 @@ public class DecimalFormat extends NumberFormat {
0xFF0E, 0xFF0E,
0xFF61, 0xFF61).freeze();
private static final UnicodeSet minusSigns =
static final UnicodeSet minusSigns =
new UnicodeSet(
0x002D, 0x002D,
0x207B, 0x207B,
@ -2289,7 +2289,7 @@ public class DecimalFormat extends NumberFormat {
0xFE63, 0xFE63,
0xFF0D, 0xFF0D).freeze();
private static final UnicodeSet plusSigns =
static final UnicodeSet plusSigns =
new UnicodeSet(
0x002B, 0x002B,
0x207A, 0x207A,

View File

@ -0,0 +1,235 @@
/*
*******************************************************************************
* Copyright (C) 2014, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
package com.ibm.icu.text;
import java.text.AttributedCharacterIterator;
import java.text.AttributedCharacterIterator.Attribute;
import java.text.CharacterIterator;
import java.util.Map;
import com.ibm.icu.lang.UCharacter;
/**
* A helper class for formatting in user-friendly scientific notation.
*
* ScientificFormatHelper instances are immutable and thread-safe. However, the
* AttributedCharacterIterator instances that ScientificFormatHelper instances format must
* not be shared across multiple threads.
*
* Sample code:
* <pre>
* DecimalFormat decfmt = (DecimalFormat) NumberFormat.getScientificInstance(new ULocale("en"));
* AttributedCharacterIterator iterator = decfmt.formatToCharacterIterator(1.23456e-78);
* ScientificFormatHelper helper = ScientificFormatHelper.getInstance(
decfmt.getDecimalFormatSymbols());
* <pre>
* // Output: "1.23456×10<sup>-78</sup>"
* System.out.println(helper.insertMarkup(iterator, "<sup>", "</sup>"));
* </pre>
*
* @see NumberFormat
* @provisional
* @draft ICU 54
*
*/
public final class ScientificFormatHelper {
private static final char[] SUPERSCRIPT_DIGITS = {
0x2070, 0xB9, 0xB2, 0xB3, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079
};
private static final char SUPERSCRIPT_PLUS_SIGN = 0x207A;
private static final char SUPERSCRIPT_MINUS_SIGN = 0x207B;
private final String preExponent;
private ScientificFormatHelper(String preExponent) {
this.preExponent = preExponent;
}
/**
* Returns a new ScientificFormatHelper.
* @param dfs comes from the DecimalFormat instance used for default scientific notation.
* @provisional
* @draft ICU 54
*/
public static ScientificFormatHelper getInstance(DecimalFormatSymbols dfs) {
StringBuilder preExponent = new StringBuilder();
preExponent.append(getMultiplicationSymbol(dfs));
char[] digits = dfs.getDigits();
preExponent.append(digits[1]).append(digits[0]);
return new ScientificFormatHelper(preExponent.toString());
}
private static String getMultiplicationSymbol(DecimalFormatSymbols dfs) {
//TODO: revisit this
return "\u00d7";
}
/**
* Makes scientific notation user-friendly by surrounding exponent with
* html to make it superscript.
* @param iterator the value that DecimalFormat.formatToCharacterIterator() returned.
* @param beginMarkup the start html for the exponent e.g "<sup>"
* @param endMarkup the end html for the exponent e.g "</sup>"
* @return the user-friendly scientific notation.
* @provisional
* @draft ICU 54
*/
public String insertMarkup(
AttributedCharacterIterator iterator,
CharSequence beginMarkup,
CharSequence endMarkup) {
int copyFromOffset = 0;
StringBuilder result = new StringBuilder();
for (
iterator.first();
iterator.current() != CharacterIterator.DONE;
) {
Map<Attribute, Object> attributeSet = iterator.getAttributes();
if (attributeSet.containsKey(NumberFormat.Field.EXPONENT_SYMBOL)) {
append(
iterator,
copyFromOffset,
iterator.getRunStart(NumberFormat.Field.EXPONENT_SYMBOL),
result);
copyFromOffset = iterator.getRunLimit(NumberFormat.Field.EXPONENT_SYMBOL);
iterator.setIndex(copyFromOffset);
result.append(preExponent);
result.append(beginMarkup);
} else if (attributeSet.containsKey(NumberFormat.Field.EXPONENT)) {
int limit = iterator.getRunLimit(NumberFormat.Field.EXPONENT);
append(
iterator,
copyFromOffset,
limit,
result);
copyFromOffset = limit;
iterator.setIndex(copyFromOffset);
result.append(endMarkup);
} else {
iterator.next();
}
}
append(iterator, copyFromOffset, iterator.getEndIndex(), result);
return result.toString();
}
private static void append(
AttributedCharacterIterator iterator,
int start,
int limit,
StringBuilder result) {
int oldIndex = iterator.getIndex();
iterator.setIndex(start);
for (int i = start; i < limit; i++) {
result.append(iterator.current());
iterator.next();
}
iterator.setIndex(oldIndex);
}
/**
* Makes scientific notation user-friendly by using specific code points
* for superscript 0..9, -, and + in the exponent rather than by using
* html.
* @param iterator the value that DecimalFormat.formatToCharacterIterator() returned.
* @return the user-friendly scientific notation.
* @provisional
* @draft ICU 54
*/
public String toSuperscriptExponentDigits(AttributedCharacterIterator iterator) {
int copyFromOffset = 0;
StringBuilder result = new StringBuilder();
for (
iterator.first();
iterator.current() != CharacterIterator.DONE;
) {
Map<Attribute, Object> attributeSet = iterator.getAttributes();
if (attributeSet.containsKey(NumberFormat.Field.EXPONENT_SYMBOL)) {
append(
iterator,
copyFromOffset,
iterator.getRunStart(NumberFormat.Field.EXPONENT_SYMBOL),
result);
copyFromOffset = iterator.getRunLimit(NumberFormat.Field.EXPONENT_SYMBOL);
iterator.setIndex(copyFromOffset);
result.append(preExponent);
} else if (attributeSet.containsKey(NumberFormat.Field.EXPONENT_SIGN)) {
int start = iterator.getRunStart(NumberFormat.Field.EXPONENT_SIGN);
int limit = iterator.getRunLimit(NumberFormat.Field.EXPONENT_SIGN);
int aChar = char32AtAndAdvance(iterator);
if (DecimalFormat.minusSigns.contains(aChar)) {
append(
iterator,
copyFromOffset,
start,
result);
result.append(SUPERSCRIPT_MINUS_SIGN);
} else if (DecimalFormat.plusSigns.contains(aChar)) {
append(
iterator,
copyFromOffset,
start,
result);
result.append(SUPERSCRIPT_PLUS_SIGN);
} else {
throw new IllegalArgumentException();
}
copyFromOffset = limit;
iterator.setIndex(copyFromOffset);
} else if (attributeSet.containsKey(NumberFormat.Field.EXPONENT)) {
int start = iterator.getRunStart(NumberFormat.Field.EXPONENT);
int limit = iterator.getRunLimit(NumberFormat.Field.EXPONENT);
append(
iterator,
copyFromOffset,
start,
result);
copyAsSuperscript(iterator, start, limit, result);
copyFromOffset = limit;
iterator.setIndex(copyFromOffset);
} else {
iterator.next();
}
}
append(iterator, copyFromOffset, iterator.getEndIndex(), result);
return result.toString();
}
private static void copyAsSuperscript(
AttributedCharacterIterator iterator, int start, int limit, StringBuilder result) {
int oldIndex = iterator.getIndex();
iterator.setIndex(start);
while (iterator.getIndex() < limit) {
int aChar = char32AtAndAdvance(iterator);
int digit = UCharacter.digit(aChar);
if (digit < 0) {
throw new IllegalArgumentException();
}
result.append(SUPERSCRIPT_DIGITS[digit]);
}
iterator.setIndex(oldIndex);
}
private static int char32AtAndAdvance(AttributedCharacterIterator iterator) {
char c1 = iterator.current();
iterator.next();
if (UCharacter.isHighSurrogate(c1)) {
char c2 = iterator.current();
if (c2 != CharacterIterator.DONE) {
if (UCharacter.isLowSurrogate(c2)) {
iterator.next();
return UCharacter.toCodePoint(c1, c2);
}
}
}
return c1;
}
}

View File

@ -0,0 +1,51 @@
/*
*******************************************************************************
* Copyright (C) 2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.dev.test.format;
import java.text.AttributedCharacterIterator;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.text.DecimalFormat;
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.text.ScientificFormatHelper;
import com.ibm.icu.util.ULocale;
public class ScientificFormatHelperTest extends TestFmwk {
public static void main(String[] args) throws Exception {
new ScientificFormatHelperTest().run(args);
}
public void TestBasic() {
ULocale en = new ULocale("en");
DecimalFormat decfmt = (DecimalFormat) NumberFormat.getScientificInstance(en);
AttributedCharacterIterator iterator = decfmt.formatToCharacterIterator(1.23456e-78);
ScientificFormatHelper helper = ScientificFormatHelper.getInstance(
decfmt.getDecimalFormatSymbols());
assertEquals(
"insetMarkup",
"1.23456\u00d710<sup>-78</sup>",
helper.insertMarkup(iterator, "<sup>", "</sup>"));
assertEquals(
"toSuperscriptExponentDigits",
"1.23456\u00d710\u207b\u2077\u2078",
helper.toSuperscriptExponentDigits(iterator));
}
public void TestPlusSignInExponent() {
ULocale en = new ULocale("en");
DecimalFormat decfmt = (DecimalFormat) NumberFormat.getScientificInstance(en);
decfmt.applyPattern("0.00E+0");
AttributedCharacterIterator iterator = decfmt.formatToCharacterIterator(6.02e23);
ScientificFormatHelper helper = ScientificFormatHelper.getInstance(
decfmt.getDecimalFormatSymbols());
assertEquals(
"",
"6.02\u00d710\u207a\u00b2\u00b3",
helper.toSuperscriptExponentDigits(iterator));
}
}

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (c) 2004-2013, International Business Machines
* Copyright (c) 2004-2014, International Business Machines
* Corporation and others. All Rights Reserved.
* Copyright (C) 2010 , Yahoo! Inc.
*******************************************************************************
@ -58,6 +58,7 @@ public class TestAll extends TestGroup {
"NumberFormatRoundTripTest",
"NumberRegression",
"NumberFormatRegressionTest",
"ScientificFormatHelperTest",
"IntlTestDecimalFormatAPI",
"IntlTestDecimalFormatAPIC",
"IntlTestDecimalFormatSymbols",