ICU-10046 Introduce ScientificFormatHelper class.

X-SVN-Rev: 35612
This commit is contained in:
Travis Keep 2014-04-09 23:00:45 +00:00
parent a98683b629
commit 7ed712add5
11 changed files with 409 additions and 5 deletions

3
.gitattributes vendored
View file

@ -74,6 +74,8 @@ icu4c/source/extra/uconv/uconv.vcxproj -text
icu4c/source/extra/uconv/uconv.vcxproj.filters -text
icu4c/source/i18n/i18n.vcxproj -text
icu4c/source/i18n/i18n.vcxproj.filters -text
icu4c/source/i18n/scientificformathelper.cpp -text
icu4c/source/i18n/unicode/scientificformathelper.h -text
icu4c/source/io/io.vcxproj -text
icu4c/source/io/io.vcxproj.filters -text
icu4c/source/layout/layout.vcxproj -text
@ -141,6 +143,7 @@ icu4c/source/test/cintltst/cintltst.vcxproj -text
icu4c/source/test/cintltst/cintltst.vcxproj.filters -text
icu4c/source/test/intltest/intltest.vcxproj -text
icu4c/source/test/intltest/intltest.vcxproj.filters -text
icu4c/source/test/intltest/scientificformathelpertest.cpp -text
icu4c/source/test/iotest/iotest.vcxproj -text
icu4c/source/test/iotest/iotest.vcxproj.filters -text
icu4c/source/test/letest/cletest.vcxproj -text

View file

