react-native-executorch 0.10.6 → 0.10.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/module/fetcher/telemetry.js +1 -1
- package/package.json +1 -1
- package/react-native-executorch.podspec +2 -0
- package/src/fetcher/telemetry.ts +1 -1
- package/third-party/common/phonemis/CMakeLists.txt +70 -14
- package/third-party/common/phonemis/README.md +183 -33
- package/third-party/common/phonemis/THIRD_PARTY_NOTICES.md +57 -0
- package/third-party/common/phonemis/knowledge/code_style.md +642 -0
- package/third-party/common/phonemis/licenses/Unicode-3.0.txt +39 -0
- package/third-party/common/phonemis/licenses/misaki-Apache-2.0.txt +201 -0
- package/third-party/common/phonemis/licenses/nlohmann-json-MIT.txt +21 -0
- package/third-party/common/phonemis/licenses/xsimd-BSD-3-Clause.txt +29 -0
- package/third-party/common/phonemis/src/phonemis/base/config.h +6 -0
- package/third-party/common/phonemis/src/phonemis/base/ipipeline.cpp +75 -0
- package/third-party/common/phonemis/src/phonemis/base/ipipeline.h +21 -0
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/constants.h +2 -5
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/lexicon_phonemizer.cpp +3 -4
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.cpp +17 -8
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.h +4 -0
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.cpp +21 -6
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.h +13 -4
- package/third-party/common/phonemis/src/phonemis/base/pipeline.cpp +8 -0
- package/third-party/common/phonemis/src/phonemis/base/pipeline.h +19 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.cpp +37 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.h +45 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/constants.h +10 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/context.cpp +105 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/context.h +49 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/document.cpp +173 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/document.h +67 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/text.cpp +75 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/text.h +60 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/types.h +18 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/config.h +53 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layer.h +9 -7
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/constants.h +20 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.cpp +89 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.h +35 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/types.h +16 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/kind.h +40 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/layer.h +382 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/notation.h +30 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.cpp +51 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.h +31 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern.h +30 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.cpp +17 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.h +31 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.cpp +811 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.h +285 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.cpp +64 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.h +23 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/types.h +94 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/sanitizer/layer.cpp +19 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/{sanitizer_layer.h → layers/sanitizer/layer.h} +8 -8
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.cpp +65 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.h +29 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.cpp +170 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.h +40 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/types.h +25 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.cpp +47 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.h +19 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.cpp +60 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.h +45 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/processor.cpp +6 -7
- package/third-party/common/phonemis/src/phonemis/base/processor/processor.h +14 -10
- package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.cpp +89 -52
- package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.h +16 -9
- package/third-party/common/phonemis/src/phonemis/base/tokenizer/tokenizer.cpp +13 -12
- package/third-party/common/phonemis/src/phonemis/lang/de/constants.h +183 -19
- package/third-party/common/phonemis/src/phonemis/lang/de/num2word.cpp +355 -309
- package/third-party/common/phonemis/src/phonemis/lang/de/num2word.h +42 -17
- package/third-party/common/phonemis/src/phonemis/lang/de/patterns.cpp +56 -0
- package/third-party/common/phonemis/src/phonemis/lang/de/patterns.h +15 -0
- package/third-party/common/phonemis/src/phonemis/lang/de/pipeline.h +3 -3
- package/third-party/common/phonemis/src/phonemis/lang/en/constants.h +181 -30
- package/third-party/common/phonemis/src/phonemis/lang/en/hmm_tagger.cpp +5 -7
- package/third-party/common/phonemis/src/phonemis/lang/en/num2word.cpp +232 -135
- package/third-party/common/phonemis/src/phonemis/lang/en/num2word.h +41 -16
- package/third-party/common/phonemis/src/phonemis/lang/en/pipeline.h +3 -10
- package/third-party/common/phonemis/src/phonemis/lang/es/constants.h +182 -60
- package/third-party/common/phonemis/src/phonemis/lang/es/num2word.cpp +247 -212
- package/third-party/common/phonemis/src/phonemis/lang/es/num2word.h +38 -18
- package/third-party/common/phonemis/src/phonemis/lang/es/patterns.cpp +50 -0
- package/third-party/common/phonemis/src/phonemis/lang/es/patterns.h +15 -0
- package/third-party/common/phonemis/src/phonemis/lang/es/pipeline.h +3 -3
- package/third-party/common/phonemis/src/phonemis/lang/fr/constants.h +152 -26
- package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.cpp +252 -179
- package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.h +38 -15
- package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.cpp +83 -0
- package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.h +15 -0
- package/third-party/common/phonemis/src/phonemis/lang/fr/pipeline.h +3 -3
- package/third-party/common/phonemis/src/phonemis/lang/hi/constants.h +62 -10
- package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.cpp +74 -123
- package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.h +27 -16
- package/third-party/common/phonemis/src/phonemis/lang/hi/pipeline.h +5 -3
- package/third-party/common/phonemis/src/phonemis/lang/it/constants.h +122 -42
- package/third-party/common/phonemis/src/phonemis/lang/it/num2word.cpp +200 -207
- package/third-party/common/phonemis/src/phonemis/lang/it/num2word.h +30 -18
- package/third-party/common/phonemis/src/phonemis/lang/it/patterns.cpp +25 -0
- package/third-party/common/phonemis/src/phonemis/lang/it/patterns.h +15 -0
- package/third-party/common/phonemis/src/phonemis/lang/it/pipeline.h +3 -3
- package/third-party/common/phonemis/src/phonemis/lang/pl/constants.h +346 -77
- package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.cpp +631 -246
- package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.h +47 -15
- package/third-party/common/phonemis/src/phonemis/lang/pl/pipeline.h +6 -6
- package/third-party/common/phonemis/src/phonemis/lang/pt/constants.h +201 -0
- package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.cpp +365 -0
- package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.h +53 -0
- package/third-party/common/phonemis/src/phonemis/lang/pt/pipeline.h +4 -2
- package/third-party/common/phonemis/src/phonemis/main.cpp +42 -11
- package/third-party/common/phonemis/src/phonemis/protophone/meta.h +24 -0
- package/third-party/common/phonemis/src/phonemis/protophone/numeric.h +26 -0
- package/third-party/common/phonemis/src/phonemis/protophone/protophone.cpp +525 -0
- package/third-party/common/phonemis/src/phonemis/protophone/protophone.h +80 -0
- package/third-party/common/phonemis/src/phonemis/protophone/tensor.h +76 -0
- package/third-party/common/phonemis/src/phonemis/protophone/tensor_utils.h +89 -0
- package/third-party/common/phonemis/src/phonemis/protophone/tensor_view.h +125 -0
- package/third-party/common/phonemis/src/phonemis/protophone/types.h +43 -0
- package/third-party/common/phonemis/src/phonemis/utils/strings.h +20 -14
- package/third-party/common/phonemis/src/phonemis/utils/unicode.h +15 -1
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_arithmetic.hpp +267 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_bit.hpp +232 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_cast.hpp +43 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_complex.hpp +112 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_details.hpp +386 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_logical.hpp +240 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_math.hpp +2601 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_memory.hpp +1006 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_rounding.hpp +72 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_swizzle.hpp +260 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_trigo.hpp +996 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/utils/shifts.hpp +82 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx.hpp +2111 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2.hpp +1591 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2_128.hpp +170 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512bw.hpp +724 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512cd.hpp +28 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512dq.hpp +270 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512er.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512f.hpp +2919 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512ifma.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512pf.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi.hpp +76 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi2.hpp +130 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512bw.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512vbmi2.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx_128.hpp +164 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avxvnni.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common.hpp +26 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common_fwd.hpp +127 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_constants.hpp +393 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_emulated.hpp +787 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx.hpp +93 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx2.hpp +46 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_sse.hpp +97 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma4.hpp +92 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_i8mm_neon64.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_isa.hpp +148 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon.hpp +3580 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon64.hpp +1614 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_rvv.hpp +1515 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_scalar.hpp +1210 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse2.hpp +2333 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse3.hpp +66 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_1.hpp +510 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_2.hpp +44 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_ssse3.hpp +186 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sve.hpp +1186 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vsx.hpp +947 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vxe.hpp +787 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_wasm.hpp +1819 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_arch.hpp +242 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_config.hpp +633 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_arm.hpp +132 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_ppc.hpp +54 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_riscv.hpp +95 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_s390x.hpp +56 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_x86.hpp +1121 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpuid.hpp +144 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_getauxval.hpp +159 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_macros.hpp +78 -0
- package/third-party/common/phonemis/src/third-party/xsimd/math/xsimd_rem_pio2.hpp +707 -0
- package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_aligned_allocator.hpp +349 -0
- package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_alignment.hpp +102 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_all_registers.hpp +57 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_api.hpp +3106 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx2_register.hpp +57 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512bw_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512cd_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512dq_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512er_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512f_register.hpp +77 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512ifma_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512pf_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi2_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512bw_register.hpp +54 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512vbmi2_register.hpp +53 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx_register.hpp +79 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avxvnni_register.hpp +44 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch.hpp +1666 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_constant.hpp +572 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_fwd.hpp +41 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_common_arch.hpp +49 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_emulated_register.hpp +80 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx2_register.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx_register.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_sse_register.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma4_register.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_i8mm_neon64_register.hpp +55 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon64_register.hpp +55 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon_register.hpp +130 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_register.hpp +96 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_rvv_register.hpp +491 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse2_register.hpp +59 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse3_register.hpp +49 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_1_register.hpp +48 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_2_register.hpp +48 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_ssse3_register.hpp +48 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sve_register.hpp +216 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_traits.hpp +409 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_utils.hpp +462 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vsx_register.hpp +84 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vxe_register.hpp +86 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_wasm_register.hpp +59 -0
- package/third-party/common/phonemis/src/third-party/xsimd/utils/bits.hpp +122 -0
- package/third-party/common/phonemis/src/third-party/xsimd/utils/xsimd_type_traits.hpp +145 -0
- package/third-party/common/phonemis/src/third-party/xsimd/xsimd.hpp +43 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/constants.h +0 -11
- package/third-party/common/phonemis/src/phonemis/base/processor/num2word/config.h +0 -16
- package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.cpp +0 -271
- package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.h +0 -45
- package/third-party/common/phonemis/src/phonemis/base/processor/num2word/types.h +0 -29
- package/third-party/common/phonemis/src/phonemis/base/processor/sanitizer_layer.cpp +0 -22
- package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.cpp +0 -40
- package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.h +0 -22
|
@@ -1,326 +1,711 @@
|
|
|
1
|
-
#include "num2word.h"
|
|
2
1
|
#include "constants.h"
|
|
3
|
-
#include
|
|
2
|
+
#include "num2word.h"
|
|
3
|
+
#include <phonemis/base/processor/common/constants.h>
|
|
4
|
+
#include <phonemis/base/processor/layers/num2word/numerals.h>
|
|
5
|
+
#include <phonemis/base/processor/layers/num2word/patterns.h>
|
|
6
|
+
#include <phonemis/base/processor/layers/num2word/primitives.h>
|
|
7
|
+
#include <phonemis/utils/strings.h>
|
|
8
|
+
#include <phonemis/utils/unicode.h>
|
|
9
|
+
|
|
4
10
|
#include <algorithm>
|
|
5
|
-
#include <cmath>
|
|
6
|
-
#include <cstdlib>
|
|
7
11
|
#include <optional>
|
|
8
|
-
#include <
|
|
12
|
+
#include <unordered_set>
|
|
9
13
|
|
|
10
14
|
namespace phonemis::pl {
|
|
11
15
|
|
|
12
|
-
using namespace constants;
|
|
13
|
-
using namespace
|
|
14
|
-
using num2word
|
|
16
|
+
using namespace constants::num2word;
|
|
17
|
+
using namespace processor;
|
|
18
|
+
using namespace processor::num2word;
|
|
19
|
+
using namespace utils;
|
|
15
20
|
|
|
16
21
|
namespace {
|
|
22
|
+
size_t index(Case c) {
|
|
23
|
+
return static_cast<size_t>(c);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
uint64_t value(const Number& number) {
|
|
27
|
+
return value_of(number.integer).value_or(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
bool starts_with_any(std::u32string_view word, const std::vector<std::u32string>& stems) {
|
|
31
|
+
return std::ranges::any_of(stems, [word](const auto& stem) { return word.starts_with(stem); });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ------------------------
|
|
35
|
+
// ----- Number words -----
|
|
36
|
+
// ------------------------
|
|
37
|
+
|
|
38
|
+
// The column of kCardinals: nominative and accusative, genitive and locative, dative, instrumental
|
|
39
|
+
size_t column(Case c) {
|
|
40
|
+
switch (c) {
|
|
41
|
+
case Case::NOMINATIVE:
|
|
42
|
+
case Case::ACCUSATIVE:
|
|
43
|
+
return 0;
|
|
44
|
+
case Case::GENITIVE:
|
|
45
|
+
case Case::LOCATIVE:
|
|
46
|
+
return 1;
|
|
47
|
+
case Case::DATIVE:
|
|
48
|
+
return 2;
|
|
49
|
+
default:
|
|
50
|
+
return 3;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// The form of a noun after a number: 1 / 2-4 / 5+ in the nominative, the plural of the case otherwise
|
|
55
|
+
const std::u32string& form(const Noun& noun, uint64_t n, Case c, bool fraction = false) {
|
|
56
|
+
if (fraction) {
|
|
57
|
+
return noun.singular[index(Case::GENITIVE)];
|
|
58
|
+
}
|
|
59
|
+
if (n == 1) {
|
|
60
|
+
return noun.singular[index(c)];
|
|
61
|
+
}
|
|
62
|
+
if (c == Case::NOMINATIVE || c == Case::ACCUSATIVE) {
|
|
63
|
+
bool few = n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14);
|
|
64
|
+
return noun.plural[index(few ? Case::NOMINATIVE : Case::GENITIVE)];
|
|
65
|
+
}
|
|
66
|
+
return noun.plural[index(c)];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
std::u32string below_thousand(uint64_t n, Case c, Gender g) {
|
|
70
|
+
if (n == 0) {
|
|
71
|
+
return std::u32string(kCardinals.at(0)[column(c)]);
|
|
72
|
+
}
|
|
17
73
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return PluralForm::MANY;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Inflects an ordinal word from its masculine-nominative form. The form code
|
|
32
|
-
// reuses PluralForm to share a single inflection table:
|
|
33
|
-
// - SINGULAR -> feminine singular ("druga", "trzecia")
|
|
34
|
-
// - FEW -> neuter / non-masc-plural ("drugie", "czwarte")
|
|
35
|
-
// - MANY -> genitive plural ("drugich", "czwartych")
|
|
36
|
-
// The ending shape depends on the masculine stem:
|
|
37
|
-
// - hard stem (-y): drop "y", append plain ending (a / e / ych)
|
|
38
|
-
// - soft stem (-i): drop "i", append i-prefixed ending (ia / ie / ich)
|
|
39
|
-
// - velar stem (-gi/-ki): drop "i", "a" doesn't get the leading "i"
|
|
40
|
-
// Words not ending in -y or -i are returned unchanged so the helper is safe
|
|
41
|
-
// to apply across cardinal tokens of a compound ordinal phrase.
|
|
42
|
-
std::u32string inflect_ordinal(std::u32string_view word, PluralForm form) {
|
|
43
|
-
if (word.empty()) return std::u32string(word);
|
|
44
|
-
char32_t last = word.back();
|
|
45
|
-
std::u32string stem(word);
|
|
46
|
-
stem.pop_back();
|
|
47
|
-
|
|
48
|
-
if (last == U'y') {
|
|
49
|
-
if (form == PluralForm::SINGULAR) return stem + U"a";
|
|
50
|
-
if (form == PluralForm::FEW) return stem + U"e";
|
|
51
|
-
return stem + U"ych";
|
|
52
|
-
}
|
|
53
|
-
if (last == U'i') {
|
|
54
|
-
char32_t prev = stem.empty() ? U'\0' : stem.back();
|
|
55
|
-
bool velar = (prev == U'g' || prev == U'k');
|
|
56
|
-
if (form == PluralForm::SINGULAR) return stem + (velar ? U"a" : U"ia");
|
|
57
|
-
if (form == PluralForm::FEW) return stem + U"ie";
|
|
58
|
-
return stem + U"ich";
|
|
59
|
-
}
|
|
60
|
-
return std::u32string(word);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Builds the masculine-nominative ordinal phrase for `value`. Ordinals beyond
|
|
64
|
-
// 100 keep the upper magnitude as a cardinal phrase and only inflect the
|
|
65
|
-
// trailing sub-100 portion (e.g. 2026 -> "dwa tysiące dwudziesty szósty").
|
|
66
|
-
std::u32string ordinal_masc(int32_t value, const Num2Word& self) {
|
|
67
|
-
if (auto it = num2word::kOrdinals.find(value); it != num2word::kOrdinals.end()) {
|
|
68
|
-
return it->second;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (value < 100) {
|
|
72
|
-
int32_t tens = (value / 10) * 10;
|
|
73
|
-
int32_t units = value % 10;
|
|
74
|
-
return num2word::kOrdinals.at(tens) + U" " + num2word::kOrdinals.at(units);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (value < 1000) {
|
|
78
|
-
int32_t hundreds = (value / 100) * 100;
|
|
79
|
-
int32_t rest = value % 100;
|
|
80
|
-
if (rest == 0) {
|
|
81
|
-
// 200-900 lack dedicated ordinal entries; the cardinal form is the
|
|
82
|
-
// pragmatic fallback (the literal "dwusetny" family is rarely used).
|
|
83
|
-
return num2word::kCardinals.at(hundreds);
|
|
74
|
+
uint64_t r = n % 100;
|
|
75
|
+
std::vector<std::u32string> words;
|
|
76
|
+
for (uint64_t part : {n - r, r < 20 ? r : r - r % 10, r < 20 ? 0 : r % 10}) {
|
|
77
|
+
if (part == 1) {
|
|
78
|
+
words.push_back(U"jeden"); // Inside a compound number "jeden" does not inflect
|
|
79
|
+
} else if (part == 2 && g == Gender::FEMININE &&
|
|
80
|
+
(c == Case::NOMINATIVE || c == Case::ACCUSATIVE || c == Case::INSTRUMENTAL)) {
|
|
81
|
+
words.push_back(c == Case::INSTRUMENTAL ? U"dwiema" : U"dwie");
|
|
82
|
+
} else if (part) {
|
|
83
|
+
words.emplace_back(kCardinals.at(part)[column(c)]);
|
|
84
84
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
for (auto it = num2word::kLargeCardinals.rbegin(); it != num2word::kLargeCardinals.rend(); ++it) {
|
|
89
|
-
int64_t base = it->first;
|
|
90
|
-
if (static_cast<int64_t>(value) >= base) {
|
|
91
|
-
int32_t high = value / static_cast<int32_t>(base);
|
|
92
|
-
int32_t low = value % static_cast<int32_t>(base);
|
|
93
|
-
const auto& forms = it->second;
|
|
94
|
-
const auto& scale_word = forms[static_cast<std::size_t>(pick_plural_form(high))];
|
|
95
|
-
|
|
96
|
-
if (low == 0) {
|
|
97
|
-
// 1000 -> "tysięczny", 1000000 -> "milionowy" already in kOrdinals.
|
|
98
|
-
// For 2000+ we fall back to "<cardinal high> <scale word>" since
|
|
99
|
-
// round multiple ordinals ("dwutysięczny", ...) aren't tabulated.
|
|
100
|
-
return self.to_cardinal_int(high) + U" " + scale_word;
|
|
101
|
-
}
|
|
85
|
+
}
|
|
86
|
+
return join(words);
|
|
87
|
+
}
|
|
102
88
|
|
|
103
|
-
|
|
104
|
-
|
|
89
|
+
std::u32string cardinal(uint64_t n, Case c = Case::NOMINATIVE, Gender g = Gender::MASCULINE) {
|
|
90
|
+
if (n == 1) {
|
|
91
|
+
return std::u32string(kOne[static_cast<size_t>(g)][index(c)]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
std::vector<std::u32string> parts;
|
|
95
|
+
for (auto [scale, noun] : {std::pair{1000000000ULL, &kBillion}, {1000000ULL, &kMillion}, {1000ULL, &kThousand}}) {
|
|
96
|
+
uint64_t q = n / scale;
|
|
97
|
+
n %= scale;
|
|
98
|
+
if (q) {
|
|
99
|
+
parts.push_back(q == 1 ? form(*noun, q, c) : cardinal(q, c) + U" " + form(*noun, q, c));
|
|
105
100
|
}
|
|
106
101
|
}
|
|
102
|
+
if (n || parts.empty()) {
|
|
103
|
+
parts.push_back(below_thousand(n, c, g));
|
|
104
|
+
}
|
|
105
|
+
return join(parts);
|
|
106
|
+
}
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
// An ordinal stem with an adjective ending: drug + y -> drugi, trzec + a -> trzecia
|
|
109
|
+
std::u32string adjective(std::u32string_view stem, std::u32string_view ending) {
|
|
110
|
+
std::u32string e(ending);
|
|
111
|
+
if (stem.ends_with(U'g') || stem.ends_with(U'k')) {
|
|
112
|
+
e = e[0] == U'y' ? U"i" + e.substr(1) : e[0] == U'e' ? U"i" + e : e;
|
|
113
|
+
} else if (stem.ends_with(U'c')) {
|
|
114
|
+
e = e[0] == U'y' ? U"i" + e.substr(1) : U"i" + e;
|
|
115
|
+
}
|
|
116
|
+
return std::u32string(stem) + e;
|
|
109
117
|
}
|
|
110
118
|
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
std::
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
// The form of a number inside a compound: czterdziestopięcio(metrowe), stu(letni)
|
|
120
|
+
std::u32string combining(uint64_t n) {
|
|
121
|
+
uint64_t h = n - n % 100, r = n % 100;
|
|
122
|
+
if (h >= 1000) {
|
|
123
|
+
return cardinal(n);
|
|
124
|
+
}
|
|
125
|
+
std::u32string words(h ? kCombining.at(h) : U"");
|
|
126
|
+
if (r) {
|
|
127
|
+
words += r < 20 || r % 10 == 0 ? std::u32string(kCombining.at(r)) :
|
|
128
|
+
std::u32string(kCombining.at(r - r % 10)) + std::u32string(kCombining.at(r % 10));
|
|
129
|
+
}
|
|
130
|
+
return words;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Only the last two parts inflect: dwa tysiące dwudziestym drugim, tysiąc osiemsetnym
|
|
134
|
+
std::u32string ordinal(uint64_t n, Case c = Case::NOMINATIVE, Gender g = Gender::MASCULINE, bool plural = false) {
|
|
135
|
+
std::u32string_view e = kAdjectiveEndings[plural ? 3 : static_cast<size_t>(g)][index(c)];
|
|
136
|
+
|
|
137
|
+
uint64_t r = n % 100;
|
|
138
|
+
if (r) {
|
|
139
|
+
std::vector<std::u32string> words = {n - r ? cardinal(n - r) : U""};
|
|
140
|
+
if (r < 20 || r % 10 == 0) {
|
|
141
|
+
words.push_back(adjective(kOrdinalStems.at(r), e));
|
|
142
|
+
} else {
|
|
143
|
+
words.push_back(adjective(kOrdinalStems.at(r - r % 10), e));
|
|
144
|
+
words.push_back(adjective(kOrdinalStems.at(r % 10), e));
|
|
124
145
|
}
|
|
125
|
-
|
|
126
|
-
pos = next + 1;
|
|
146
|
+
return join(words);
|
|
127
147
|
}
|
|
128
148
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
boundary--;
|
|
149
|
+
uint64_t h = n % 1000;
|
|
150
|
+
if (h) {
|
|
151
|
+
std::vector<std::u32string> words = {n - h ? cardinal(n - h) : U"", adjective(kOrdinalStems.at(h), e)};
|
|
152
|
+
return join(words);
|
|
134
153
|
}
|
|
135
154
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
155
|
+
uint64_t t = n / 1000;
|
|
156
|
+
return adjective((t == 1 ? U"" : combining(t)) + U"tysięczn", e);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
std::u32string digits(std::u32string_view text) {
|
|
160
|
+
std::vector<std::u32string> words;
|
|
161
|
+
for (char32_t c : text) {
|
|
162
|
+
words.emplace_back(c == U'1' ? U"jeden" : kCardinals.at(c - U'0')[0]);
|
|
140
163
|
}
|
|
141
|
-
return
|
|
164
|
+
return join(words);
|
|
142
165
|
}
|
|
143
166
|
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
167
|
+
// -------------------
|
|
168
|
+
// ----- Context -----
|
|
169
|
+
// -------------------
|
|
170
|
+
|
|
171
|
+
// Inflection of a number: its form, case and gender
|
|
172
|
+
struct Features {
|
|
173
|
+
Form form = Form::CARDINAL;
|
|
174
|
+
Case grammatical_case = Case::NOMINATIVE;
|
|
175
|
+
Gender gender = Gender::MASCULINE;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// A noun's case, gender and number, guessed from its ending (as seen after an ordinal): sesji, sesję, roku
|
|
179
|
+
struct NounForm {
|
|
180
|
+
Case grammatical_case = Case::NOMINATIVE;
|
|
181
|
+
Gender gender = Gender::MASCULINE;
|
|
182
|
+
bool plural = false;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Whether a word is made only of given characters (and is not empty).
|
|
186
|
+
bool made_of(std::u32string_view word, std::u32string_view characters) {
|
|
187
|
+
return !word.empty() && std::ranges::all_of(word, [&](char32_t c) { return strings::contains(characters, c); });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
constexpr std::u32string_view kDigits = U"0123456789";
|
|
191
|
+
|
|
192
|
+
const std::unordered_set<std::u32string>& genitive_plurals() {
|
|
193
|
+
static const std::unordered_set<std::u32string> forms = [] {
|
|
194
|
+
std::unordered_set<std::u32string> result;
|
|
195
|
+
for (const auto* table : {&kUnits, &kCurrencies, &kScales}) {
|
|
196
|
+
for (const auto& [key, noun] : *table) {
|
|
197
|
+
result.insert(noun.plural[index(Case::GENITIVE)]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return result;
|
|
201
|
+
}();
|
|
202
|
+
return forms;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// A noun that a number counts: osób, metrów, złotych (as opposed to a verb, or nothing after a year)
|
|
206
|
+
bool counted(std::u32string_view word) {
|
|
207
|
+
std::u32string w(word);
|
|
208
|
+
return kCountNouns.contains(w) || genitive_plurals().contains(w) || word.ends_with(U"ów") || word.ends_with(U"ych") ||
|
|
209
|
+
word.ends_with(U"ich");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The words before a number within its clause (lowercased), and the first word after it, skipping a range
|
|
214
|
+
* or coordination it belongs to (20-30, 3 a 368) and the złote of an amount of grosze (39 532 złotych 20 groszy).
|
|
215
|
+
*/
|
|
216
|
+
std::pair<std::vector<std::u32string>, std::u32string> surroundings(const Context& context) {
|
|
217
|
+
std::u32string_view head = context.head();
|
|
218
|
+
size_t clause = 0;
|
|
219
|
+
for (size_t i = 0; i + 1 < head.size(); ++i) {
|
|
220
|
+
if (strings::contains(std::u32string_view(U",;:.!?"), head[i]) && unicode::isspace(head[i + 1])) {
|
|
221
|
+
clause = i + 1;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
std::vector<std::u32string> before;
|
|
226
|
+
for (auto word : words_of(head.substr(clause))) {
|
|
227
|
+
before.push_back(strings::to_lower(stripped(word)));
|
|
228
|
+
}
|
|
229
|
+
auto range_start = [](std::u32string_view w) {
|
|
230
|
+
return w.size() > 1 && unicode::isdigit(w[0]) && w.back() == U'-' &&
|
|
231
|
+
made_of(w.substr(0, w.size() - 1), U"0123456789,. ");
|
|
232
|
+
};
|
|
233
|
+
while (!before.empty() && range_start(before.back())) {
|
|
234
|
+
before.pop_back();
|
|
235
|
+
}
|
|
236
|
+
while (before.size() >= 2 && kConjunctions.contains(before.back()) &&
|
|
237
|
+
made_of(before[before.size() - 2], U"0123456789,.")) {
|
|
238
|
+
before.resize(before.size() - 2);
|
|
239
|
+
}
|
|
240
|
+
if (!before.empty() && kCurrencyWords.contains(before.back())) {
|
|
241
|
+
before.pop_back();
|
|
242
|
+
while (!before.empty() && made_of(before.back(), kDigits)) {
|
|
243
|
+
before.pop_back();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// The first word after, beyond the end of a range (-30)
|
|
248
|
+
std::u32string next;
|
|
249
|
+
std::u32string_view tail = context.tail();
|
|
250
|
+
if (tail.empty() || !strings::contains(processor::constants::kPunctuation, tail[0])) {
|
|
251
|
+
for (auto word : words_of(tail)) {
|
|
252
|
+
std::u32string_view w = stripped(word);
|
|
253
|
+
if (!(w.size() > 1 && w[0] == U'-' && made_of(w.substr(1), U"0123456789,."))) {
|
|
254
|
+
next = strings::to_lower(w);
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
154
258
|
}
|
|
259
|
+
return {before, next};
|
|
155
260
|
}
|
|
156
261
|
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
std::
|
|
160
|
-
|
|
161
|
-
|
|
262
|
+
// The context of the number this one continues after a comma (140 g mąki, 130 g mąki): both share a case.
|
|
263
|
+
std::optional<Context> enumerated(const Context& context) {
|
|
264
|
+
std::u32string_view head = context.head();
|
|
265
|
+
size_t end = head.find_last_not_of(U" \t\n\r");
|
|
266
|
+
if (end == std::u32string_view::npos || head[end] != U',') {
|
|
267
|
+
return std::nullopt;
|
|
162
268
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
269
|
+
|
|
270
|
+
// The last number before the comma, at most four words before it
|
|
271
|
+
std::u32string_view text = head.substr(0, end);
|
|
272
|
+
std::optional<Span> number;
|
|
273
|
+
for (size_t i = 0; i < text.size();) {
|
|
274
|
+
if (unicode::isdigit(text[i]) && is_clear_before(text, i, U".,")) {
|
|
275
|
+
number = Span{i, digits_end(text, i)};
|
|
276
|
+
i = number->end;
|
|
277
|
+
} else {
|
|
278
|
+
i++;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (!number || words_of(text.substr(number->end)).size() > 4) {
|
|
282
|
+
return std::nullopt;
|
|
283
|
+
}
|
|
284
|
+
return Context(text, *number);
|
|
166
285
|
}
|
|
167
286
|
|
|
168
|
-
|
|
287
|
+
// The case of a number governed by an amount noun, a genitive verb or a negation right before it.
|
|
288
|
+
std::optional<Case> governed(const std::vector<std::u32string>& before) {
|
|
289
|
+
std::u32string w1 = before.empty() ? U"" : before.back();
|
|
290
|
+
for (const auto& stem : kAmountNouns) {
|
|
291
|
+
if (w1.starts_with(stem) && kNounEndings.contains(std::u32string(w1.substr(stem.size())))) {
|
|
292
|
+
return Case::GENITIVE; // od kwoty trzystu tysięcy
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
std::vector<std::u32string> window(before.end() - std::min<size_t>(before.size(), 3), before.end());
|
|
297
|
+
std::vector<std::u32string> verbs;
|
|
298
|
+
std::ranges::copy_if(window, std::back_inserter(verbs), [](const auto& w) { return !kClitics.contains(w); });
|
|
299
|
+
if (!verbs.empty() && starts_with_any(verbs.back(), kGenitiveVerbs)) {
|
|
300
|
+
return Case::GENITIVE; // potrzebowali stu czterdziestu gramów, brakuje nam trzech osób
|
|
301
|
+
}
|
|
169
302
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
303
|
+
// nie powinno przekraczać pięciu gramów, but not: nie jest to pięć, nie więcej niż pięć
|
|
304
|
+
auto no = std::ranges::find(window, U"nie");
|
|
305
|
+
if (no != window.end() && std::none_of(no + 1, window.end(), [](const auto& w) {
|
|
306
|
+
return kCopulas.contains(w) || w == U"niż" || w == U"tylko";
|
|
307
|
+
})) {
|
|
308
|
+
return Case::GENITIVE;
|
|
173
309
|
}
|
|
310
|
+
return std::nullopt;
|
|
311
|
+
}
|
|
174
312
|
|
|
175
|
-
|
|
176
|
-
|
|
313
|
+
NounForm noun_form(std::u32string_view word, std::u32string_view preposition) {
|
|
314
|
+
bool locative = kLocativePrepositions.contains(std::u32string(preposition));
|
|
315
|
+
bool instrumental = preposition == U"z" || preposition == U"ze" || preposition == U"przed" || preposition == U"nad" ||
|
|
316
|
+
preposition == U"pod";
|
|
317
|
+
|
|
318
|
+
const std::vector<std::pair<std::u32string_view, NounForm>> endings = {
|
|
319
|
+
{U"ami", {Case::INSTRUMENTAL, Gender::MASCULINE, true}},
|
|
320
|
+
{U"ach", {Case::LOCATIVE, Gender::MASCULINE, true}},
|
|
321
|
+
{U"ych", {Case::GENITIVE, Gender::MASCULINE, true}},
|
|
322
|
+
{U"ów", {Case::GENITIVE, Gender::MASCULINE, true}},
|
|
323
|
+
{U"iem", {Case::INSTRUMENTAL, Gender::MASCULINE}},
|
|
324
|
+
{U"em", {Case::INSTRUMENTAL, Gender::MASCULINE}},
|
|
325
|
+
{U"ą", {instrumental ? Case::INSTRUMENTAL : Case::ACCUSATIVE, Gender::FEMININE}},
|
|
326
|
+
{U"ę", {Case::ACCUSATIVE, Gender::FEMININE}},
|
|
327
|
+
{U"a", {Case::NOMINATIVE, Gender::FEMININE}},
|
|
328
|
+
{U"i", {locative ? Case::LOCATIVE : Case::GENITIVE, Gender::FEMININE}},
|
|
329
|
+
{U"y", {locative ? Case::LOCATIVE : Case::GENITIVE, Gender::FEMININE}},
|
|
330
|
+
{U"u", {locative ? Case::LOCATIVE : Case::GENITIVE, Gender::MASCULINE}},
|
|
331
|
+
{U"ie", {Case::LOCATIVE, Gender::MASCULINE}},
|
|
332
|
+
{U"e", {Case::NOMINATIVE, Gender::NEUTER}},
|
|
333
|
+
{U"o", {Case::NOMINATIVE, Gender::NEUTER}}};
|
|
334
|
+
for (const auto& [ending, form] : endings) {
|
|
335
|
+
if (word.ends_with(ending)) {
|
|
336
|
+
return form;
|
|
337
|
+
}
|
|
177
338
|
}
|
|
339
|
+
return {};
|
|
340
|
+
}
|
|
178
341
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
342
|
+
// The form, case and gender of a number from its context: an ordinal for years, days and headings.
|
|
343
|
+
Features features(const Context& context, uint64_t n, bool decimal, bool year_abbreviation = false) {
|
|
344
|
+
auto [before, next] = surroundings(context);
|
|
345
|
+
std::u32string w1 = before.empty() ? U"" : before.back();
|
|
346
|
+
std::u32string w2 = before.size() < 2 ? U"" : before[before.size() - 2];
|
|
347
|
+
std::u32string noun = year_abbreviation ? U"roku" : next; // 2020 r.
|
|
348
|
+
|
|
349
|
+
// 1. Years, days and headings are ordinals
|
|
350
|
+
bool locative = kLocativePrepositions.contains(w1);
|
|
351
|
+
if (noun == U"roku" || noun == U"rok" || noun == U"rokiem") {
|
|
352
|
+
Case c = noun == U"rok" ? Case::NOMINATIVE :
|
|
353
|
+
noun == U"rokiem" ? Case::INSTRUMENTAL :
|
|
354
|
+
locative ? Case::LOCATIVE :
|
|
355
|
+
Case::GENITIVE;
|
|
356
|
+
return {Form::ORDINAL, c};
|
|
357
|
+
}
|
|
358
|
+
if (w1 == U"dnia") {
|
|
359
|
+
return {Form::ORDINAL, Case::GENITIVE}; // z dnia 1.
|
|
360
|
+
}
|
|
361
|
+
if (w1 == U"roku" || w1 == U"rok") {
|
|
362
|
+
bool w2_locative = kLocativePrepositions.contains(w2);
|
|
363
|
+
return {Form::ORDINAL, w1 == U"rok" ? Case::NOMINATIVE : w2_locative ? Case::LOCATIVE : Case::GENITIVE};
|
|
364
|
+
}
|
|
365
|
+
if (std::ranges::find(kMonthsGenitive, noun) != kMonthsGenitive.end() && n >= 1 && n <= 31) {
|
|
366
|
+
return {Form::ORDINAL, kCopulas.contains(w1) ? Case::NOMINATIVE : Case::GENITIVE}; // od pierwszego kwietnia
|
|
367
|
+
}
|
|
368
|
+
if (kMonths.contains(w1) && n >= 1000 && n <= 2100) {
|
|
369
|
+
return {Form::ORDINAL, Case::GENITIVE};
|
|
370
|
+
}
|
|
371
|
+
if ((w1 == U"w" || w1 == U"we") && n >= 1000 && n <= 2100 && !genitive_plurals().contains(noun)) {
|
|
372
|
+
return {Form::ORDINAL, Case::LOCATIVE};
|
|
373
|
+
}
|
|
374
|
+
if (auto it = kYearPrepositions.find(w1); it != kYearPrepositions.end() && n >= 1900 && n <= 2100 && !counted(noun)) {
|
|
375
|
+
return {Form::ORDINAL, it->second}; // od dwa tysiące dwudziestego do dwa tysiące dwudziestego drugiego
|
|
376
|
+
}
|
|
377
|
+
if (starts_with_any(w1, kOrdinalHeadings) && n < 100) {
|
|
378
|
+
return {Form::ORDINAL, noun_form(w1, w2).grammatical_case}; // w punkcie drugim
|
|
184
379
|
}
|
|
185
380
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
381
|
+
// 2. The case of a cardinal: from a preposition, a governing word or a number it continues
|
|
382
|
+
Features result;
|
|
383
|
+
if (auto it = kPrepositionCases.find(w1); it != kPrepositionCases.end()) {
|
|
384
|
+
result.grammatical_case = it->second;
|
|
385
|
+
} else if (auto it = kComplexPrepositions.find(w1); it != kComplexPrepositions.end() && it->second == w2) {
|
|
386
|
+
result.grammatical_case = Case::GENITIVE;
|
|
387
|
+
} else if (auto governing = decimal ? std::nullopt : governed(before)) {
|
|
388
|
+
result.grammatical_case = *governing;
|
|
389
|
+
} else if (auto earlier = enumerated(context)) {
|
|
390
|
+
result.grammatical_case = features(*earlier, 0, false).grammatical_case;
|
|
190
391
|
}
|
|
191
392
|
|
|
192
|
-
//
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
393
|
+
// 3. The noun after it, as it agrees with the number
|
|
394
|
+
bool few = n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14);
|
|
395
|
+
bool nominative = result.grammatical_case == Case::NOMINATIVE || result.grammatical_case == Case::ACCUSATIVE;
|
|
396
|
+
if ((noun.ends_with(U"ami") || noun.ends_with(U"mi")) && noun.size() > 4) {
|
|
397
|
+
result.grammatical_case = Case::INSTRUMENTAL;
|
|
398
|
+
} else if (noun.ends_with(U"ach") && noun.size() > 4) {
|
|
399
|
+
result.grammatical_case = Case::LOCATIVE;
|
|
400
|
+
} else if (nominative && few && counted(noun)) {
|
|
401
|
+
result.grammatical_case = Case::GENITIVE; // trzech osób: the noun is genitive, so the number is too
|
|
402
|
+
}
|
|
198
403
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
404
|
+
if ((noun.ends_with(U'a') && n == 1) || starts_with_any(noun, kFemininePlurals)) {
|
|
405
|
+
result.gender = Gender::FEMININE;
|
|
406
|
+
} else if (noun == U"euro") {
|
|
407
|
+
result.gender = Gender::NEUTER;
|
|
408
|
+
}
|
|
409
|
+
return result;
|
|
410
|
+
}
|
|
204
411
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
412
|
+
// The word governing a dot ordinal: the one before it, or before the first ordinal of "lat 50. i 60."
|
|
413
|
+
std::u32string ordinal_cue(const Context& context) {
|
|
414
|
+
std::u32string w1 = context.before();
|
|
415
|
+
auto head = words_of(context.head());
|
|
416
|
+
if (w1 != U"czy" && kConjunctions.contains(w1) && head.size() > 1) {
|
|
417
|
+
std::u32string_view previous = head[head.size() - 2];
|
|
418
|
+
if (previous.ends_with(U'.') && made_of(previous.substr(0, previous.size() - 1), kDigits)) {
|
|
419
|
+
return context.before(3);
|
|
210
420
|
}
|
|
211
421
|
}
|
|
422
|
+
return w1;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// The gender of a counted noun, for the number before it: dwie tony, dwa metry
|
|
426
|
+
Gender gender_of(const Noun& noun) {
|
|
427
|
+
const auto& nominative = noun.singular[index(Case::NOMINATIVE)];
|
|
428
|
+
return nominative.ends_with(U'a') ? Gender::FEMININE : nominative == U"euro" ? Gender::NEUTER : Gender::MASCULINE;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// A decimal number in a case: dwa przecinek pięć, półtora, dwa i pół
|
|
432
|
+
std::u32string decimal(const Number& number, Case c) {
|
|
433
|
+
// 801.04, 4.0: a dotted code rather than a decimal
|
|
434
|
+
if (number.decimal_mark == U'.' && (number.fraction.size() == 2 || number.fraction == U"0")) {
|
|
435
|
+
uint64_t f = value_of(number.fraction).value_or(0);
|
|
436
|
+
return cardinal(value(number)) + U" " + (number.fraction[0] == U'0' ? digits(number.fraction) : cardinal(f));
|
|
437
|
+
}
|
|
212
438
|
|
|
213
|
-
|
|
439
|
+
bool zero = !number.integer.empty(); // .5 has no zero before its point
|
|
440
|
+
if (number.integer == U"1" && number.fraction == U"5") {
|
|
441
|
+
return U"półtora";
|
|
442
|
+
}
|
|
443
|
+
std::u32string head = zero ? cardinal(value(number), c) + U" " : U"";
|
|
444
|
+
if (number.fraction == U"5") {
|
|
445
|
+
return head + U"i pół";
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
std::vector<std::u32string> words = {U"przecinek"};
|
|
449
|
+
size_t zeros = number.fraction.find_first_not_of(U'0');
|
|
450
|
+
words.insert(words.end(), std::min(zeros, number.fraction.size()), U"zero");
|
|
451
|
+
if (zeros != std::u32string::npos) {
|
|
452
|
+
words.push_back(cardinal(value_of(number.fraction).value_or(0), c));
|
|
453
|
+
}
|
|
454
|
+
return head + join(words);
|
|
214
455
|
}
|
|
215
456
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
457
|
+
// A number counting a noun, both in a case: pięćset dwadzieścia cztery kilometry
|
|
458
|
+
std::u32string amount(const Number& number, const Noun& noun, Case c) {
|
|
459
|
+
std::u32string words;
|
|
460
|
+
if (!number.fraction.empty()) {
|
|
461
|
+
words = decimal(number, c);
|
|
462
|
+
} else {
|
|
463
|
+
auto n = value_of(number.integer);
|
|
464
|
+
words = !n || spoken_digits(number, 7) ? digits(number.integer) : cardinal(*n, c, gender_of(noun));
|
|
465
|
+
}
|
|
466
|
+
return words + U" " + form(noun, value(number), c, !number.fraction.empty());
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
bool is_zloty(std::u32string_view currency) {
|
|
470
|
+
return currency == U"zł" || currency == U"PLN";
|
|
471
|
+
}
|
|
472
|
+
} // namespace
|
|
473
|
+
|
|
474
|
+
Num2Word::Num2Word() : Num2WordLayer(kNotation, kJoiners) {
|
|
475
|
+
add_pattern(std::make_unique<DatePattern>(kDateFormat));
|
|
476
|
+
for (const auto& format : kPhoneFormats) {
|
|
477
|
+
add_pattern(std::make_unique<PhonePattern>(format));
|
|
478
|
+
}
|
|
479
|
+
add_pattern(std::make_unique<DotOrdinalPattern>(true, true));
|
|
480
|
+
add_pattern(std::make_unique<SuffixPattern>(Kind::NUMBER, kYearSuffixes, kYearFormat));
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// -----------------------
|
|
484
|
+
// ----- Resolution -----
|
|
485
|
+
// -----------------------
|
|
486
|
+
|
|
487
|
+
bool Num2Word::accept(const Match& match, const Context& context) const {
|
|
488
|
+
switch (match.kind) {
|
|
489
|
+
case Kind::PHONE:
|
|
490
|
+
// 600 123 456 is a count, unless a word says it is a phone number
|
|
491
|
+
return match.separator != U' ' || kPhoneWords.contains(context.before());
|
|
492
|
+
case Kind::TIME: {
|
|
493
|
+
const auto& minutes = match.numbers[1].integer;
|
|
494
|
+
bool round = minutes == U"00" || minutes == U"15" || minutes == U"30" || minutes == U"45";
|
|
495
|
+
bool decimal = match.separator == U'.' && !round && !kTimeWords.contains(context.before());
|
|
496
|
+
return value(match.numbers[0]) <= 24 && value(match.numbers[1]) <= 59 && !decimal;
|
|
497
|
+
}
|
|
498
|
+
case Kind::ORDINAL: {
|
|
499
|
+
// An ordinal agrees with the noun after it: "29. sesji", but "Punkt 3. Dalej" ends a sentence
|
|
500
|
+
std::u32string w1 = ordinal_cue(context);
|
|
501
|
+
auto words = words_of(context.tail());
|
|
502
|
+
std::u32string_view next = words.empty() ? U"" : stripped(words[0]);
|
|
503
|
+
bool heading = starts_with_any(w1, kHeadings) && value(match.numbers[0]) < 100;
|
|
504
|
+
return kDecadeWords.contains(w1) || heading || (!next.empty() && unicode::islower(next[0]));
|
|
505
|
+
}
|
|
506
|
+
default:
|
|
507
|
+
return true;
|
|
219
508
|
}
|
|
509
|
+
}
|
|
220
510
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
511
|
+
NumberReading Num2Word::resolve(const Match& match, const Context& context) const {
|
|
512
|
+
NumberReading reading;
|
|
513
|
+
|
|
514
|
+
switch (match.kind) {
|
|
515
|
+
case Kind::DATE:
|
|
516
|
+
reading.grammatical_case = kCopulas.contains(context.before()) ? Case::NOMINATIVE : Case::GENITIVE;
|
|
517
|
+
return reading;
|
|
518
|
+
|
|
519
|
+
case Kind::TIME: {
|
|
520
|
+
// o osiemnastej trzydzieści: the hour is a feminine ordinal (godzina) in the case of the word before
|
|
521
|
+
std::u32string w1 = context.before();
|
|
522
|
+
reading.grammatical_case = w1 == U"o" || w1 == U"godzinie" || w1 == U"po" ? Case::LOCATIVE :
|
|
523
|
+
w1 == U"do" || w1 == U"od" || w1 == U"około" || w1 == U"koło" ? Case::GENITIVE :
|
|
524
|
+
w1 == U"przed" || w1 == U"między" ? Case::INSTRUMENTAL :
|
|
525
|
+
w1 == U"na" || w1 == U"za" ? Case::ACCUSATIVE :
|
|
526
|
+
Case::NOMINATIVE;
|
|
527
|
+
return reading;
|
|
528
|
+
}
|
|
225
529
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
530
|
+
case Kind::ORDINAL: {
|
|
531
|
+
// "29. sesji": an ordinal agreeing with the noun after it, the decade of "lat 70.", or a heading
|
|
532
|
+
reading.form = Form::ORDINAL;
|
|
533
|
+
std::u32string w1 = ordinal_cue(context);
|
|
534
|
+
if (auto it = kDecadeWords.find(w1); it != kDecadeWords.end()) {
|
|
535
|
+
reading.grammatical_case = it->second;
|
|
536
|
+
reading.plural = true;
|
|
537
|
+
} else if (starts_with_any(w1, kHeadings) && value(match.numbers[0]) < 100) {
|
|
538
|
+
reading.grammatical_case = noun_form(w1, context.before(2)).grammatical_case; // Punkt 3., w punkcie 5.
|
|
539
|
+
} else {
|
|
540
|
+
auto words = words_of(context.tail());
|
|
541
|
+
NounForm next = noun_form(words.empty() ? U"" : strings::to_lower(stripped(words[0])), w1);
|
|
542
|
+
reading.grammatical_case = next.grammatical_case;
|
|
543
|
+
reading.gender = next.gender;
|
|
544
|
+
reading.plural = next.plural;
|
|
545
|
+
}
|
|
546
|
+
return reading;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
case Kind::DIMENSION: {
|
|
550
|
+
// numerem 3x38: a document number, where "x" stands for a slash
|
|
551
|
+
std::u32string_view head = context.head();
|
|
552
|
+
size_t digits = head.size();
|
|
553
|
+
while (digits > 0 && unicode::isdigit(head[digits - 1])) {
|
|
554
|
+
digits--;
|
|
555
|
+
}
|
|
556
|
+
size_t word_end = digits;
|
|
557
|
+
while (word_end > 0 && unicode::isspace(head[word_end - 1])) {
|
|
558
|
+
word_end--;
|
|
559
|
+
}
|
|
560
|
+
size_t word_begin = word_end;
|
|
561
|
+
while (word_begin > 0 && unicode::isword(head[word_begin - 1])) {
|
|
562
|
+
word_begin--;
|
|
563
|
+
}
|
|
564
|
+
std::u32string_view word = head.substr(word_begin, word_end - word_begin);
|
|
565
|
+
reading.numbered = digits < head.size() && word_end < digits && (word.starts_with(U"numer") || word == U"nr");
|
|
566
|
+
return reading;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
default:
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// A number: its own inflection (the start of a range for amounts), and the case of what it counts
|
|
574
|
+
if (!match.numbers.empty()) {
|
|
575
|
+
const Number& first = match.numbers.front();
|
|
576
|
+
bool year_abbreviation = match.suffix == U"r.";
|
|
577
|
+
Features own = first.fraction.empty() ? features(context, value(first), false, year_abbreviation) :
|
|
578
|
+
features(context, 0, true, year_abbreviation);
|
|
579
|
+
reading.form = own.form;
|
|
580
|
+
reading.grammatical_case = own.grammatical_case;
|
|
581
|
+
reading.gender = own.gender;
|
|
582
|
+
|
|
583
|
+
const Number& last = match.numbers.back();
|
|
584
|
+
bool grosze = match.kind == Kind::MONEY && match.scale.empty() && last.fraction.size() == 2 && is_zloty(match.unit);
|
|
585
|
+
reading.amount_case = features(context, 0, !last.fraction.empty() && !grosze).grammatical_case;
|
|
232
586
|
}
|
|
587
|
+
return reading;
|
|
588
|
+
}
|
|
233
589
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
590
|
+
// --------------------
|
|
591
|
+
// ----- Readings -----
|
|
592
|
+
// --------------------
|
|
593
|
+
|
|
594
|
+
std::u32string Num2Word::read_number(const Number& number, const NumberReading& reading) const {
|
|
595
|
+
if (!number.fraction.empty()) {
|
|
596
|
+
return decimal(number, reading.grammatical_case);
|
|
237
597
|
}
|
|
238
598
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
599
|
+
auto n = value_of(number.integer);
|
|
600
|
+
if (!n || spoken_digits(number, 7)) {
|
|
601
|
+
return digits(number.integer);
|
|
602
|
+
}
|
|
603
|
+
if (reading.form == Form::ORDINAL) {
|
|
604
|
+
return ordinal(*n, reading.grammatical_case, reading.gender);
|
|
605
|
+
}
|
|
606
|
+
return cardinal(*n, reading.grammatical_case, reading.gender);
|
|
607
|
+
}
|
|
242
608
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
size_t pos = 0;
|
|
248
|
-
while (pos < fractional_part_str.size() && fractional_part_str[pos] == '0') {
|
|
249
|
-
if (!frac_words.empty()) frac_words += U" ";
|
|
250
|
-
frac_words += U"zero";
|
|
251
|
-
pos++;
|
|
609
|
+
std::u32string Num2Word::read_code_digits(std::u32string_view text) const {
|
|
610
|
+
auto n = value_of(text);
|
|
611
|
+
if ((text.size() > 1 && text[0] == U'0') || text.size() >= 7 || !n) {
|
|
612
|
+
return digits(text);
|
|
252
613
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
614
|
+
return cardinal(*n);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
std::u32string Num2Word::read_date(const Match& match, const NumberReading& reading) const {
|
|
618
|
+
std::vector<std::u32string> words = {ordinal(value(match.numbers[0]), reading.grammatical_case),
|
|
619
|
+
std::u32string(kMonthsGenitive[value(match.numbers[1]) - 1]),
|
|
620
|
+
ordinal(value(match.numbers[2]), Case::GENITIVE)};
|
|
621
|
+
if (!match.suffix.empty()) {
|
|
622
|
+
words.push_back(U"roku");
|
|
256
623
|
}
|
|
624
|
+
return join(words);
|
|
625
|
+
}
|
|
257
626
|
|
|
258
|
-
|
|
627
|
+
std::u32string Num2Word::read_phone(const Match& match, const NumberReading& reading) const {
|
|
628
|
+
std::vector<std::u32string> words;
|
|
629
|
+
// In groups: sześćset sto dwadzieścia trzy; a longer one digit by digit
|
|
630
|
+
for (const auto& group : match.numbers) {
|
|
631
|
+
words.push_back(group.integer.size() > 3 ? digits(group.integer) : cardinal(value(group)));
|
|
632
|
+
}
|
|
633
|
+
return join(words);
|
|
259
634
|
}
|
|
260
635
|
|
|
261
|
-
std::u32string Num2Word::
|
|
262
|
-
std::u32string
|
|
263
|
-
|
|
264
|
-
|
|
636
|
+
std::u32string Num2Word::read_time(const Match& match, const NumberReading& reading) const {
|
|
637
|
+
std::u32string hours = ordinal(value(match.numbers[0]), reading.grammatical_case, Gender::FEMININE);
|
|
638
|
+
const auto& minutes = match.numbers[1].integer;
|
|
639
|
+
if (value(match.numbers[1]) == 0) {
|
|
640
|
+
return hours;
|
|
265
641
|
}
|
|
266
|
-
return
|
|
642
|
+
return hours + U" " + (minutes[0] == U'0' ? digits(minutes) : cardinal(value(match.numbers[1])));
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
std::u32string Num2Word::read_ordinal(const Match& match, const NumberReading& reading) const {
|
|
646
|
+
return ordinal(value(match.numbers[0]), reading.grammatical_case, reading.gender, reading.plural);
|
|
267
647
|
}
|
|
268
648
|
|
|
269
|
-
std::u32string Num2Word::
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
return std::u32string(
|
|
649
|
+
std::u32string Num2Word::read_compound(const Match& match, const NumberReading& reading) const {
|
|
650
|
+
const Number& number = match.numbers[0];
|
|
651
|
+
if (!number.fraction.empty()) {
|
|
652
|
+
return read_number(number, reading) + U"-" + std::u32string(match.suffix);
|
|
273
653
|
}
|
|
274
654
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
655
|
+
// lat 70-tych: siedemdziesiątych - the first gender and case taking the ending of the suffix
|
|
656
|
+
if (auto it = kOrdinalSuffixes.find(std::u32string(match.suffix)); it != kOrdinalSuffixes.end()) {
|
|
657
|
+
for (size_t g = 0; g < kAdjectiveEndings.size(); ++g) {
|
|
658
|
+
for (size_t c = 0; c < kAdjectiveEndings[g].size(); ++c) {
|
|
659
|
+
if (kAdjectiveEndings[g][c] == it->second) {
|
|
660
|
+
Gender gender = g == 3 ? Gender::MASCULINE : static_cast<Gender>(g);
|
|
661
|
+
return ordinal(value(number), static_cast<Case>(c), gender, g == 3);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
284
664
|
}
|
|
285
|
-
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// 45-metrowe: czterdziestopięciometrowe
|
|
668
|
+
return combining(value(number)) + std::u32string(match.suffix);
|
|
669
|
+
}
|
|
286
670
|
|
|
287
|
-
|
|
671
|
+
std::u32string Num2Word::read_plain(const Match& match, const NumberReading& reading) const {
|
|
672
|
+
return read_number(match.numbers[0], reading) + (match.suffix == U"r." ? U" roku" : U"");
|
|
288
673
|
}
|
|
289
674
|
|
|
290
|
-
std::u32string Num2Word::
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
else if (numerator == 2) num_word = U"dwie";
|
|
297
|
-
else num_word = to_cardinal_int(numerator);
|
|
675
|
+
std::u32string Num2Word::read_money(const Number& number, const Match& match, const NumberReading& reading) const {
|
|
676
|
+
const Noun& currency = kCurrencies.at(std::u32string(match.unit));
|
|
677
|
+
Case c = reading.amount_case;
|
|
678
|
+
if (!match.scale.empty()) {
|
|
679
|
+
return amount(number, kScales.at(std::u32string(match.scale)), c) + U" " + currency.plural[index(Case::GENITIVE)];
|
|
680
|
+
}
|
|
298
681
|
|
|
299
|
-
|
|
300
|
-
|
|
682
|
+
// dwanaście złotych dziewięćdziesiąt dziewięć groszy
|
|
683
|
+
if (number.fraction.size() == 2 && is_zloty(match.unit)) {
|
|
684
|
+
uint64_t grosze = value_of(number.fraction).value_or(0);
|
|
685
|
+
Number zlote{.integer = number.integer, .grouped = number.grouped};
|
|
686
|
+
return amount(zlote, currency, c) + U" " + cardinal(grosze, c) + U" " + form(kGrosz, grosze, c);
|
|
687
|
+
}
|
|
688
|
+
return amount(number, currency, c);
|
|
301
689
|
}
|
|
302
690
|
|
|
303
|
-
std::u32string Num2Word::
|
|
304
|
-
|
|
305
|
-
return ordinal_gen(static_cast<int32_t>(day));
|
|
691
|
+
std::u32string Num2Word::read_scale(const Number& number, const Match& match, const NumberReading& reading) const {
|
|
692
|
+
return amount(number, kScales.at(std::u32string(match.scale)), reading.amount_case);
|
|
306
693
|
}
|
|
307
694
|
|
|
308
|
-
std::u32string Num2Word::
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
return U"";
|
|
695
|
+
std::u32string Num2Word::read_percent(const Number& number, const Match& match, const NumberReading& reading) const {
|
|
696
|
+
std::u32string suffix = match.suffix.empty() ? U"" : U" " + std::u32string(match.suffix);
|
|
697
|
+
return amount(number, kPercent, reading.amount_case) + suffix;
|
|
313
698
|
}
|
|
314
699
|
|
|
315
|
-
std::u32string Num2Word::
|
|
316
|
-
|
|
317
|
-
// dwadzieścia sześć"). The fully-inflected form ("dwa tysiące dwudziestego
|
|
318
|
-
// szóstego roku") is reserved for formal contexts and not produced here.
|
|
319
|
-
return to_cardinal_int(static_cast<int32_t>(year));
|
|
700
|
+
std::u32string Num2Word::read_unit(const Number& number, const Match& match, const NumberReading& reading) const {
|
|
701
|
+
return amount(number, kUnits.at(std::u32string(match.unit)), reading.amount_case);
|
|
320
702
|
}
|
|
321
703
|
|
|
322
|
-
|
|
323
|
-
|
|
704
|
+
std::u32string Num2Word::read_joiner(const Match& match, const NumberReading& reading) const {
|
|
705
|
+
if (match.kind == Kind::DIMENSION) {
|
|
706
|
+
return reading.numbered ? U" przez " : U" na ";
|
|
707
|
+
}
|
|
708
|
+
return Num2WordLayer::read_joiner(match, reading);
|
|
324
709
|
}
|
|
325
710
|
|
|
326
711
|
} // namespace phonemis::pl
|