LibreOffice Module i18npool (master) 1
nativenumbersupplier.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
22#include <rtl/ustrbuf.hxx>
23#include <sal/macros.h>
25#include <localedata.hxx>
26#include "data/numberchar.h"
29#include <o3tl/string_view.hxx>
30#include <cstddef>
31#include <map>
32#include <mutex>
33#include <memory>
34#include <string_view>
35#include <unordered_map>
36#include <com/sun/star/i18n/CharacterClassification.hpp>
37#include <com/sun/star/i18n/NativeNumberMode.hpp>
38#include <com/sun/star/linguistic2/NumberText.hpp>
39
40using namespace ::com::sun::star::uno;
41using namespace ::com::sun::star::i18n;
42using namespace ::com::sun::star::lang;
43
44namespace {
45
46struct Number {
47 sal_Int16 number;
48 const sal_Unicode *multiplierChar;
49 sal_Int16 numberFlag;
50 sal_Int16 exponentCount;
51 const sal_Int16 *multiplierExponent;
52};
53
54}
55
56#define NUMBER_OMIT_ZERO (1 << 0)
57#define NUMBER_OMIT_ONLY_ZERO (1 << 1)
58#define NUMBER_OMIT_ONE_1 (1 << 2)
59#define NUMBER_OMIT_ONE_2 (1 << 3)
60#define NUMBER_OMIT_ONE_3 (1 << 4)
61#define NUMBER_OMIT_ONE_4 (1 << 5)
62#define NUMBER_OMIT_ONE_5 (1 << 6)
63#define NUMBER_OMIT_ONE_6 (1 << 7)
64#define NUMBER_OMIT_ONE_7 (1 << 8)
65#define NUMBER_OMIT_ONE (NUMBER_OMIT_ONE_1|NUMBER_OMIT_ONE_2|NUMBER_OMIT_ONE_3|NUMBER_OMIT_ONE_4|NUMBER_OMIT_ONE_5|NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
66#define NUMBER_OMIT_ONE_CHECK(bit) (1 << (2 + bit))
67#define NUMBER_OMIT_ALL ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE|NUMBER_OMIT_ONLY_ZERO )
68#define NUMBER_OMIT_ZERO_ONE ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE )
69#define NUMBER_OMIT_ONE_67 (NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
70#define NUMBER_OMIT_ZERO_ONE_67 ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE_67 )
71
72namespace i18npool {
73
74namespace {
75
76std::mutex theNatNumMutex;
77
78}
79
80static OUString getHebrewNativeNumberString(const OUString& aNumberString, bool useGeresh);
81
82static OUString getCyrillicNativeNumberString(const OUString& aNumberString);
83
85static OUString AsciiToNativeChar( const OUString& inStr, sal_Int32 nCount,
86 Sequence< sal_Int32 >* pOffset, sal_Int16 number )
87{
88 const sal_Unicode *src = inStr.getStr();
89 rtl_uString *newStr = rtl_uString_alloc(nCount);
90 if (pOffset)
91 pOffset->realloc(nCount);
92 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
93
94 for (sal_Int32 i = 0; i < nCount; i++)
95 {
96 sal_Unicode ch = src[i];
97 if (isNumber(ch))
98 newStr->buffer[i] = NumberChar[number][ ch - NUMBER_ZERO ];
99 else if (i+1 < nCount && isNumber(src[i+1])) {
100 if (i > 0 && isNumber(src[i-1]) && isSeparator(ch))
101 newStr->buffer[i] = SeparatorChar[number] ? SeparatorChar[number] : ch;
102 else
103 newStr->buffer[i] = isDecimal(ch) ? (DecimalChar[number] ? DecimalChar[number] : ch) :
104 isMinus(ch) ? (MinusChar[number] ? MinusChar[number] : ch) : ch;
105 }
106 else
107 newStr->buffer[i] = ch;
108 if (ppOffset)
109 ppOffset[i] = i;
110 }
111 return OUString(newStr, SAL_NO_ACQUIRE); // take ownership
112}
113
114static bool AsciiToNative_numberMaker(const sal_Unicode *str, sal_Int32 begin, sal_Int32 len,
115 sal_Unicode *dst, sal_Int32& count, sal_Int16 multiChar_index, Sequence< sal_Int32 >* pOffset, sal_Int32 startPos,
116 const Number *number, const sal_Unicode* numberChar)
117{
118 sal_Unicode multiChar = (multiChar_index == -1 ? 0 : number->multiplierChar[multiChar_index]);
119 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
120 if ( len <= number->multiplierExponent[number->exponentCount-1] ) {
121 if (number->multiplierExponent[number->exponentCount-1] > 1) {
122 bool bNotZero = false;
123 for (const sal_Int32 end = begin+len; begin < end; begin++) {
124 if (bNotZero || str[begin] != NUMBER_ZERO) {
125 dst[count] = numberChar[str[begin] - NUMBER_ZERO];
126 if (ppOffset)
127 ppOffset[count] = begin + startPos;
128 count++;
129 bNotZero = true;
130 }
131 }
132 if (bNotZero && multiChar > 0) {
133 dst[count] = multiChar;
134 if (ppOffset)
135 ppOffset[count] = begin + startPos;
136 count++;
137 }
138 return bNotZero;
139 } else if (str[begin] != NUMBER_ZERO) {
140 if (!(number->numberFlag & (multiChar_index < 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index))) || str[begin] != NUMBER_ONE) {
141 dst[count] = numberChar[str[begin] - NUMBER_ZERO];
142 if (ppOffset)
143 ppOffset[count] = begin + startPos;
144 count++;
145 }
146 if (multiChar > 0) {
147 dst[count] = multiChar;
148 if (ppOffset)
149 ppOffset[count] = begin + startPos;
150 count++;
151 }
152 } else if (!(number->numberFlag & NUMBER_OMIT_ZERO) && count > 0 && dst[count-1] != numberChar[0]) {
153 dst[count] = numberChar[0];
154 if (ppOffset)
155 ppOffset[count] = begin + startPos;
156 count++;
157 }
158 return str[begin] != NUMBER_ZERO;
159 } else {
160 bool bPrintPower = false;
161 // sal_Int16 last = 0;
162 for (sal_Int16 i = 1; i <= number->exponentCount; i++) {
163 sal_Int32 tmp = len - (i == number->exponentCount ? 0 : number->multiplierExponent[i]);
164 if (tmp > 0) {
165 bPrintPower |= AsciiToNative_numberMaker(str, begin, tmp, dst, count,
166 (i == number->exponentCount ? -1 : i), pOffset, startPos, number, numberChar);
167 begin += tmp;
168 len -= tmp;
169 }
170 }
171 if (bPrintPower) {
172 if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
173 dst[count-1] == numberChar[0])
174 count--;
175 if (multiChar > 0) {
176 dst[count] = multiChar;
177 if (ppOffset)
178 ppOffset[count] = begin + startPos;
179 count++;
180 }
181 }
182 return bPrintPower;
183 }
184}
185
187static OUString AsciiToNative( const OUString& inStr, sal_Int32 nCount,
188 Sequence< sal_Int32 >* pOffset, const Number* number )
189{
190 OUString aRet;
191
192 sal_Int32 strLen = inStr.getLength();
193 const sal_Unicode *numberChar = NumberChar[number->number];
194
195 if (nCount > strLen)
196 nCount = strLen;
197
198 if (nCount > 0)
199 {
200 const sal_Unicode *str = inStr.getStr();
201 std::unique_ptr<sal_Unicode[]> newStr(new sal_Unicode[nCount * 2 + 1]);
202 std::unique_ptr<sal_Unicode[]> srcStr(new sal_Unicode[nCount + 1]); // for keeping number without comma
203 sal_Int32 i, len = 0, count = 0;
204
205 if (pOffset)
206 pOffset->realloc( nCount * 2 );
207 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
208 bool bDoDecimal = false;
209
210 for (i = 0; i <= nCount; i++)
211 {
212 if (i < nCount && isNumber(str[i])) {
213 if (bDoDecimal) {
214 newStr[count] = numberChar[str[i] - NUMBER_ZERO];
215 if (ppOffset)
216 ppOffset[count] = i;
217 count++;
218 }
219 else
220 srcStr[len++] = str[i];
221 } else {
222 if (len > 0) {
223 if (i < nCount-1 && isSeparator(str[i]) && isNumber(str[i+1]))
224 continue; // skip comma inside number string
225 bool bNotZero = false;
226 for (sal_Int32 begin = 0, end = len % number->multiplierExponent[0];
227 end <= len; begin = end, end += number->multiplierExponent[0]) {
228 if (end == 0) continue;
229 sal_Int32 _count = count;
230 bNotZero |= AsciiToNative_numberMaker(srcStr.get(), begin, end - begin, newStr.get(), count,
231 end == len ? -1 : 0, pOffset, i - len, number, numberChar);
232 if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
233 newStr[count-1] == numberChar[0])
234 count--;
235 if (bNotZero && _count == count && end != len) {
236 newStr[count] = number->multiplierChar[0];
237 if (ppOffset)
238 ppOffset[count] = i - len;
239 count++;
240 }
241 }
242 if (! bNotZero && ! (number->numberFlag & NUMBER_OMIT_ONLY_ZERO)) {
243 newStr[count] = numberChar[0];
244 if (ppOffset)
245 ppOffset[count] = i - len;
246 count++;
247 }
248 len = 0;
249 }
250 if (i < nCount) {
251 bDoDecimal = (!bDoDecimal && i < nCount-1 && isDecimal(str[i]) && isNumber(str[i+1]));
252 if (bDoDecimal)
253 newStr[count] = (DecimalChar[number->number] ? DecimalChar[number->number] : str[i]);
254 else if (i < nCount-1 && isMinus(str[i]) && isNumber(str[i+1]))
255 newStr[count] = (MinusChar[number->number] ? MinusChar[number->number] : str[i]);
256 else if (i < nCount-1 && isSeparator(str[i]) && isNumber(str[i+1]))
257 newStr[count] = (SeparatorChar[number->number] ? SeparatorChar[number->number] : str[i]);
258 else
259 newStr[count] = str[i];
260 if (ppOffset)
261 ppOffset[count] = i;
262 count++;
263 }
264 }
265 }
266
267 if (pOffset)
268 pOffset->realloc(count);
269 aRet = OUString(newStr.get(), count);
270 }
271 return aRet;
272}
273
274namespace
275{
276void NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str,
277 sal_Int32& i, sal_Int32 nCount, sal_Unicode *dst, sal_Int32& count, Sequence< sal_Int32 >* pOffset,
278 OUString& numberChar, OUString& multiplierChar)
279{
280 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
281 sal_Int16 curr = 0, num = 0, end = 0, shift = 0;
282 while (++i < nCount) {
283 if ((curr = sal::static_int_cast<sal_Int16>( numberChar.indexOf(str[i]) )) >= 0) {
284 if (num > 0)
285 break;
286 num = curr % 10;
287 } else if ((curr = sal::static_int_cast<sal_Int16>( multiplierChar.indexOf(str[i]) )) >= 0) {
289 if (prev > curr && num == 0) num = 1; // One may be omitted in informal format
290 shift = end = 0;
291 if (curr >= max)
292 max = curr;
293 else if (curr > prev)
294 shift = max - curr;
295 else
296 end = curr;
297 while (end++ < prev) {
298 dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
299 if (ppOffset)
300 ppOffset[count] = i;
301 count++;
302 }
303 if (shift) {
304 count -= max;
305 for (const sal_Int32 countEnd = count+shift; count < countEnd; count++) {
306 dst[count] = dst[count + curr];
307 if (ppOffset)
308 ppOffset[count] = ppOffset[count + curr];
309 }
310 max = curr;
311 }
312 NativeToAscii_numberMaker(max, curr, str, i, nCount, dst,
313 count, pOffset, numberChar, multiplierChar);
314 return;
315 } else
316 break;
317 }
318 while (end++ < prev) {
319 dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
320 if (ppOffset)
321 ppOffset[count] = i - 1;
322 count++;
323 }
324}
325
327OUString NativeToAscii(const OUString& inStr,
328 sal_Int32 nCount, Sequence< sal_Int32 >* pOffset )
329{
330 OUString aRet;
331
332 sal_Int32 strLen = inStr.getLength();
333
334 if (nCount > strLen)
335 nCount = strLen;
336
337 if (nCount > 0) {
338 const sal_Unicode *str = inStr.getStr();
339 std::unique_ptr<sal_Unicode[]> newStr(new sal_Unicode[nCount * MultiplierExponent_7_CJK[0] + 2]);
340 if (pOffset)
341 pOffset->realloc( nCount * MultiplierExponent_7_CJK[0] + 1 );
342 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
343 sal_Int32 count = 0, index;
344 sal_Int32 i;
345
346 OUString numberChar, multiplierChar, decimalChar, separatorChar;
347 numberChar = OUString(NumberChar[0], 10*NumberChar_Count);
348 multiplierChar = OUString(MultiplierChar_7_CJK[0], ExponentCount_7_CJK*Multiplier_Count);
349 decimalChar = OUString(DecimalChar, NumberChar_Count);
350 std::u16string_view const minusChar(MinusChar, NumberChar_Count);
351 separatorChar = OUString(
352 reinterpret_cast<sal_Unicode *>(SeparatorChar), NumberChar_Count);
353
354 for ( i = 0; i < nCount; i++) {
355 if ((index = multiplierChar.indexOf(str[i])) >= 0) {
356 if (count == 0 || !isNumber(newStr[count-1])) { // add 1 in front of multiplier
357 newStr[count] = NUMBER_ONE;
358 if (ppOffset)
359 ppOffset[count] = i;
360 count++;
361 }
363 NativeToAscii_numberMaker(
364 sal::static_int_cast<sal_Int16>( index ), sal::static_int_cast<sal_Int16>( index ),
365 str, i, nCount, newStr.get(), count, pOffset,
366 numberChar, multiplierChar);
367 } else {
368 if ((index = numberChar.indexOf(str[i])) >= 0)
369 newStr[count] = sal::static_int_cast<sal_Unicode>( (index % 10) + NUMBER_ZERO );
370 else if (separatorChar.indexOf(str[i]) >= 0 &&
371 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 ||
372 multiplierChar.indexOf(str[i+1]) >= 0)))
374 else if (decimalChar.indexOf(str[i]) >= 0 &&
375 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 ||
376 multiplierChar.indexOf(str[i+1]) >= 0)))
377 // Only when decimal point is followed by numbers,
378 // it will be convert to ASCII decimal point
380 else if (minusChar.find(str[i]) != std::u16string_view::npos &&
381 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 ||
382 multiplierChar.indexOf(str[i+1]) >= 0)))
383 // Only when minus is followed by numbers,
384 // it will be convert to ASCII minus sign
386 else
387 newStr[count] = str[i];
388 if (ppOffset)
389 ppOffset[count] = i;
390 count++;
391 }
392 }
393
394 if (pOffset) {
395 pOffset->realloc(count);
396 }
397 aRet = OUString(newStr.get(), count);
398 }
399 return aRet;
400}
401
402const Number natnum4[4] = {
411};
412
413const Number natnum5[4] = {
422};
423
424const Number natnum6[4] = {
433};
434
435const Number natnum7[4] = {
444};
445
446const Number natnum8[4] = {
455};
456
461
464const char *natnum1Locales[] = {
465 "zh_CN",
466 "zh_TW",
467 "ja",
468 "ko",
469 "he",
470 "ar",
471 "th",
472 "hi",
473 "or",
474 "mr",
475 "bn",
476 "pa",
477 "gu",
478 "ta",
479 "te",
480 "kn",
481 "ml",
482 "lo",
483 "bo",
484 "my",
485 "km",
486 "mn",
487 "ne",
488 "dz",
489 "fa",
490 "cu"
491};
492const sal_Int16 nbOfLocale = SAL_N_ELEMENTS(natnum1Locales);
493
496const sal_Int16 natnum1[] = {
523};
524const sal_Int16 sizeof_natnum1 = SAL_N_ELEMENTS(natnum1);
525
528const sal_Int16 natnum2[] = {
534};
535const sal_Int16 sizeof_natnum2 = SAL_N_ELEMENTS(natnum2);
536
537sal_Int16 getLanguageNumber( const Locale& rLocale)
538{
539 // return zh_TW for TW, HK and MO, return zh_CN for other zh locales.
540 if (rLocale.Language == "zh") return MsLangId::isTraditionalChinese(rLocale) ? 1 : 0;
541
542 for (sal_Int16 i = 2; i < nbOfLocale; i++)
543 if (rLocale.Language.equalsAsciiL(natnum1Locales[i], 2))
544 return i;
545
546 return -1;
547}
548
549struct Separators
550{
553 Separators(const Locale& rLocale)
554 {
555 LocaleDataItem aLocaleItem = LocaleDataImpl::get()->getLocaleItem(rLocale);
556 DecimalSeparator = aLocaleItem.decimalSeparator.toChar();
557 ThousandSeparator = aLocaleItem.thousandSeparator.toChar();
558 }
559};
560
561Separators getLocaleSeparators(const Locale& rLocale, const OUString& rLocStr)
562{
563 // Guard the static variable below.
564 std::scoped_lock aGuard(theNatNumMutex);
565 // Maximum a couple hundred of pairs with 4-byte structs - so no need for smart managing
566 static std::unordered_map<OUString, Separators> aLocaleSeparatorsBuf;
567 auto it = aLocaleSeparatorsBuf.find(rLocStr);
568 if (it == aLocaleSeparatorsBuf.end())
569 {
570 it = aLocaleSeparatorsBuf.emplace(rLocStr, Separators(rLocale)).first;
571 }
572 return it->second;
573}
574
575OUString getNumberText(const Locale& rLocale, const OUString& rNumberString,
576 std::u16string_view sNumberTextParams)
577{
578 sal_Int32 i, count = 0;
579 const sal_Int32 len = rNumberString.getLength();
580 const sal_Unicode* src = rNumberString.getStr();
581
582 OUString aLoc = LanguageTag::convertToBcp47(rLocale);
583 Separators aSeparators = getLocaleSeparators(rLocale, aLoc);
584
585 OUStringBuffer sBuf(len);
586 for (i = 0; i < len; i++)
587 {
588 sal_Unicode ch = src[i];
589 if (isNumber(ch))
590 {
591 ++count;
592 sBuf.append(ch);
593 }
594 else if (ch == aSeparators.DecimalSeparator)
595 // Convert any decimal separator to point - in case libnumbertext has a different one
596 // for this locale (it seems that point is supported for all locales in libnumbertext)
597 sBuf.append('.');
598 else if (ch == aSeparators.ThousandSeparator && count > 0)
599 continue;
600 else if (isMinus(ch) && count == 0)
601 sBuf.append(ch);
602 else
603 break;
604 }
605
606 // Handle also month and day names for NatNum12 date formatting
607 const OUString& rNumberStr = (count == 0) ? rNumberString : sBuf.makeStringAndClear();
608
609 static auto xNumberText
610 = css::linguistic2::NumberText::create(comphelper::getProcessComponentContext());
611
612 // Guard the static variables below.
613 std::scoped_lock aGuard( theNatNumMutex );
614
615 OUString numbertext_prefix;
616 // default "cardinal" gets empty prefix
617 if (!sNumberTextParams.empty() && sNumberTextParams != u"cardinal")
618 numbertext_prefix = OUString::Concat(sNumberTextParams) + " ";
619 // Several hundreds of headings could result typing lags because
620 // of the continuous update of the multiple number names during typing.
621 // We fix this by buffering the result of the conversion.
622 static std::unordered_map<OUString, std::map<OUString, OUString>> aBuff;
623 auto& rItems = aBuff[rNumberStr];
624 auto& rItem = rItems[numbertext_prefix + aLoc];
625 if (rItem.isEmpty())
626 {
627 rItem = xNumberText->getNumberText(numbertext_prefix + rNumberStr, rLocale);
628 // use number at missing number to text conversion
629 if (rItem.isEmpty())
630 rItem = rNumberStr;
631 }
632 OUString sResult = rItem;
633 if (i != 0 && i < len)
634 sResult += rNumberString.subView(i);
635 return sResult;
636}
637}
638
639OUString NativeNumberSupplierService::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
640 sal_Int16 nNativeNumberMode,
641 Sequence<sal_Int32>* pOffset,
642 std::u16string_view rNativeNumberParams)
643{
644 if (!isValidNatNumImpl(rLocale, nNativeNumberMode))
645 return aNumberString;
646
647 if (nNativeNumberMode == NativeNumberMode::NATNUM12)
648 {
649 // handle capitalization prefixes "capitalize", "upper", "lower" and "title"
650
651 enum WhichCasing
652 {
654 UPPER,
655 LOWER,
656 TITLE
657 };
658
659 struct CasingEntry
660 {
661 std::u16string_view aLiteral;
662 WhichCasing eCasing;
663 };
664
665 static const CasingEntry Casings[] =
666 {
667 { std::u16string_view(u"capitalize"), CAPITALIZE },
668 { std::u16string_view(u"upper"), UPPER },
669 { std::u16string_view(u"lower"), LOWER },
670 { std::u16string_view(u"title"), TITLE }
671 };
672
673 std::size_t nStripCase = 0;
674 size_t nCasing;
675 for (nCasing = 0; nCasing < SAL_N_ELEMENTS(Casings); ++nCasing)
676 {
677 if (o3tl::starts_with(rNativeNumberParams, Casings[nCasing].aLiteral))
678 {
679 nStripCase = Casings[nCasing].aLiteral.size();
680 break;
681 }
682 }
683
684 if (nStripCase > 0 && (rNativeNumberParams.size() == nStripCase ||
685 rNativeNumberParams[nStripCase++] == ' '))
686 {
687 OUString aStr = getNumberText(rLocale, aNumberString, rNativeNumberParams.substr(nStripCase));
688
689 if (!xCharClass.is())
690 xCharClass = CharacterClassification::create(comphelper::getProcessComponentContext());
691
692 switch (Casings[nCasing].eCasing)
693 {
694 case CAPITALIZE:
695 return xCharClass->toTitle(aStr, 0, 1, aLocale) +
696 (aStr.getLength() > 1 ? aStr.subView(1) : u"");
697 case UPPER:
698 return xCharClass->toUpper(aStr, 0, aStr.getLength(), aLocale);
699 case LOWER:
700 return xCharClass->toLower(aStr, 0, aStr.getLength(), aLocale);
701 case TITLE:
702 {
703 if ( rLocale.Language == "en" )
704 {
705 // title case is common in English, so fix bugs of toTitle():
706 // not "One Dollar *And* *Twenty-two* Cents", but
707 // "One Dollar *and* *Twenty-Two* Cents".
708
709 // Add spaces after hyphens to separate the elements of the
710 // hyphenated compound words temporarily, allowing their
711 // capitalization by toTitle()
712 aStr = aStr.replaceAll("-", "- ");
713 aStr = xCharClass->toTitle(aStr, 0, aStr.getLength(), aLocale);
714 return aStr.replaceAll("- ", "-").replaceAll(" And ", " and ");
715 }
716 else
717 return xCharClass->toTitle(aStr, 0, aStr.getLength(), aLocale);
718 }
719 }
720 }
721 else
722 {
723 return getNumberText(rLocale, aNumberString, rNativeNumberParams);
724 }
725 }
726
727 sal_Int16 langnum = getLanguageNumber(rLocale);
728 if (langnum == -1)
729 return aNumberString;
730
731 const Number *number = nullptr;
732 sal_Int16 num = -1;
733
734 switch (nNativeNumberMode)
735 {
736 case NativeNumberMode::NATNUM0: // Ascii
737 return NativeToAscii(aNumberString, aNumberString.getLength(), pOffset);
738 case NativeNumberMode::NATNUM1: // Char, Lower
739 num = natnum1[langnum];
740 break;
741 case NativeNumberMode::NATNUM2: // Char, Upper
742 num = natnum2[langnum];
743 break;
744 case NativeNumberMode::NATNUM3: // Char, FullWidth
746 break;
747 case NativeNumberMode::NATNUM4: // Text, Lower, Long
748 number = &natnum4[langnum];
749 break;
750 case NativeNumberMode::NATNUM5: // Text, Upper, Long
751 number = &natnum5[langnum];
752 break;
753 case NativeNumberMode::NATNUM6: // Text, FullWidth
754 number = &natnum6[langnum];
755 break;
756 case NativeNumberMode::NATNUM7: // Text. Lower, Short
757 number = &natnum7[langnum];
758 break;
759 case NativeNumberMode::NATNUM8: // Text, Upper, Short
760 number = &natnum8[langnum];
761 break;
762 case NativeNumberMode::NATNUM9: // Char, Hangul
764 break;
765 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
766 number = &natnum10;
767 break;
768 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
769 number = &natnum11;
770 break;
771 default:
772 break;
773 }
774
775 if (number || num >= 0) {
776 if (aLocale.Language != rLocale.Language ||
777 aLocale.Country != rLocale.Country ||
778 aLocale.Variant != rLocale.Variant) {
779 LocaleDataItem item = LocaleDataImpl::get()->getLocaleItem( rLocale );
780 aLocale = rLocale;
781 DecimalChar[NumberChar_HalfWidth]=item.decimalSeparator.toChar();
784 else
786 SeparatorChar[NumberChar_HalfWidth]=item.thousandSeparator.toChar();
789 else
791 }
792 if (number)
793 return AsciiToNative( aNumberString, aNumberString.getLength(), pOffset, number );
794 else if (num == NumberChar_he)
795 return getHebrewNativeNumberString(aNumberString,
796 nNativeNumberMode == NativeNumberMode::NATNUM2);
797 else if (num == NumberChar_cu)
798 return getCyrillicNativeNumberString(aNumberString);
799 else
800 return AsciiToNativeChar(aNumberString, aNumberString.getLength(), pOffset, num);
801 }
802 else
803 return aNumberString;
804}
805
806OUString SAL_CALL NativeNumberSupplierService::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
807 sal_Int16 nNativeNumberMode)
808{
809 return getNativeNumberString(aNumberString, rLocale, nNativeNumberMode, nullptr);
810}
811
813 const OUString& rNumberString, const css::lang::Locale& rLocale, sal_Int16 nNativeNumberMode,
814 const OUString& rNativeNumberParams)
815{
816 return getNativeNumberString(rNumberString, rLocale, nNativeNumberMode, nullptr, rNativeNumberParams);
817}
818
819sal_Unicode NativeNumberSupplierService::getNativeNumberChar( const sal_Unicode inChar, const Locale& rLocale, sal_Int16 nNativeNumberMode )
820{
821 if (nNativeNumberMode == NativeNumberMode::NATNUM0) { // Ascii
822 for (const auto & i : NumberChar)
823 for (sal_Int16 j = 0; j < 10; j++)
824 if (inChar == i[j])
825 return j;
826 return inChar;
827 }
828
829 if (!isNumber(inChar))
830 return inChar;
831
832 if (!isValidNatNumImpl(rLocale, nNativeNumberMode))
833 return inChar;
834
835 sal_Int16 langnum = getLanguageNumber(rLocale);
836 if (langnum == -1)
837 return inChar;
838
839 switch (nNativeNumberMode)
840 {
841 case NativeNumberMode::NATNUM1: // Char, Lower
842 case NativeNumberMode::NATNUM4: // Text, Lower, Long
843 case NativeNumberMode::NATNUM7: // Text. Lower, Short
844 return NumberChar[natnum1[langnum]][inChar - NUMBER_ZERO];
845 case NativeNumberMode::NATNUM2: // Char, Upper
846 case NativeNumberMode::NATNUM5: // Text, Upper, Long
847 case NativeNumberMode::NATNUM8: // Text, Upper, Short
848 return NumberChar[natnum2[langnum]][inChar - NUMBER_ZERO];
849 case NativeNumberMode::NATNUM3: // Char, FullWidth
850 case NativeNumberMode::NATNUM6: // Text, FullWidth
852 case NativeNumberMode::NATNUM9: // Char, Hangul
853 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
854 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
856 default:
857 break;
858 }
859
860 return inChar;
861}
862
863bool NativeNumberSupplierService::isValidNatNumImpl( const Locale& rLocale, sal_Int16 nNativeNumberMode )
864{
865 sal_Int16 langnum = getLanguageNumber(rLocale);
866
867 switch (nNativeNumberMode) {
868 case NativeNumberMode::NATNUM0: // Ascii
869 case NativeNumberMode::NATNUM3: // Char, FullWidth
870 case NativeNumberMode::NATNUM12: // spell out numbers, dates and money amounts
871 return true;
872 case NativeNumberMode::NATNUM1: // Char, Lower
873 return (langnum >= 0);
874 case NativeNumberMode::NATNUM2: // Char, Upper
875 if (langnum == 4) // Hebrew numbering
876 return true;
877 [[fallthrough]];
878 case NativeNumberMode::NATNUM4: // Text, Lower, Long
879 case NativeNumberMode::NATNUM5: // Text, Upper, Long
880 case NativeNumberMode::NATNUM6: // Text, FullWidth
881 case NativeNumberMode::NATNUM7: // Text. Lower, Short
882 case NativeNumberMode::NATNUM8: // Text, Upper, Short
883 return (langnum >= 0 && langnum < 4); // CJK numbering
884 case NativeNumberMode::NATNUM9: // Char, Hangul
885 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
886 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
887 return (langnum == 3); // Korean numbering
888 }
889 return false;
890}
891
892NativeNumberXmlAttributes SAL_CALL NativeNumberSupplierService::convertToXmlAttributes( const Locale& rLocale, sal_Int16 nNativeNumberMode )
893{
894 static const sal_Int16 attShort = 0;
895 static const sal_Int16 attMedium = 1;
896 static const sal_Int16 attLong = 2;
897 static const char *attType[] = { "short", "medium", "long" };
898
899 sal_Int16 number = NumberChar_HalfWidth, type = attShort;
900
901 sal_Int16 langnum = -1;
902 if (isValidNatNum(rLocale, nNativeNumberMode)) {
903 langnum = getLanguageNumber(rLocale);
904 }
905 if (langnum != -1) {
906 switch (nNativeNumberMode) {
907 case NativeNumberMode::NATNUM0: // Ascii
908 number = NumberChar_HalfWidth;
909 type = attShort;
910 break;
911 case NativeNumberMode::NATNUM1: // Char, Lower
912 number = natnum1[langnum];
913 type = attShort;
914 break;
915 case NativeNumberMode::NATNUM2: // Char, Upper
916 number = natnum2[langnum];
917 type = number == NumberChar_he ? attMedium : attShort;
918 break;
919 case NativeNumberMode::NATNUM3: // Char, FullWidth
920 number = NumberChar_FullWidth;
921 type = attShort;
922 break;
923 case NativeNumberMode::NATNUM4: // Text, Lower, Long
924 number = natnum1[langnum];
925 type = attLong;
926 break;
927 case NativeNumberMode::NATNUM5: // Text, Upper, Long
928 number = natnum2[langnum];
929 type = attLong;
930 break;
931 case NativeNumberMode::NATNUM6: // Text, FullWidth
932 number = NumberChar_FullWidth;
933 type = attLong;
934 break;
935 case NativeNumberMode::NATNUM7: // Text. Lower, Short
936 number = natnum1[langnum];
937 type = attMedium;
938 break;
939 case NativeNumberMode::NATNUM8: // Text, Upper, Short
940 number = natnum2[langnum];
941 type = attMedium;
942 break;
943 case NativeNumberMode::NATNUM9: // Char, Hangul
944 number = NumberChar_Hangul_ko;
945 type = attShort;
946 break;
947 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
948 number = NumberChar_Hangul_ko;
949 type = attLong;
950 break;
951 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
952 number = NumberChar_Hangul_ko;
953 type = attMedium;
954 break;
955 default:
956 break;
957 }
958 }
959 return NativeNumberXmlAttributes(rLocale, OUString(&NumberChar[number][1], 1),
960 OUString::createFromAscii(attType[type]));
961}
962
963static bool natNumIn(sal_Int16 num, const sal_Int16 natnum[], sal_Int16 len)
964{
965 for (sal_Int16 i = 0; i < len; i++)
966 if (natnum[i] == num)
967 return true;
968 return false;
969}
970
971sal_Int16 SAL_CALL NativeNumberSupplierService::convertFromXmlAttributes( const NativeNumberXmlAttributes& aAttr )
972{
973 sal_Unicode numberChar[NumberChar_Count];
974 for (sal_Int16 i = 0; i < NumberChar_Count; i++)
975 numberChar[i] = NumberChar[i][1];
976 OUString number(numberChar, NumberChar_Count);
977
978 sal_Int16 num = sal::static_int_cast<sal_Int16>( number.indexOf(aAttr.Format) );
979
980 if ( aAttr.Style == "short" ) {
981 if (num == NumberChar_FullWidth)
982 return NativeNumberMode::NATNUM3;
983 else if (num == NumberChar_Hangul_ko)
984 return NativeNumberMode::NATNUM9;
985 else if (natNumIn(num, natnum1, sizeof_natnum1))
986 return NativeNumberMode::NATNUM1;
987 else if (natNumIn(num, natnum2, sizeof_natnum2))
988 return NativeNumberMode::NATNUM2;
989 } else if ( aAttr.Style == "medium" ) {
990 if (num == NumberChar_Hangul_ko)
991 return NativeNumberMode::NATNUM11;
992 else if (num == NumberChar_he)
993 return NativeNumberMode::NATNUM2;
994 else if (natNumIn(num, natnum1, sizeof_natnum1))
995 return NativeNumberMode::NATNUM7;
996 else if (natNumIn(num, natnum2, sizeof_natnum2))
997 return NativeNumberMode::NATNUM8;
998 } else if ( aAttr.Style == "long" ) {
999 if (num == NumberChar_FullWidth)
1000 return NativeNumberMode::NATNUM6;
1001 else if (num == NumberChar_Hangul_ko)
1002 return NativeNumberMode::NATNUM10;
1003 else if (natNumIn(num, natnum1, sizeof_natnum1))
1004 return NativeNumberMode::NATNUM4;
1005 else if (natNumIn(num, natnum2, sizeof_natnum2))
1006 return NativeNumberMode::NATNUM5;
1007 } else {
1008 throw RuntimeException();
1009 }
1010 return NativeNumberMode::NATNUM0;
1011}
1012
1013
1014// Following code generates Hebrew Number,
1015// see numerical system in the Hebrew Numbering System in following link for details,
1016// http://smontagu.org/writings/HebrewNumbers.html
1017
1018namespace {
1019
1020struct HebrewNumberChar {
1022 sal_Int16 value;
1023};
1024
1025}
1026
1027HebrewNumberChar const HebrewNumberCharArray[] = {
1028 { 0x05ea, 400 },
1029 { 0x05ea, 400 },
1030 { 0x05e9, 300 },
1031 { 0x05e8, 200 },
1032 { 0x05e7, 100 },
1033 { 0x05e6, 90 },
1034 { 0x05e4, 80 },
1035 { 0x05e2, 70 },
1036 { 0x05e1, 60 },
1037 { 0x05e0, 50 },
1038 { 0x05de, 40 },
1039 { 0x05dc, 30 },
1040 { 0x05db, 20 },
1041 { 0x05d9, 10 },
1042 { 0x05d8, 9 },
1043 { 0x05d7, 8 },
1044 { 0x05d6, 7 },
1045 { 0x05d5, 6 },
1046 { 0x05d4, 5 },
1047 { 0x05d3, 4 },
1048 { 0x05d2, 3 },
1049 { 0x05d1, 2 },
1050 { 0x05d0, 1 }
1051};
1052
1053const sal_Unicode thousand[] = {0x05d0, 0x05dc, 0x05e3, 0x0};
1054const sal_Unicode thousands[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0};
1055const sal_Unicode thousands_last[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0};
1056const sal_Unicode geresh = 0x05f3;
1057const sal_Unicode gershayim = 0x05f4;
1058
1059static void makeHebrewNumber(sal_Int64 value, OUStringBuffer& output, bool isLast, bool useGeresh)
1060{
1061 sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000);
1062
1063 if (value > 1000) {
1064 makeHebrewNumber(value / 1000, output, num != 0, useGeresh);
1065 output.append(" ");
1066 }
1067 if (num == 0) {
1068 output.append(value == 1000 ? thousand : isLast ? thousands_last : thousands);
1069 } else {
1070 sal_Int16 nbOfChar = 0;
1071 for (sal_Int32 j = 0; num > 0 && j < sal_Int32(SAL_N_ELEMENTS(HebrewNumberCharArray)); j++) {
1072 if (num - HebrewNumberCharArray[j].value >= 0) {
1073 nbOfChar++;
1074 // https://en.wikipedia.org/wiki/Hebrew_numerals#Key_exceptions
1075 // By convention, the numbers 15 and 16 are represented as 9 + 6 and 9 + 7
1076 if (num == 15 || num == 16) // substitution for 15 and 16
1077 j++;
1078 assert(j < sal_Int32(SAL_N_ELEMENTS(HebrewNumberCharArray)));
1079 num = sal::static_int_cast<sal_Int16>( num - HebrewNumberCharArray[j].value );
1080 output.append(HebrewNumberCharArray[j].code);
1081 }
1082 }
1083 if (useGeresh) {
1084 if (nbOfChar > 1) // a number is written as more than one character
1085 output.insert(output.getLength() - 1, gershayim);
1086 else if (nbOfChar == 1) // a number is written as a single character
1087 output.append(geresh);
1088 }
1089 }
1090}
1091
1092OUString getHebrewNativeNumberString(const OUString& aNumberString, bool useGeresh)
1093{
1094 sal_Int64 value = 0;
1095 sal_Int32 i, count = 0, len = aNumberString.getLength();
1096 const sal_Unicode *src = aNumberString.getStr();
1097
1098 for (i = 0; i < len; i++) {
1099 sal_Unicode ch = src[i];
1100 if (isNumber(ch)) {
1101 if (++count >= 20) // Number is too long, could not be handled.
1102 return aNumberString;
1103 value = value * 10 + (ch - NUMBER_ZERO);
1104 }
1105 else if (isSeparator(ch) && count > 0) continue;
1106 else if (isMinus(ch) && count == 0) continue;
1107 else break;
1108 }
1109
1110 if (value > 0) {
1111 OUStringBuffer output(count*2 + 2 + len - i);
1112
1113 makeHebrewNumber(value, output, true, useGeresh);
1114
1115 if (i < len)
1116 output.append(aNumberString.subView(i));
1117
1118 return output.makeStringAndClear();
1119 }
1120 else
1121 return aNumberString;
1122}
1123
1124// Support for Cyrillic Numerals
1125// See UTN 41 for implementation information
1126// http://www.unicode.org/notes/tn41/
1127
1131
1132namespace {
1133
1134struct CyrillicNumberChar {
1136 sal_Int16 value;
1137};
1138
1139}
1140
1141CyrillicNumberChar const CyrillicNumberCharArray[] = {
1142 { 0x0446, 900 },
1143 { 0x047f, 800 },
1144 { 0x0471, 700 },
1145 { 0x0445, 600 },
1146 { 0x0444, 500 },
1147 { 0x0443, 400 },
1148 { 0x0442, 300 },
1149 { 0x0441, 200 },
1150 { 0x0440, 100 },
1151 { 0x0447, 90 },
1152 { 0x043f, 80 },
1153 { 0x047b, 70 },
1154 { 0x046f, 60 },
1155 { 0x043d, 50 },
1156 { 0x043c, 40 },
1157 { 0x043b, 30 },
1158 { 0x043a, 20 },
1159 { 0x0456, 10 },
1160 { 0x0473, 9 },
1161 { 0x0438, 8 },
1162 { 0x0437, 7 },
1163 { 0x0455, 6 },
1164 { 0x0454, 5 },
1165 { 0x0434, 4 },
1166 { 0x0433, 3 },
1167 { 0x0432, 2 },
1168 { 0x0430, 1 }
1169};
1170
1171static void makeCyrillicNumber(sal_Int64 value, OUStringBuffer& output, bool addTitlo)
1172{
1173 sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000);
1174 if (value >= 1000) {
1175 output.append(cyrillicThousandsMark);
1176 makeCyrillicNumber(value / 1000, output, false);
1177 if (value >= 10000 && (value - 10000) % 1000 != 0) {
1178 output.append(" ");
1179 }
1180 if (value % 1000 == 0)
1181 addTitlo = false;
1182 }
1183
1184 for (sal_Int32 j = 0; num > 0 && j < sal_Int32(SAL_N_ELEMENTS(CyrillicNumberCharArray)); j++) {
1185 if (num < 20 && num > 10) {
1186 num -= 10;
1187 makeCyrillicNumber(num, output, false);
1188 output.append(cyrillicTen);
1189 break;
1190 }
1191
1192 if (CyrillicNumberCharArray[j].value <= num) {
1193 output.append(CyrillicNumberCharArray[j].code);
1194 num = sal::static_int_cast<sal_Int16>( num - CyrillicNumberCharArray[j].value );
1195 }
1196 }
1197
1198 if (!addTitlo)
1199 return;
1200
1201 if (output.getLength() == 1) {
1202 output.append(cyrillicTitlo);
1203 } else if (output.getLength() == 2) {
1204 if (value > 800 && value < 900) {
1205 output.append(cyrillicTitlo);
1206 } else {
1207 output.insert(1, cyrillicTitlo);
1208 }
1209 } else if (output.getLength() > 2) {
1210 if (output.indexOf(" ") == output.getLength() - 2) {
1211 output.append(cyrillicTitlo);
1212 } else {
1213 output.insert(output.getLength() - 1, cyrillicTitlo);
1214 }
1215 }
1216}
1217
1218OUString getCyrillicNativeNumberString(const OUString& aNumberString)
1219{
1220 sal_Int64 value = 0;
1221 sal_Int32 i, count = 0, len = aNumberString.getLength();
1222 const sal_Unicode *src = aNumberString.getStr();
1223
1224 for (i = 0; i < len; i++) {
1225 sal_Unicode ch = src[i];
1226 if (isNumber(ch)) {
1227 if (++count >= 8) // Number is too long, could not be handled.
1228 return aNumberString;
1229 value = value * 10 + (ch - NUMBER_ZERO);
1230 }
1231 else if (isSeparator(ch) && count > 0) continue;
1232 else if (isMinus(ch) && count == 0) continue;
1233 else break;
1234 }
1235
1236 if (value > 0) {
1237 OUStringBuffer output(count*2 + 2 + len - i);
1238
1239 makeCyrillicNumber(value, output, true);
1240
1241 if (i < len)
1242 output.append(aNumberString.subView(i));
1243
1244 return output.makeStringAndClear();
1245 }
1246 else
1247 return aNumberString;
1248}
1249
1250constexpr OUStringLiteral implementationName = u"com.sun.star.i18n.NativeNumberSupplier";
1251
1253{
1254 return implementationName;
1255}
1256
1257sal_Bool SAL_CALL
1259{
1260 return cppu::supportsService(this, rServiceName);
1261}
1262
1263Sequence< OUString > SAL_CALL
1265{
1266 return {implementationName, "com.sun.star.i18n.NativeNumberSupplier2"};
1267}
1268
1269}
1270
1271extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1273 css::uno::XComponentContext *,
1274 css::uno::Sequence<css::uno::Any> const &)
1275{
1276 return cppu::acquire(new i18npool::NativeNumberSupplierService());
1277}
1278
1279/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static OUString convertToBcp47(LanguageType nLangID)
static bool isTraditionalChinese(LanguageType nLang)
static rtl::Reference< LocaleDataImpl > get()
Definition: localedata.hxx:77
css::uno::Reference< css::i18n::XCharacterClassification > xCharClass
virtual OUString SAL_CALL getNativeNumberStringParams(const OUString &rNumberString, const css::lang::Locale &rLocale, sal_Int16 nNativeNumberMode, const OUString &rNativeNumberParams) override
static bool isValidNatNumImpl(const css::lang::Locale &aLocale, sal_Int16 nNativeNumberMode)
virtual sal_Bool SAL_CALL isValidNatNum(const css::lang::Locale &rLocale, sal_Int16 nNativeNumberMode) override
virtual sal_Int16 SAL_CALL convertFromXmlAttributes(const css::i18n::NativeNumberXmlAttributes &aAttr) override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
virtual OUString SAL_CALL getNativeNumberString(const OUString &aNumberString, const css::lang::Locale &aLocale, sal_Int16 nNativeNumberMode) override
virtual OUString SAL_CALL getImplementationName() override
static sal_Unicode getNativeNumberChar(const sal_Unicode inChar, const css::lang::Locale &aLocale, sal_Int16 nNativeNumberMode)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual css::i18n::NativeNumberXmlAttributes SAL_CALL convertToXmlAttributes(const css::lang::Locale &aLocale, sal_Int16 nNativeNumberMode) override
Any value
int nCount
constexpr OUStringLiteral TITLE
float u
#define max(a, b)
#define SAL_N_ELEMENTS(arr)
aStr
Reference< XComponentContext > getProcessComponentContext()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
Constant values shared between i18npool and, for example, the number formatter.
const sal_Int16 Multiplier_Hangul_ko
Definition: numberchar.h:216
static sal_uInt16 SeparatorChar[]
Definition: numberchar.h:167
static bool natNumIn(sal_Int16 num, const sal_Int16 natnum[], sal_Int16 len)
const sal_Int16 Multiplier_Lower_zh_TW
Definition: numberchar.h:212
static void makeHebrewNumber(sal_Int64 value, OUStringBuffer &output, bool isLast, bool useGeresh)
const sal_Int16 NumberChar_Upper_zh_TW
Definition: numberchar.h:31
constexpr OUStringLiteral implementationName
const sal_Int16 ExponentCount_7_CJK
Definition: numberchar.h:256
const sal_Int16 ExponentCount_6_CJK
Definition: numberchar.h:221
const sal_Int16 NumberChar_lo
Definition: numberchar.h:50
static OUString AsciiToNative(const OUString &inStr, sal_Int32 nCount, Sequence< sal_Int32 > *pOffset, const Number *number)
const sal_Unicode MultiplierChar_7_CJK[][ExponentCount_7_CJK]
Definition: numberchar.h:261
const sal_Int16 NumberChar_bn
Definition: numberchar.h:43
const sal_Int16 NumberChar_or
Definition: numberchar.h:41
const sal_Int16 NumberChar_kn
Definition: numberchar.h:48
static bool AsciiToNative_numberMaker(const sal_Unicode *str, sal_Int32 begin, sal_Int32 len, sal_Unicode *dst, sal_Int32 &count, sal_Int16 multiChar_index, Sequence< sal_Int32 > *pOffset, sal_Int32 startPos, const Number *number, const sal_Unicode *numberChar)
const sal_Int16 Multiplier_Traditional_ja
Definition: numberchar.h:218
static void makeCyrillicNumber(sal_Int64 value, OUStringBuffer &output, bool addTitlo)
const sal_Unicode MinusChar[]
Definition: numberchar.h:132
const sal_Int16 NumberChar_ne
Definition: numberchar.h:56
static OUString getCyrillicNativeNumberString(const OUString &aNumberString)
static OUString getHebrewNativeNumberString(const OUString &aNumberString, bool useGeresh)
const sal_Int16 NumberChar_mr
Definition: numberchar.h:42
const sal_Int16 NumberChar_Traditional_ja
Definition: numberchar.h:33
const sal_Int16 NumberChar_bo
Definition: numberchar.h:51
const sal_Int16 NumberChar_cu
Definition: numberchar.h:58
const sal_Int16 NumberChar_dz
Definition: numberchar.h:57
const sal_Unicode MultiplierChar_2_CJK[][ExponentCount_2_CJK]
Definition: numberchar.h:244
const sal_Int16 NumberChar_Upper_zh
Definition: numberchar.h:30
const sal_Unicode geresh
const sal_Int16 Multiplier_Count
Definition: numberchar.h:219
const sal_Int16 NumberChar_gu
Definition: numberchar.h:45
static sal_Unicode DecimalChar[]
Definition: numberchar.h:97
const sal_Int16 NumberChar_ml
Definition: numberchar.h:49
static OUString AsciiToNativeChar(const OUString &inStr, sal_Int32 nCount, Sequence< sal_Int32 > *pOffset, sal_Int16 number)
const sal_Int16 MultiplierExponent_6_CJK[ExponentCount_6_CJK]
Definition: numberchar.h:223
const sal_Unicode thousands_last[]
const sal_Int16 ExponentCount_2_CJK
Definition: numberchar.h:238
const sal_Unicode cyrillicTitlo
const sal_Int16 NumberChar_my
Definition: numberchar.h:52
const sal_Int16 NumberChar_ta
Definition: numberchar.h:46
const sal_Int16 MultiplierExponent_7_CJK[ExponentCount_7_CJK]
Definition: numberchar.h:258
const sal_Int16 NumberChar_HalfWidth
Definition: numberchar.h:27
const sal_Unicode gershayim
const sal_Int16 Multiplier_Upper_zh_TW
Definition: numberchar.h:213
const sal_Int16 NumberChar_Indic_ar
Definition: numberchar.h:37
const sal_Int16 NumberChar_FullWidth
Definition: numberchar.h:28
const sal_Int16 NumberChar_Lower_zh
Definition: numberchar.h:29
const sal_Int16 NumberChar_Modern_ja
Definition: numberchar.h:32
const sal_Unicode cyrillicThousandsMark
const sal_Unicode thousand[]
const sal_Unicode cyrillicTen
const sal_Int16 Multiplier_Upper_zh
Definition: numberchar.h:211
const sal_Unicode MultiplierChar_6_CJK[][ExponentCount_6_CJK]
Definition: numberchar.h:226
const sal_Int16 Multiplier_Lower_zh
Definition: numberchar.h:210
const sal_Int16 MultiplierExponent_2_CJK[ExponentCount_2_CJK]
Definition: numberchar.h:240
const sal_Int16 Multiplier_Lower_ko
Definition: numberchar.h:214
const sal_Unicode thousands[]
const sal_Int16 NumberChar_te
Definition: numberchar.h:47
const sal_Int16 NumberChar_Count
Definition: numberchar.h:59
const sal_Int16 NumberChar_Upper_ko
Definition: numberchar.h:35
const sal_Int16 NumberChar_hi
Definition: numberchar.h:39
const sal_Unicode NumberChar[][10]
Definition: numberchar.h:61
HebrewNumberChar const HebrewNumberCharArray[]
CyrillicNumberChar const CyrillicNumberCharArray[]
const sal_Int16 NumberChar_Hangul_ko
Definition: numberchar.h:36
const sal_Int16 NumberChar_Lower_ko
Definition: numberchar.h:34
const sal_Int16 NumberChar_mn
Definition: numberchar.h:54
const sal_Int16 Multiplier_Modern_ja
Definition: numberchar.h:217
const sal_Int16 NumberChar_th
Definition: numberchar.h:40
const sal_Int16 NumberChar_he
Definition: numberchar.h:55
const sal_Int16 NumberChar_pa
Definition: numberchar.h:44
const sal_Int16 NumberChar_EastIndic_ar
Definition: numberchar.h:38
const sal_Int16 NumberChar_km
Definition: numberchar.h:53
const sal_Int16 Multiplier_Upper_ko
Definition: numberchar.h:215
index
int shift
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
enumrange< T >::Iterator begin(enumrange< T >)
end
#define NUMBER_OMIT_ONE_CHECK(bit)
sal_Unicode ThousandSeparator
#define NUMBER_OMIT_ZERO
#define NUMBER_OMIT_ZERO_ONE
sal_Unicode code
#define NUMBER_OMIT_ONLY_ZERO
#define NUMBER_OMIT_ALL
#define NUMBER_OMIT_ZERO_ONE_67
sal_Unicode DecimalSeparator
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_i18n_NativeNumberSupplier_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
#define isMinus(n)
Definition: numberchar.h:207
#define isSeparator(n)
Definition: numberchar.h:208
#define NUMBER_ZERO
Definition: numberchar.h:202
#define isDecimal(n)
Definition: numberchar.h:206
#define isNumber(n)
Definition: numberchar.h:205
#define NUMBER_ONE
Definition: numberchar.h:203
unsigned char sal_Bool
sal_uInt16 sal_Unicode
ResultType type