@ -94,7 +94,7 @@ uspoof.o uspoof_impl.o uspoof_build.o uspoof_conf.o uspoof_wsconf.o decfmtst.o s
ztrans.o zrule.o vzone.o fphdlimp.o fpositer.o locdspnm.o \
decNumber.o decContext.o alphaindex.o tznames.o tznames_impl.o tzgnames.o \
tzfmt.o compactdecimalformat.o gender.o region.o scriptset.o identifier_info.o \
uregion.o reldatefmt.o quantityformatter.o measunit.o filteredbrk.o
uregion.o reldatefmt.o quantityformatter.o measunit.o filteredbrk.o scientificformathelper.o
## Header files to install
HEADERS = $(srcdir)/unicode/*.h

View file

@ -347,6 +347,7 @@
<DisableLanguageExtensions>false</DisableLanguageExtensions>
</ClCompile>
<ClCompile Include="reldtfmt.cpp" />
<ClCompile Include="scientificformathelper.cpp" />
<ClCompile Include="selfmt.cpp" />
<ClCompile Include="simpletz.cpp" />
<ClCompile Include="scriptset.cpp" />
@ -1196,6 +1197,20 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<ClInclude Include="reldtfmt.h" />
<CustomBuild Include="unicode\scientificformathelper.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="unicode\selfmt.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
@ -1687,4 +1702,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -228,6 +228,9 @@
<ClCompile Include="reldtfmt.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="scientificformathelper.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="selfmt.cpp">
<Filter>formatting</Filter>
</ClCompile>
@ -1071,6 +1074,9 @@
<CustomBuild Include="unicode\rbtz.h">
<Filter>formatting</Filter>
</CustomBuild>
<CustomBuild Include="unicode\scientificformathelper.h">
<Filter>formatting</Filter>
</CustomBuild>
<CustomBuild Include="unicode\selfmt.h">
<Filter>formatting</Filter>
</CustomBuild>
@ -1197,4 +1203,4 @@
<Filter>misc</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>

View file

@ -0,0 +1,158 @@
/*
**********************************************************************
* Copyright (c) 2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/scientificformathelper.h"
#include "unicode/dcfmtsym.h"
#include "unicode/fpositer.h"
#include "unicode/utf16.h"
#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
// TODO: Add U_DRAFT_API directives.
// TODO: Add U_FORMATTING directives
U_NAMESPACE_BEGIN
static UChar kExponentDigits[] = {0x2070, 0xB9, 0xB2, 0xB3, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079};
static UnicodeString getMultiplicationSymbol(const DecimalFormatSymbols &dfs) {
static UChar multSign = 0xD7;
return UnicodeString(FALSE, &multSign, 1);
}
ScientificFormatHelper::ScientificFormatHelper(
const DecimalFormatSymbols &dfs, UErrorCode &status) : fPreExponent() {
if (U_FAILURE(status)) {
return;
}
fPreExponent.append(getMultiplicationSymbol(dfs));
fPreExponent.append(dfs.getSymbol(DecimalFormatSymbols::kOneDigitSymbol));
fPreExponent.append(dfs.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol));
}
ScientificFormatHelper::ScientificFormatHelper(
const ScientificFormatHelper &other) : fPreExponent(other.fPreExponent) {
}
ScientificFormatHelper &ScientificFormatHelper::operator=(const ScientificFormatHelper &other) {
if (this == &other) {
return *this;
}
fPreExponent = other.fPreExponent;
return *this;
}
ScientificFormatHelper::~ScientificFormatHelper() {
}
UnicodeString &ScientificFormatHelper::insetMarkup(
const UnicodeString &s,
FieldPositionIterator &fpi,
const UnicodeString &beginMarkup,
const UnicodeString &endMarkup,
UnicodeString &result,
UErrorCode & /* status */) const {
FieldPosition fp;
int32_t copyFromOffset = 0;
while (fpi.next(fp)) {
switch (fp.getField()) {
case UNUM_EXPONENT_SYMBOL_FIELD:
result.append(s, copyFromOffset, fp.getBeginIndex() - copyFromOffset);
copyFromOffset = fp.getEndIndex();
result.append(fPreExponent);
result.append(beginMarkup);
break;
case UNUM_EXPONENT_FIELD:
result.append(s, copyFromOffset, fp.getEndIndex() - copyFromOffset);
copyFromOffset = fp.getEndIndex();
result.append(endMarkup);
break;
default:
break;
}
}
result.append(s, copyFromOffset, s.length() - copyFromOffset);
return result;
}
static UBool copyAsSuperscript(
const UnicodeString &s,
int32_t beginIndex,
int32_t endIndex,
UnicodeString &result,
UErrorCode &status) {
if (U_FAILURE(status)) {
return FALSE;
}
for (int32_t i = beginIndex; i < endIndex;) {
UChar32 c = s.char32At(i);
int32_t digit = u_charDigitValue(c);
if (digit < 0) {
status = U_INVALID_CHAR_FOUND;
return FALSE;
}
result.append(kExponentDigits[digit]);
i += U16_LENGTH(c);
}
return TRUE;
}
static UBool isMinusSign(UChar ch) {
// TODO: revisit this.
return (ch == 0x2D);
}
UnicodeString &ScientificFormatHelper::toSuperscriptExponentDigits(
const UnicodeString &s,
FieldPositionIterator &fpi,
UnicodeString &result,
UErrorCode &status) const {
FieldPosition fp;
int32_t copyFromOffset = 0;
while (fpi.next(fp)) {
switch (fp.getField()) {
case UNUM_EXPONENT_SYMBOL_FIELD:
result.append(s, copyFromOffset, fp.getBeginIndex() - copyFromOffset);
copyFromOffset = fp.getEndIndex();
result.append(fPreExponent);
break;
case UNUM_EXPONENT_SIGN_FIELD:
{
int32_t beginIndex = fp.getBeginIndex();
int32_t endIndex = fp.getEndIndex();
if (endIndex - beginIndex == 1 && isMinusSign(s[beginIndex])) {
result.append(s, copyFromOffset, beginIndex - copyFromOffset);
result.append(0x207B);
} else {
status = U_INVALID_CHAR_FOUND;
return result;
}
copyFromOffset = endIndex;
}
break;
case UNUM_EXPONENT_FIELD:
result.append(s, copyFromOffset, fp.getBeginIndex() - copyFromOffset);
if (!copyAsSuperscript(
s, fp.getBeginIndex(), fp.getEndIndex(), result, status)) {
return result;
}
copyFromOffset = fp.getEndIndex();
break;
default:
break;
}
}
result.append(s, copyFromOffset, s.length() - copyFromOffset);
return result;
}
U_NAMESPACE_END
#endif /* !UCONFIG_NO_FORMATTING */

View file

