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) || ch == aSeparators.DecimalSeparator)
590 {
591 ++count;
592 sBuf.append(ch);
593 }
594 else if (ch == aSeparators.ThousandSeparator && count > 0)
595 continue;
596 else if (isMinus(ch) && count == 0)
597 sBuf.append(ch);
598 else
599 break;
600 }
601
602 // Handle also month and day names for NatNum12 date formatting
603 const OUString& rNumberStr = (count == 0) ? rNumberString : sBuf.makeStringAndClear();
604
605 static auto xNumberText
606 = css::linguistic2::NumberText::create(comphelper::getProcessComponentContext());
607
608 // Guard the static variables below.
609 std::scoped_lock aGuard( theNatNumMutex );
610
611 OUString numbertext_prefix;
612 // default "cardinal" gets empty prefix
613 if (!sNumberTextParams.empty() && sNumberTextParams != u"cardinal")
614 numbertext_prefix = OUString::Concat(sNumberTextParams) + " ";
615 // Several hundreds of headings could result typing lags because
616 // of the continuous update of the multiple number names during typing.
617 // We fix this by buffering the result of the conversion.
618 static std::unordered_map<OUString, std::map<OUString, OUString>> aBuff;
619 auto& rItems = aBuff[rNumberStr];
620 auto& rItem = rItems[numbertext_prefix + aLoc];
621 if (rItem.isEmpty())
622 {
623 rItem = xNumberText->getNumberText(numbertext_prefix + rNumberStr, rLocale);
624 // use number at missing number to text conversion
625 if (rItem.isEmpty())
626 rItem = rNumberStr;
627 }
628 OUString sResult = rItem;
629 if (i != 0 && i < len)
630 sResult += rNumberString.subView(i);
631 return sResult;
632}
633}
634
635OUString NativeNumberSupplierService::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
636 sal_Int16 nNativeNumberMode,
637 Sequence<sal_Int32>* pOffset,
638 std::u16string_view rNativeNumberParams)
639{
640 if (!isValidNatNumImpl(rLocale, nNativeNumberMode))
641 return aNumberString;
642
643 if (nNativeNumberMode == NativeNumberMode::NATNUM12)
644 {
645 // handle capitalization prefixes "capitalize", "upper", "lower" and "title"
646
647 enum WhichCasing
648 {
650 UPPER,
651 LOWER,
652 TITLE
653 };
654
655 struct CasingEntry
656 {
657 std::u16string_view aLiteral;
658 WhichCasing eCasing;
659 };
660
661 static const CasingEntry Casings[] =
662 {
663 { std::u16string_view(u"capitalize"), CAPITALIZE },
664 { std::u16string_view(u"upper"), UPPER },
665 { std::u16string_view(u"lower"), LOWER },
666 { std::u16string_view(u"title"), TITLE }
667 };
668
669 std::size_t nStripCase = 0;
670 size_t nCasing;
671 for (nCasing = 0; nCasing < SAL_N_ELEMENTS(Casings); ++nCasing)
672 {
673 if (o3tl::starts_with(rNativeNumberParams, Casings[nCasing].aLiteral))
674 {
675 nStripCase = Casings[nCasing].aLiteral.size();
676 break;
677 }
678 }
679
680 if (nStripCase > 0 && (rNativeNumberParams.size() == nStripCase ||
681 rNativeNumberParams[nStripCase++] == ' '))
682 {
683 OUString aStr = getNumberText(rLocale, aNumberString, rNativeNumberParams.substr(nStripCase));
684
685 if (!xCharClass.is())
686 xCharClass = CharacterClassification::create(comphelper::getProcessComponentContext());
687
688 switch (Casings[nCasing].eCasing)
689 {
690 case CAPITALIZE:
691 return xCharClass->toTitle(aStr, 0, 1, aLocale) +
692 (aStr.getLength() > 1 ? aStr.subView(1) : u"");
693 case UPPER:
694 return xCharClass->toUpper(aStr, 0, aStr.getLength(), aLocale);
695 case LOWER:
696 return xCharClass->toLower(aStr, 0, aStr.getLength(), aLocale);
697 case TITLE:
698 {
699 if ( rLocale.Language == "en" )
700 {
701 // title case is common in English, so fix bugs of toTitle():
702 // not "One Dollar *And* *Twenty-two* Cents", but
703 // "One Dollar *and* *Twenty-Two* Cents".
704
705 // Add spaces after hyphens to separate the elements of the
706 // hyphenated compound words temporarily, allowing their
707 // capitalization by toTitle()
708 aStr = aStr.replaceAll("-", "- ");
709 aStr = xCharClass->toTitle(aStr, 0, aStr.getLength(), aLocale);
710 return aStr.replaceAll("- ", "-").replaceAll(" And ", " and ");
711 }
712 else
713 return xCharClass->toTitle(aStr, 0, aStr.getLength(), aLocale);
714 }
715 }
716 }
717 else
718 {
719 return getNumberText(rLocale, aNumberString, rNativeNumberParams);
720 }
721 }
722
723 sal_Int16 langnum = getLanguageNumber(rLocale);
724 if (langnum == -1)
725 return aNumberString;
726
727 const Number *number = nullptr;
728 sal_Int16 num = -1;
729
730 switch (nNativeNumberMode)
731 {
732 case NativeNumberMode::NATNUM0: // Ascii
733 return NativeToAscii(aNumberString, aNumberString.getLength(), pOffset);
734 case NativeNumberMode::NATNUM1: // Char, Lower
735 num = natnum1[langnum];
736 break;
737 case NativeNumberMode::NATNUM2: // Char, Upper
738 num = natnum2[langnum];
739 break;
740 case NativeNumberMode::NATNUM3: // Char, FullWidth
742 break;
743 case NativeNumberMode::NATNUM4: // Text, Lower, Long
744 number = &natnum4[langnum];
745 break;
746 case NativeNumberMode::NATNUM5: // Text, Upper, Long
747 number = &natnum5[langnum];
748 break;
749 case NativeNumberMode::NATNUM6: // Text, FullWidth
750 number = &natnum6[langnum];
751 break;
752 case NativeNumberMode::NATNUM7: // Text. Lower, Short
753 number = &natnum7[langnum];
754 break;
755 case NativeNumberMode::NATNUM8: // Text, Upper, Short
756 number = &natnum8[langnum];
757 break;
758 case NativeNumberMode::NATNUM9: // Char, Hangul
760 break;
761 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
762 number = &natnum10;
763 break;
764 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
765 number = &natnum11;
766 break;
767 default:
768 break;
769 }
770
771 if (number || num >= 0) {
772 if (aLocale.Language != rLocale.Language ||
773 aLocale.Country != rLocale.Country ||
774 aLocale.Variant != rLocale.Variant) {
775 LocaleDataItem item = LocaleDataImpl::get()->getLocaleItem( rLocale );
776 aLocale = rLocale;
777 DecimalChar[NumberChar_HalfWidth]=item.decimalSeparator.toChar();
780 else
782 SeparatorChar[NumberChar_HalfWidth]=item.thousandSeparator.toChar();
785 else
787 }
788 if (number)
789 return AsciiToNative( aNumberString, aNumberString.getLength(), pOffset, number );
790 else if (num == NumberChar_he)
791 return getHebrewNativeNumberString(aNumberString,
792 nNativeNumberMode == NativeNumberMode::NATNUM2);
793 else if (num == NumberChar_cu)
794 return getCyrillicNativeNumberString(aNumberString);
795 else
796 return AsciiToNativeChar(aNumberString, aNumberString.getLength(), pOffset, num);
797 }
798 else
799 return aNumberString;
800}
801
802OUString SAL_CALL NativeNumberSupplierService::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
803 sal_Int16 nNativeNumberMode)
804{
805 return getNativeNumberString(aNumberString, rLocale, nNativeNumberMode, nullptr);
806}
807
809 const OUString& rNumberString, const css::lang::Locale& rLocale, sal_Int16 nNativeNumberMode,
810 const OUString& rNativeNumberParams)
811{
812 return getNativeNumberString(rNumberString, rLocale, nNativeNumberMode, nullptr, rNativeNumberParams);
813}
814
815sal_Unicode NativeNumberSupplierService::getNativeNumberChar( const sal_Unicode inChar, const Locale& rLocale, sal_Int16 nNativeNumberMode )
816{
817 if (nNativeNumberMode == NativeNumberMode::NATNUM0) { // Ascii
818 for (const auto & i : NumberChar)
819 for (sal_Int16 j = 0; j < 10; j++)
820 if (inChar == i[j])
821 return j;
822 return inChar;
823 }
824
825 if (!isNumber(inChar))
826 return inChar;
827
828 if (!isValidNatNumImpl(rLocale, nNativeNumberMode))
829 return inChar;
830
831 sal_Int16 langnum = getLanguageNumber(rLocale);
832 if (langnum == -1)
833 return inChar;
834
835 switch (nNativeNumberMode)
836 {
837 case NativeNumberMode::NATNUM1: // Char, Lower
838 case NativeNumberMode::NATNUM4: // Text, Lower, Long
839 case NativeNumberMode::NATNUM7: // Text. Lower, Short
840 return NumberChar[natnum1[langnum]][inChar - NUMBER_ZERO];
841 case NativeNumberMode::NATNUM2: // Char, Upper
842 case NativeNumberMode::NATNUM5: // Text, Upper, Long
843 case NativeNumberMode::NATNUM8: // Text, Upper, Short
844 return NumberChar[natnum2[langnum]][inChar - NUMBER_ZERO];
845 case NativeNumberMode::NATNUM3: // Char, FullWidth
846 case NativeNumberMode::NATNUM6: // Text, FullWidth
848 case NativeNumberMode::NATNUM9: // Char, Hangul
849 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
850 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
852 default:
853 break;
854 }
855
856 return inChar;
857}
858
859bool NativeNumberSupplierService::isValidNatNumImpl( const Locale& rLocale, sal_Int16 nNativeNumberMode )
860{
861 sal_Int16 langnum = getLanguageNumber(rLocale);
862
863 switch (nNativeNumberMode) {
864 case NativeNumberMode::NATNUM0: // Ascii
865 case NativeNumberMode::NATNUM3: // Char, FullWidth
866 case NativeNumberMode::NATNUM12: // spell out numbers, dates and money amounts
867 return true;
868 case NativeNumberMode::NATNUM1: // Char, Lower
869 return (langnum >= 0);
870 case NativeNumberMode::NATNUM2: // Char, Upper
871 if (langnum == 4) // Hebrew numbering
872 return true;
873 [[fallthrough]];
874 case NativeNumberMode::NATNUM4: // Text, Lower, Long
875 case NativeNumberMode::NATNUM5: // Text, Upper, Long
876 case NativeNumberMode::NATNUM6: // Text, FullWidth
877 case NativeNumberMode::NATNUM7: // Text. Lower, Short
878 case NativeNumberMode::NATNUM8: // Text, Upper, Short
879 return (langnum >= 0 && langnum < 4); // CJK numbering
880 case NativeNumberMode::NATNUM9: // Char, Hangul
881 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
882 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
883 return (langnum == 3); // Korean numbering
884 }
885 return false;
886}
887
888NativeNumberXmlAttributes SAL_CALL NativeNumberSupplierService::convertToXmlAttributes( const Locale& rLocale, sal_Int16 nNativeNumberMode )
889{
890 static const sal_Int16 attShort = 0;
891 static const sal_Int16 attMedium = 1;
892 static const sal_Int16 attLong = 2;
893 static const char *attType[] = { "short", "medium", "long" };
894
895 sal_Int16 number = NumberChar_HalfWidth, type = attShort;
896
897 sal_Int16 langnum = -1;
898 if (isValidNatNum(rLocale, nNativeNumberMode)) {
899 langnum = getLanguageNumber(rLocale);
900 }
901 if (langnum != -1) {
902 switch (nNativeNumberMode) {
903 case NativeNumberMode::NATNUM0: // Ascii
904 number = NumberChar_HalfWidth;
905 type = attShort;
906 break;
907 case NativeNumberMode::NATNUM1: // Char, Lower
908 number = natnum1[langnum];
909 type = attShort;
910 break;
911 case NativeNumberMode::NATNUM2: // Char, Upper
912 number = natnum2[langnum];
913 type = number == NumberChar_he ? attMedium : attShort;
914 break;
915 case NativeNumberMode::NATNUM3: // Char, FullWidth
916 number = NumberChar_FullWidth;
917 type = attShort;
918 break;
919 case NativeNumberMode::NATNUM4: // Text, Lower, Long
920 number = natnum1[langnum];
921 type = attLong;
922 break;
923 case NativeNumberMode::NATNUM5: // Text, Upper, Long
924 number = natnum2[langnum];
925 type = attLong;
926 break;
927 case NativeNumberMode::NATNUM6: // Text, FullWidth
928 number = NumberChar_FullWidth;
929 type = attLong;
930 break;
931 case NativeNumberMode::NATNUM7: // Text. Lower, Short
932 number = natnum1[langnum];
933 type = attMedium;
934 break;
935 case NativeNumberMode::NATNUM8: // Text, Upper, Short
936 number = natnum2[langnum];
937 type = attMedium;
938 break;
939 case NativeNumberMode::NATNUM9: // Char, Hangul
940 number = NumberChar_Hangul_ko;
941 type = attShort;
942 break;
943 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
944 number = NumberChar_Hangul_ko;
945 type = attLong;
946 break;
947 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
948 number = NumberChar_Hangul_ko;
949 type = attMedium;
950 break;
951 default:
952 break;
953 }
954 }
955 return NativeNumberXmlAttributes(rLocale, OUString(&NumberChar[number][1], 1),
956 OUString::createFromAscii(attType[type]));
957}
958
959static bool natNumIn(sal_Int16 num, const sal_Int16 natnum[], sal_Int16 len)
960{
961 for (sal_Int16 i = 0; i < len; i++)
962 if (natnum[i] == num)
963 return true;
964 return false;
965}
966
967sal_Int16 SAL_CALL NativeNumberSupplierService::convertFromXmlAttributes( const NativeNumberXmlAttributes& aAttr )
968{
969 sal_Unicode numberChar[NumberChar_Count];
970 for (sal_Int16 i = 0; i < NumberChar_Count; i++)
971 numberChar[i] = NumberChar[i][1];
972 OUString number(numberChar, NumberChar_Count);
973
974 sal_Int16 num = sal::static_int_cast<sal_Int16>( number.indexOf(aAttr.Format) );
975
976 if ( aAttr.Style == "short" ) {
977 if (num == NumberChar_FullWidth)
978 return NativeNumberMode::NATNUM3;
979 else if (num == NumberChar_Hangul_ko)
980 return NativeNumberMode::NATNUM9;
981 else if (natNumIn(num, natnum1, sizeof_natnum1))
982 return NativeNumberMode::NATNUM1;
983 else if (natNumIn(num, natnum2, sizeof_natnum2))
984 return NativeNumberMode::NATNUM2;
985 } else if ( aAttr.Style == "medium" ) {
986 if (num == NumberChar_Hangul_ko)
987 return NativeNumberMode::NATNUM11;
988 else if (num == NumberChar_he)
989 return NativeNumberMode::NATNUM2;
990 else if (natNumIn(num, natnum1, sizeof_natnum1))
991 return NativeNumberMode::NATNUM7;
992 else if (natNumIn(num, natnum2, sizeof_natnum2))
993 return NativeNumberMode::NATNUM8;
994 } else if ( aAttr.Style == "long" ) {
995 if (num == NumberChar_FullWidth)
996 return NativeNumberMode::NATNUM6;
997 else if (num == NumberChar_Hangul_ko)
998 return NativeNumberMode::NATNUM10;
999 else if (natNumIn(num, natnum1, sizeof_natnum1))
1000 return NativeNumberMode::NATNUM4;
1001 else if (natNumIn(num, natnum2, sizeof_natnum2))
1002 return NativeNumberMode::NATNUM5;
1003 } else {
1004 throw RuntimeException();
1005 }
1006 return NativeNumberMode::NATNUM0;
1007}
1008
1009
1010// Following code generates Hebrew Number,
1011// see numerical system in the Hebrew Numbering System in following link for details,
1012// http://smontagu.org/writings/HebrewNumbers.html
1013
1014namespace {
1015
1016struct HebrewNumberChar {
1018 sal_Int16 value;
1019};
1020
1021}
1022
1023HebrewNumberChar const HebrewNumberCharArray[] = {
1024 { 0x05ea, 400 },
1025 { 0x05ea, 400 },
1026 { 0x05e9, 300 },
1027 { 0x05e8, 200 },
1028 { 0x05e7, 100 },
1029 { 0x05e6, 90 },
1030 { 0x05e4, 80 },
1031 { 0x05e2, 70 },
1032 { 0x05e1, 60 },
1033 { 0x05e0, 50 },
1034 { 0x05de, 40 },
1035 { 0x05dc, 30 },
1036 { 0x05db, 20 },
1037 { 0x05d9, 10 },
1038 { 0x05d8, 9 },
1039 { 0x05d7, 8 },
1040 { 0x05d6, 7 },
1041 { 0x05d5, 6 },
1042 { 0x05d4, 5 },
1043 { 0x05d3, 4 },
1044 { 0x05d2, 3 },
1045 { 0x05d1, 2 },
1046 { 0x05d0, 1 }
1047};
1048
1049const sal_Unicode thousand[] = {0x05d0, 0x05dc, 0x05e3, 0x0};
1050const sal_Unicode thousands[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0};
1051const sal_Unicode thousands_last[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0};
1052const sal_Unicode geresh = 0x05f3;
1053const sal_Unicode gershayim = 0x05f4;
1054
1055static void makeHebrewNumber(sal_Int64 value, OUStringBuffer& output, bool isLast, bool useGeresh)
1056{
1057 sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000);
1058
1059 if (value > 1000) {
1060 makeHebrewNumber(value / 1000, output, num != 0, useGeresh);
1061 output.append(" ");
1062 }
1063 if (num == 0) {
1064 output.append(value == 1000 ? thousand : isLast ? thousands_last : thousands);
1065 } else {
1066 sal_Int16 nbOfChar = 0;
1067 for (sal_Int32 j = 0; num > 0 && j < sal_Int32(SAL_N_ELEMENTS(HebrewNumberCharArray)); j++) {
1068 if (num - HebrewNumberCharArray[j].value >= 0) {
1069 nbOfChar++;
1070 // https://en.wikipedia.org/wiki/Hebrew_numerals#Key_exceptions
1071 // By convention, the numbers 15 and 16 are represented as 9 + 6 and 9 + 7
1072 if (num == 15 || num == 16) // substitution for 15 and 16
1073 j++;
1074 assert(j < sal_Int32(SAL_N_ELEMENTS(HebrewNumberCharArray)));
1075 num = sal::static_int_cast<sal_Int16>( num - HebrewNumberCharArray[j].value );
1076 output.append(HebrewNumberCharArray[j].code);
1077 }
1078 }
1079 if (useGeresh) {
1080 if (nbOfChar > 1) // a number is written as more than one character
1081 output.insert(output.getLength() - 1, gershayim);
1082 else if (nbOfChar == 1) // a number is written as a single character
1083 output.append(geresh);
1084 }
1085 }
1086}
1087
1088OUString getHebrewNativeNumberString(const OUString& aNumberString, bool useGeresh)
1089{
1090 sal_Int64 value = 0;
1091 sal_Int32 i, count = 0, len = aNumberString.getLength();
1092 const sal_Unicode *src = aNumberString.getStr();
1093
1094 for (i = 0; i < len; i++) {
1095 sal_Unicode ch = src[i];
1096 if (isNumber(ch)) {
1097 if (++count >= 20) // Number is too long, could not be handled.
1098 return aNumberString;
1099 value = value * 10 + (ch - NUMBER_ZERO);
1100 }
1101 else if (isSeparator(ch) && count > 0) continue;
1102 else if (isMinus(ch) && count == 0) continue;
1103 else break;
1104 }
1105
1106 if (value > 0) {
1107 OUStringBuffer output(count*2 + 2 + len - i);
1108
1109 makeHebrewNumber(value, output, true, useGeresh);
1110
1111 if (i < len)
1112 output.append(aNumberString.subView(i));
1113
1114 return output.makeStringAndClear();
1115 }
1116 else
1117 return aNumberString;
1118}
1119
1120// Support for Cyrillic Numerals
1121// See UTN 41 for implementation information
1122// http://www.unicode.org/notes/tn41/
1123
1127
1128namespace {
1129
1130struct CyrillicNumberChar {
1132 sal_Int16 value;
1133};
1134
1135}
1136
1137CyrillicNumberChar const CyrillicNumberCharArray[] = {
1138 { 0x0446, 900 },
1139 { 0x047f, 800 },
1140 { 0x0471, 700 },
1141 { 0x0445, 600 },
1142 { 0x0444, 500 },
1143 { 0x0443, 400 },
1144 { 0x0442, 300 },
1145 { 0x0441, 200 },
1146 { 0x0440, 100 },
1147 { 0x0447, 90 },
1148 { 0x043f, 80 },
1149 { 0x047b, 70 },
1150 { 0x046f, 60 },
1151 { 0x043d, 50 },
1152 { 0x043c, 40 },
1153 { 0x043b, 30 },
1154 { 0x043a, 20 },
1155 { 0x0456, 10 },
1156 { 0x0473, 9 },
1157 { 0x0438, 8 },
1158 { 0x0437, 7 },
1159 { 0x0455, 6 },
1160 { 0x0454, 5 },
1161 { 0x0434, 4 },
1162 { 0x0433, 3 },
1163 { 0x0432, 2 },
1164 { 0x0430, 1 }
1165};
1166
1167static void makeCyrillicNumber(sal_Int64 value, OUStringBuffer& output, bool addTitlo)
1168{
1169 sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000);
1170 if (value >= 1000) {
1171 output.append(cyrillicThousandsMark);
1172 makeCyrillicNumber(value / 1000, output, false);
1173 if (value >= 10000 && (value - 10000) % 1000 != 0) {
1174 output.append(" ");
1175 }
1176 if (value % 1000 == 0)
1177 addTitlo = false;
1178 }
1179
1180 for (sal_Int32 j = 0; num > 0 && j < sal_Int32(SAL_N_ELEMENTS(CyrillicNumberCharArray)); j++) {
1181 if (num < 20 && num > 10) {
1182 num -= 10;
1183 makeCyrillicNumber(num, output, false);
1184 output.append(cyrillicTen);
1185 break;
1186 }
1187
1188 if (CyrillicNumberCharArray[j].value <= num) {
1189 output.append(CyrillicNumberCharArray[j].code);
1190 num = sal::static_int_cast<sal_Int16>( num - CyrillicNumberCharArray[j].value );
1191 }
1192 }
1193
1194 if (!addTitlo)
1195 return;
1196
1197 if (output.getLength() == 1) {
1198 output.append(cyrillicTitlo);
1199 } else if (output.getLength() == 2) {
1200 if (value > 800 && value < 900) {
1201 output.append(cyrillicTitlo);
1202 } else {
1203 output.insert(1, cyrillicTitlo);
1204 }
1205 } else if (output.getLength() > 2) {
1206 if (output.indexOf(" ") == output.getLength() - 2) {
1207 output.append(cyrillicTitlo);
1208 } else {
1209 output.insert(output.getLength() - 1, cyrillicTitlo);
1210 }
1211 }
1212}
1213
1214OUString getCyrillicNativeNumberString(const OUString& aNumberString)
1215{
1216 sal_Int64 value = 0;
1217 sal_Int32 i, count = 0, len = aNumberString.getLength();
1218 const sal_Unicode *src = aNumberString.getStr();
1219
1220 for (i = 0; i < len; i++) {
1221 sal_Unicode ch = src[i];
1222 if (isNumber(ch)) {
1223 if (++count >= 8) // Number is too long, could not be handled.
1224 return aNumberString;
1225 value = value * 10 + (ch - NUMBER_ZERO);
1226 }
1227 else if (isSeparator(ch) && count > 0) continue;
1228 else if (isMinus(ch) && count == 0) continue;
1229 else break;
1230 }
1231
1232 if (value > 0) {
1233 OUStringBuffer output(count*2 + 2 + len - i);
1234
1235 makeCyrillicNumber(value, output, true);
1236
1237 if (i < len)
1238 output.append(aNumberString.subView(i));
1239
1240 return output.makeStringAndClear();
1241 }
1242 else
1243 return aNumberString;
1244}
1245
1246constexpr OUStringLiteral implementationName = u"com.sun.star.i18n.NativeNumberSupplier";
1247
1249{
1250 return implementationName;
1251}
1252
1253sal_Bool SAL_CALL
1255{
1256 return cppu::supportsService(this, rServiceName);
1257}
1258
1259Sequence< OUString > SAL_CALL
1261{
1262 return {implementationName, "com.sun.star.i18n.NativeNumberSupplier2"};
1263}
1264
1265}
1266
1267extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1269 css::uno::XComponentContext *,
1270 css::uno::Sequence<css::uno::Any> const &)
1271{
1272 return cppu::acquire(new i18npool::NativeNumberSupplierService());
1273}
1274
1275/* 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