@ -0,0 +1,131 @@
/*
**********************************************************************
* Copyright (c) 2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*/
#ifndef SCIFORMATHELPER_H
#define SCIFORMATHELPER_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#ifndef U_HIDE_DRAFT_API
#include "unicode/unistr.h"
/**
* \file
* \brief C++ API: Formatter for measure objects.
*/
U_NAMESPACE_BEGIN
class DecimalFormatSymbols;
class FieldPositionIterator;
/**
* A helper class for formatting in user-friendly scientific notation.
*
* Sample code:
* <pre>
* UErrorCode status = U_ZERO_ERROR;
* DecimalFormat *decfmt = (DecimalFormat *)
* NumberFormat::createScientificInstance("en", status);
* UnicodeString appendTo;
* FieldPositionIterator fpositer;
* decfmt->format(1.23456e-78, appendTo, &fpositer, status);
* ScientificFormatHelper helper(*decfmt->getDecimalFormatSymbols(), status);
* UnicodeString result;
*
* // result = "1.23456×10<sup>-78</sup>"
* helper.insetMarkup(appendTo, fpositer, "<sup>", "</sup>", result, status));
* </pre>
*
* @see NumberFormat
* @draft ICU 54
*/
class U_I18N_API ScientificFormatHelper : public UObject {
public:
/**
* Constructor.
* @param symbols comes from DecimalFormat instance used for default
* scientific notation.
* @param status any error reported here.
* @draft ICU 54
*/
ScientificFormatHelper(const DecimalFormatSymbols &symbols, UErrorCode& status);
/**
* Copy constructor.
* @draft ICU 54
*/
ScientificFormatHelper(const ScientificFormatHelper &other);
/**
* Assignment operator.
* @draft ICU 54
*/
ScientificFormatHelper &operator=(const ScientificFormatHelper &other);
/**
* Destructor.
* @draft ICU 54
*/
virtual ~ScientificFormatHelper();
/**
* Makes scientific notation user-friendly by surrounding exponent with
* html to make it superscript.
* @param s the original formatted scientific notation e.g "6.02e23"
* s is output from NumberFormat::createScientificInstance()->format().
* @param fpi the FieldPositionIterator from the format call.
* fpi is output from NumberFormat::createScientificInstance()->format().
* @param beginMarkup the start html for the exponent e.g "<sup>"
* @param endMarkup the end html for the exponent e.g "</sup>"
* @param result user-friendly scientific notation stored here.
* @param status any error returned here. When status is set to a non-zero
* error, the value of result is unspecified, and client should fallback
* to using s for scientific notation.
* @return the value stored in result.
* @draft ICU 54
*/
UnicodeString &insetMarkup(
const UnicodeString &s,
FieldPositionIterator &fpi,
const UnicodeString &beginMarkup,
const UnicodeString &endMarkup,
UnicodeString &result,
UErrorCode &status) const;
/**
* Makes scientific notation user-friendly by using specific code points
* for superscript 0..9 and - in the exponent rather than by using
* html.
* @param s the original formatted scientific notation e.g "6.02e23"
* s is output from NumberFormat::createScientificInstance()->format().
* @param fpi the corresponding FieldPositionIterator from the format call.
* fpi is output from NumberFormat::createScientificInstance()->format().
* @param result user-friendly scientific notation stored here.
* @param status any error returned here. When status is set to a non-zero
* error, the value of result is unspecified, and client should fallback
* to using s for scientific notation.
* @return the value stored in result.
* @draft ICU 54
*/
UnicodeString &toSuperscriptExponentDigits(
const UnicodeString &s,
FieldPositionIterator &fpi,
UnicodeString &result,
UErrorCode &status) const;
private:
UnicodeString fPreExponent;
};
U_NAMESPACE_END
#endif /* U_HIDE_DRAFT_API */
#endif /* !UCONFIG_NO_FORMATTING */
#endif

View file

@ -57,7 +57,7 @@ uobjtest.o idnaref.o idnaconf.o nptrans.o punyref.o testidn.o testidna.o uts46te
incaltst.o calcasts.o v32test.o uvectest.o textfile.o tokiter.o utxttest.o \
windttst.o winnmtst.o winutil.o csdetest.o tzrulets.o tzoffloc.o tzfmttst.o ssearch.o dtifmtts.o \
tufmtts.o itspoof.o simplethread.o bidiconf.o locnmtst.o dcfmtest.o alphaindextst.o listformattertest.o genderinfotest.o compactdecimalformattest.o regiontst.o \
reldatefmttest.o lrucachetest.o simplepatternformattertest.o measfmttest.o
reldatefmttest.o lrucachetest.o simplepatternformattertest.o measfmttest.o scientificformathelpertest.o
DEPS = $(OBJECTS:.o=.d)

View file

@ -324,6 +324,7 @@
<ClCompile Include="reldatefmttest.cpp">
<DisableLanguageExtensions>false</DisableLanguageExtensions>
</ClCompile>
<ClCompile Include="scientificformathelpertest.cpp" />
<ClCompile Include="sdtfmtts.cpp" />
<ClCompile Include="selfmts.cpp" />
<ClCompile Include="tchcfmt.cpp" />
@ -570,4 +571,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -268,6 +268,9 @@
<ClCompile Include="reldatefmttest.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="scientificformathelpertest.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="sdtfmtts.cpp">
<Filter>formatting</Filter>
</ClCompile>

View file

@ -63,6 +63,7 @@ extern IntlTest *createCompactDecimalFormatTest();
extern IntlTest *createGenderInfoTest();
extern IntlTest *createRelativeDateTimeFormatterTest();
extern IntlTest *createMeasureFormatTest();
extern IntlTest *createScientificFormatHelperTest();
#define TESTCLASS(id, TestClass) \
case id: \
@ -177,6 +178,15 @@ void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &nam
callTest(*test, par);
}
break;
case 48:
name = "ScientificFormatHelperTest";
if (exec) {
logln("ScientificFormatHelperTest test---");
logln((UnicodeString)"");
LocalPointer<IntlTest> test(createScientificFormatHelperTest());
callTest(*test, par);
}
break;
default: name = ""; break; //needed to end loop
}
if (exec) {

View file

@ -0,0 +1,77 @@
/*
*******************************************************************************
* Copyright (C) 2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
* File SCIFORMATHELPERTEST.CPP
*
*******************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include "intltest.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/scientificformathelper.h"
#include "unicode/numfmt.h"
#include "unicode/decimfmt.h"
#define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0]))
class ScientificFormatHelperTest : public IntlTest {
public:
ScientificFormatHelperTest() {
}
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
private:
void TestBasic();
};
void ScientificFormatHelperTest::runIndexedTest(
int32_t index, UBool exec, const char *&name, char *) {
if (exec) {
logln("TestSuite ScientificFormatHelperTest: ");
}
TESTCASE_AUTO_BEGIN;
TESTCASE_AUTO(TestBasic);
TESTCASE_AUTO_END;
}
void ScientificFormatHelperTest::TestBasic() {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<DecimalFormat> decfmt((DecimalFormat *) NumberFormat::createScientificInstance("en", status));
UnicodeString appendTo("String: ");
FieldPositionIterator fpositer;
decfmt->format(1.23456e-78, appendTo, &fpositer, status);
FieldPositionIterator fpositer2(fpositer);
FieldPositionIterator fpositer3(fpositer);
ScientificFormatHelper helper(*decfmt->getDecimalFormatSymbols(), status);
UnicodeString result;
assertEquals(
"insetMarkup",
"String: 1.23456×10<sup>-78</sup>",
helper.insetMarkup(appendTo, fpositer, "<sup>", "</sup>", result, status));
result.remove();
assertEquals(
"toSuperscriptExponentDigits",
"String: 1.23456×10⁻⁷⁸",
helper.toSuperscriptExponentDigits(appendTo, fpositer2, result, status));
assertSuccess("", status);
result.remove();
// The 'a' is an invalid exponent character.
helper.toSuperscriptExponentDigits("String: 1.23456e-7a", fpositer3, result, status);
if (status != U_INVALID_CHAR_FOUND) {
errln("Expected U_INVALID_CHAR_FOUND");
}
}
extern IntlTest *createScientificFormatHelperTest() {
return new ScientificFormatHelperTest();
}
#endif /* !UCONFIG_NO_FORMATTING */