├── .github ├── dependabot.yml └── workflows │ ├── ci-version.yml │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── rustfmt.toml ├── src ├── chinese_case.rs ├── chinese_characters.rs ├── chinese_count_method.rs ├── chinese_to_number │ ├── chinese_to_number_error.rs │ ├── functions.rs │ ├── functions_test.rs │ ├── mod.rs │ ├── naive.rs │ └── traits.rs ├── lib.rs └── number_to_chinese │ ├── functions.rs │ ├── functions_test.rs │ ├── mod.rs │ ├── naive.rs │ ├── number_to_chinese_error.rs │ └── traits.rs └── tests ├── chinese_to_number.rs ├── number_to_chinese.rs └── self.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" -------------------------------------------------------------------------------- /.github/workflows/ci-version.yml: -------------------------------------------------------------------------------- 1 | name: CI-version 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | tests: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | os: 17 | - ubuntu-latest 18 | - macos-latest 19 | - windows-latest 20 | toolchain: 21 | - stable 22 | - nightly 23 | features: 24 | - 25 | - --no-default-features --features chinese-to-number 26 | - --no-default-features --features number-to-chinese 27 | - --no-default-features --features chinese-to-number --features number-to-chinese 28 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 29 | runs-on: ${{ matrix.os }} 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: actions-rust-lang/setup-rust-toolchain@v1 33 | with: 34 | toolchain: ${{ matrix.toolchain }} 35 | - run: cargo test --release ${{ matrix.features }} 36 | - run: cargo doc --release ${{ matrix.features }} 37 | 38 | MSRV: 39 | strategy: 40 | fail-fast: false 41 | matrix: 42 | os: 43 | - ubuntu-latest 44 | - macos-latest 45 | - windows-latest 46 | toolchain: 47 | - "1.60" 48 | features: 49 | - 50 | - --no-default-features --features chinese-to-number 51 | - --no-default-features --features number-to-chinese 52 | - --no-default-features --features chinese-to-number --features number-to-chinese 53 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 54 | runs-on: ${{ matrix.os }} 55 | steps: 56 | - uses: actions/checkout@v4 57 | - uses: actions-rust-lang/setup-rust-toolchain@v1 58 | with: 59 | toolchain: ${{ matrix.toolchain }} 60 | - run: cargo test --release --lib --bins ${{ matrix.features }} -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | 8 | jobs: 9 | rustfmt: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions-rust-lang/setup-rust-toolchain@v1 14 | with: 15 | toolchain: nightly 16 | components: rustfmt 17 | - uses: actions-rust-lang/rustfmt@v1 18 | 19 | clippy: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: actions-rust-lang/setup-rust-toolchain@v1 24 | with: 25 | components: clippy 26 | - run: cargo clippy --all-targets --all-features -- -D warnings 27 | 28 | tests: 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | os: 33 | - ubuntu-latest 34 | - macos-latest 35 | - windows-latest 36 | toolchain: 37 | - stable 38 | - nightly 39 | features: 40 | - 41 | - --no-default-features --features chinese-to-number 42 | - --no-default-features --features number-to-chinese 43 | - --no-default-features --features chinese-to-number --features number-to-chinese 44 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 45 | runs-on: ${{ matrix.os }} 46 | steps: 47 | - uses: actions/checkout@v4 48 | - uses: actions-rust-lang/setup-rust-toolchain@v1 49 | with: 50 | toolchain: ${{ matrix.toolchain }} 51 | - run: cargo test ${{ matrix.features }} 52 | - run: cargo doc ${{ matrix.features }} 53 | 54 | MSRV: 55 | strategy: 56 | fail-fast: false 57 | matrix: 58 | os: 59 | - ubuntu-latest 60 | - macos-latest 61 | - windows-latest 62 | toolchain: 63 | - "1.60" 64 | features: 65 | - 66 | - --no-default-features --features chinese-to-number 67 | - --no-default-features --features number-to-chinese 68 | - --no-default-features --features chinese-to-number --features number-to-chinese 69 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 70 | runs-on: ${{ matrix.os }} 71 | steps: 72 | - uses: actions/checkout@v4 73 | - uses: actions-rust-lang/setup-rust-toolchain@v1 74 | with: 75 | toolchain: ${{ matrix.toolchain }} 76 | - run: cargo test --lib --bins ${{ matrix.features }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Intellij+all ### 2 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 3 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 4 | 5 | # User-specific stuff 6 | .idea/**/workspace.xml 7 | .idea/**/tasks.xml 8 | .idea/**/usage.statistics.xml 9 | .idea/**/dictionaries 10 | .idea/**/shelf 11 | 12 | # AWS User-specific 13 | .idea/**/aws.xml 14 | 15 | # Generated files 16 | .idea/**/contentModel.xml 17 | 18 | # Sensitive or high-churn files 19 | .idea/**/dataSources/ 20 | .idea/**/dataSources.ids 21 | .idea/**/dataSources.local.xml 22 | .idea/**/sqlDataSources.xml 23 | .idea/**/dynamic.xml 24 | .idea/**/uiDesigner.xml 25 | .idea/**/dbnavigator.xml 26 | 27 | # Gradle 28 | .idea/**/gradle.xml 29 | .idea/**/libraries 30 | 31 | # Gradle and Maven with auto-import 32 | # When using Gradle or Maven with auto-import, you should exclude module files, 33 | # since they will be recreated, and may cause churn. Uncomment if using 34 | # auto-import. 35 | # .idea/artifacts 36 | # .idea/compiler.xml 37 | # .idea/jarRepositories.xml 38 | # .idea/modules.xml 39 | # .idea/*.iml 40 | # .idea/modules 41 | # *.iml 42 | # *.ipr 43 | 44 | # CMake 45 | cmake-build-*/ 46 | 47 | # Mongo Explorer plugin 48 | .idea/**/mongoSettings.xml 49 | 50 | # File-based project format 51 | *.iws 52 | 53 | # IntelliJ 54 | out/ 55 | 56 | # mpeltonen/sbt-idea plugin 57 | .idea_modules/ 58 | 59 | # JIRA plugin 60 | atlassian-ide-plugin.xml 61 | 62 | # Cursive Clojure plugin 63 | .idea/replstate.xml 64 | 65 | # SonarLint plugin 66 | .idea/sonarlint/ 67 | 68 | # Crashlytics plugin (for Android Studio and IntelliJ) 69 | com_crashlytics_export_strings.xml 70 | crashlytics.properties 71 | crashlytics-build.properties 72 | fabric.properties 73 | 74 | # Editor-based Rest Client 75 | .idea/httpRequests 76 | 77 | # Android studio 3.1+ serialized cache file 78 | .idea/caches/build_file_checksums.ser 79 | 80 | ### Intellij+all Patch ### 81 | # Ignore everything but code style settings and run configurations 82 | # that are supposed to be shared within teams. 83 | 84 | .idea/* 85 | 86 | !.idea/codeStyles 87 | !.idea/runConfigurations 88 | 89 | ### Rust ### 90 | # Generated by Cargo 91 | # will have compiled files and executables 92 | debug/ 93 | target/ 94 | 95 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 96 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 97 | Cargo.lock 98 | 99 | # These are backup files generated by rustfmt 100 | **/*.rs.bk 101 | 102 | # MSVC Windows builds of rustc generate these, which store debugging information 103 | *.pdb 104 | 105 | ### Vim ### 106 | # Swap 107 | [._]*.s[a-v][a-z] 108 | !*.svg # comment out if you don't need vector files 109 | [._]*.sw[a-p] 110 | [._]s[a-rt-v][a-z] 111 | [._]ss[a-gi-z] 112 | [._]sw[a-p] 113 | 114 | # Session 115 | Session.vim 116 | Sessionx.vim 117 | 118 | # Temporary 119 | .netrwhist 120 | *~ 121 | # Auto-generated tag files 122 | tags 123 | # Persistent undo 124 | [._]*.un~ 125 | 126 | ### VisualStudioCode ### 127 | .vscode/* 128 | !.vscode/settings.json 129 | !.vscode/tasks.json 130 | !.vscode/launch.json 131 | !.vscode/extensions.json 132 | !.vscode/*.code-snippets 133 | 134 | # Local History for Visual Studio Code 135 | .history/ 136 | 137 | # Built Visual Studio Code Extensions 138 | *.vsix 139 | 140 | ### VisualStudioCode Patch ### 141 | # Ignore all local history of files 142 | .history 143 | .ionide -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chinese-number" 3 | version = "0.7.7" 4 | authors = ["Magic Len "] 5 | edition = "2021" 6 | rust-version = "1.60" 7 | repository = "https://github.com/magiclen/chinese-number" 8 | homepage = "https://magiclen.org/chinese-number" 9 | keywords = ["chinese", "number", "integer", "money", "float"] 10 | categories = ["no-std", "localization", "parser-implementations", "value-formatting"] 11 | description = "Convert primitive numbers to Chinese numbers, or parse Chinese numbers to primitive numbers." 12 | license = "MIT" 13 | include = ["src/**/*", "Cargo.toml", "README.md", "LICENSE"] 14 | 15 | [dependencies] 16 | chinese-variant = "1" 17 | enum-ordinalize = "4.2" 18 | 19 | num-bigint = { version = "0.4", default-features = false, optional = true } 20 | num-traits = { version = "0.2", default-features = false, optional = true } 21 | 22 | [dev-dependencies] 23 | assert-eq-float = "0.1" 24 | 25 | [features] 26 | default = ["std", "number-to-chinese", "chinese-to-number"] 27 | 28 | std = [] 29 | number-to-chinese = ["num-bigint", "num-traits"] 30 | chinese-to-number = ["num-traits"] 31 | 32 | [package.metadata.docs.rs] 33 | all-features = true 34 | rustdoc-args = ["--cfg", "docsrs"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 magiclen.org (Ron Li) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Chinese Number 2 | ==================== 3 | 4 | [![CI](https://github.com/magiclen/chinese-number/actions/workflows/ci.yml/badge.svg)](https://github.com/magiclen/chinese-number/actions/workflows/ci.yml) 5 | 6 | Convert primitive numbers to Chinese numbers, or parse Chinese numbers to primitive numbers. 7 | 8 | This crate can convert Rust's primitive number data types to Chinese numbers as strings. For example, **123** can be converted into **一二三**, **一百二十三** or **壹佰貳拾參**. It supports both Traditional Chinese and Simple Chinese, and it supports different methods to count the scale as well. Also, Chinese numbers in strings can be parsed to primitive number data types. 9 | 10 | ## Example 11 | 12 | ```rust 13 | use chinese_number::{ChineseCase, ChineseCountMethod, ChineseVariant, NumberToChinese, ChineseToNumber}; 14 | 15 | assert_eq!("一二三", 123i8.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower)); 16 | 17 | assert_eq!("壹佰貳拾參", 123i8.to_chinese(ChineseVariant::Traditional, ChineseCase::Upper, ChineseCountMethod::TenThousand).unwrap()); 18 | assert_eq!("壹佰贰拾叁", 123i8.to_chinese(ChineseVariant::Simple, ChineseCase::Upper, ChineseCountMethod::TenThousand).unwrap()); 19 | 20 | assert_eq!("一百二十三", 123i8.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::TenThousand).unwrap()); 21 | 22 | assert_eq!("一極二載三正四澗五溝六穰七秭八垓九京零一億二萬三千四百五十六", 1234567890123456i64.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::Low).unwrap()); 23 | assert_eq!("十二穰三千四百五十六秭七千八百九十垓一千二百三十四京五千六百七十八兆九千零一十二億三千四百五十六萬七千八百九十", 123456789012345678901234567890i128.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::TenThousand).unwrap()); 24 | assert_eq!("十二萬三千四百五十六京七千八百九十萬一千二百三十四兆五千六百七十八萬九千零一十二億三千四百五十六萬七千八百九十", 123456789012345678901234567890i128.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::Middle).unwrap()); 25 | assert_eq!("十二萬三千四百五十六億七千八百九十萬一千二百三十四兆五千六百七十八萬九千零一十二億三千四百五十六萬七千八百九十", 123456789012345678901234567890i128.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::High).unwrap()); 26 | 27 | assert_eq!("一角二分", 0.12f64.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::TenThousand).unwrap()); 28 | 29 | assert_eq!(123i8, "一二三".to_number_naive().unwrap()); 30 | 31 | assert_eq!(123i8, "一百二十三".to_number(ChineseCountMethod::TenThousand).unwrap()); 32 | assert_eq!(-30303i16, "負三萬零三百零三".to_number(ChineseCountMethod::TenThousand).unwrap()); 33 | assert_eq!(3212345678u32, "三十二億一千二百三十四萬五千六百七十八".to_number(ChineseCountMethod::TenThousand).unwrap()); 34 | assert_eq!(10010001001001001000u64, "一千零一京零一兆零一十億零一百萬一千".to_number(ChineseCountMethod::TenThousand).unwrap()); 35 | 36 | assert_eq!(1000000u64, "一兆".to_number(ChineseCountMethod::Low).unwrap()); 37 | assert_eq!(1000000000000u64, "一兆".to_number(ChineseCountMethod::TenThousand).unwrap()); 38 | assert_eq!(10000000000000000u64, "一兆".to_number(ChineseCountMethod::Middle).unwrap()); 39 | assert_eq!(10000000000000000u64, "一兆".to_number(ChineseCountMethod::High).unwrap()); 40 | 41 | assert_eq!(120u64, "一百二".to_number(ChineseCountMethod::TenThousand).unwrap()); 42 | assert_eq!(2300u64, "兩千三".to_number(ChineseCountMethod::TenThousand).unwrap()); 43 | assert_eq!(34000u64, "三萬四".to_number(ChineseCountMethod::TenThousand).unwrap()); 44 | assert_eq!(105000u64, "十萬五".to_number(ChineseCountMethod::TenThousand).unwrap()); 45 | assert_eq!(150000000u64, "一億五".to_number(ChineseCountMethod::TenThousand).unwrap()); 46 | ``` 47 | 48 | ## No Std 49 | 50 | Disable the default features to compile this crate without std. 51 | 52 | ```toml 53 | [dependencies.chinese-number] 54 | version = "*" 55 | default-features = false 56 | features = ["number-to-chinese", "chinese-to-number"] 57 | ``` 58 | 59 | ## Crates.io 60 | 61 | https://crates.io/crates/chinese-number 62 | 63 | ## Documentation 64 | 65 | https://docs.rs/chinese-number 66 | 67 | ## License 68 | 69 | [MIT](LICENSE) -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # array_width = 60 2 | # attr_fn_like_width = 70 3 | binop_separator = "Front" 4 | blank_lines_lower_bound = 0 5 | blank_lines_upper_bound = 1 6 | brace_style = "PreferSameLine" 7 | # chain_width = 60 8 | color = "Auto" 9 | # comment_width = 100 10 | condense_wildcard_suffixes = true 11 | control_brace_style = "AlwaysSameLine" 12 | empty_item_single_line = true 13 | enum_discrim_align_threshold = 80 14 | error_on_line_overflow = false 15 | error_on_unformatted = false 16 | # fn_call_width = 60 17 | fn_params_layout = "Tall" 18 | fn_single_line = false 19 | force_explicit_abi = true 20 | force_multiline_blocks = false 21 | format_code_in_doc_comments = true 22 | doc_comment_code_block_width = 80 23 | format_generated_files = true 24 | format_macro_matchers = true 25 | format_macro_bodies = true 26 | skip_macro_invocations = [] 27 | format_strings = true 28 | hard_tabs = false 29 | hex_literal_case = "Upper" 30 | imports_indent = "Block" 31 | imports_layout = "Mixed" 32 | indent_style = "Block" 33 | inline_attribute_width = 0 34 | match_arm_blocks = true 35 | match_arm_leading_pipes = "Never" 36 | match_block_trailing_comma = true 37 | max_width = 100 38 | merge_derives = true 39 | imports_granularity = "Crate" 40 | newline_style = "Unix" 41 | normalize_comments = false 42 | normalize_doc_attributes = true 43 | overflow_delimited_expr = true 44 | remove_nested_parens = true 45 | reorder_impl_items = true 46 | reorder_imports = true 47 | group_imports = "StdExternalCrate" 48 | reorder_modules = true 49 | short_array_element_width_threshold = 10 50 | # single_line_if_else_max_width = 50 51 | space_after_colon = true 52 | space_before_colon = false 53 | spaces_around_ranges = false 54 | struct_field_align_threshold = 80 55 | struct_lit_single_line = false 56 | # struct_lit_width = 18 57 | # struct_variant_width = 35 58 | tab_spaces = 4 59 | trailing_comma = "Vertical" 60 | trailing_semicolon = true 61 | type_punctuation_density = "Wide" 62 | use_field_init_shorthand = true 63 | use_small_heuristics = "Max" 64 | use_try_shorthand = true 65 | where_single_line = false 66 | wrap_comments = false -------------------------------------------------------------------------------- /src/chinese_case.rs: -------------------------------------------------------------------------------- 1 | /// 大寫或小寫數字。 2 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 3 | pub enum ChineseCase { 4 | /// 大寫數字。 5 | Upper, 6 | /// 小寫數字。 7 | Lower, 8 | } 9 | -------------------------------------------------------------------------------- /src/chinese_characters.rs: -------------------------------------------------------------------------------- 1 | use enum_ordinalize::Ordinalize; 2 | 3 | #[cfg(feature = "number-to-chinese")] 4 | use crate::{ChineseCase, ChineseVariant}; 5 | 6 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Ordinalize)] 7 | #[ordinalize(impl_trait = false)] 8 | #[ordinalize(ordinal(pub(crate) fn ordinal))] 9 | #[ordinalize(from_ordinal_unsafe(pub(crate) fn from_ordinal_unsafe))] 10 | #[allow(dead_code)] 11 | #[repr(u8)] 12 | pub(crate) enum ChineseNumber { 13 | 零, 14 | 一, 15 | 二, 16 | 三, 17 | 四, 18 | 五, 19 | 六, 20 | 七, 21 | 八, 22 | 九, 23 | 十, 24 | } 25 | 26 | impl ChineseNumber { 27 | #[cfg(feature = "number-to-chinese")] 28 | #[inline] 29 | pub(crate) const fn to_str( 30 | self, 31 | chinese_variant: ChineseVariant, 32 | chinese_case: ChineseCase, 33 | ) -> &'static str { 34 | match self { 35 | Self::零 => "零", 36 | Self::一 => match chinese_case { 37 | ChineseCase::Upper => "壹", 38 | ChineseCase::Lower => "一", 39 | }, 40 | Self::二 => match chinese_case { 41 | ChineseCase::Upper => match chinese_variant { 42 | ChineseVariant::Traditional => "貳", 43 | ChineseVariant::Simple => "贰", 44 | }, 45 | ChineseCase::Lower => "二", 46 | }, 47 | Self::三 => match chinese_case { 48 | ChineseCase::Upper => match chinese_variant { 49 | ChineseVariant::Traditional => "參", 50 | ChineseVariant::Simple => "叁", 51 | }, 52 | ChineseCase::Lower => "三", 53 | }, 54 | Self::四 => match chinese_case { 55 | ChineseCase::Upper => "肆", 56 | ChineseCase::Lower => "四", 57 | }, 58 | Self::五 => match chinese_case { 59 | ChineseCase::Upper => "伍", 60 | ChineseCase::Lower => "五", 61 | }, 62 | Self::六 => match chinese_case { 63 | ChineseCase::Upper => match chinese_variant { 64 | ChineseVariant::Traditional => "陸", 65 | ChineseVariant::Simple => "陆", 66 | }, 67 | ChineseCase::Lower => "六", 68 | }, 69 | Self::七 => match chinese_case { 70 | ChineseCase::Upper => "柒", 71 | ChineseCase::Lower => "七", 72 | }, 73 | Self::八 => match chinese_case { 74 | ChineseCase::Upper => "捌", 75 | ChineseCase::Lower => "八", 76 | }, 77 | Self::九 => match chinese_case { 78 | ChineseCase::Upper => "玖", 79 | ChineseCase::Lower => "九", 80 | }, 81 | Self::十 => match chinese_case { 82 | ChineseCase::Upper => "拾", 83 | ChineseCase::Lower => "十", 84 | }, 85 | } 86 | } 87 | 88 | #[cfg(feature = "chinese-to-number")] 89 | #[inline] 90 | pub(crate) const fn from_char(character: char) -> Option { 91 | match character { 92 | '零' | '0' | '〇' => Some(Self::零), 93 | '一' | '壹' | '1' => Some(Self::一), 94 | '二' | '貳' | '贰' | '貮' | '兩' | '两' | '2' => Some(Self::二), 95 | '三' | '參' | '叁' | '叄' | '参' | '3' => Some(Self::三), 96 | '四' | '肆' | '4' => Some(Self::四), 97 | '五' | '伍' | '5' => Some(Self::五), 98 | '六' | '陸' | '陆' | '6' => Some(Self::六), 99 | '七' | '柒' | '7' => Some(Self::七), 100 | '八' | '捌' | '8' => Some(Self::八), 101 | '九' | '玖' | '9' => Some(Self::九), 102 | '十' | '拾' => Some(Self::十), 103 | _ => None, 104 | } 105 | } 106 | } 107 | 108 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Ordinalize)] 109 | #[ordinalize(impl_trait = false)] 110 | #[ordinalize(ordinal(pub(crate) fn ordinal))] 111 | #[ordinalize(from_ordinal_unsafe(pub(crate) fn from_ordinal_unsafe))] 112 | #[allow(dead_code)] 113 | #[repr(u8)] 114 | pub(crate) enum ChineseExponent { 115 | 分, 116 | 角, 117 | 個, 118 | 十, 119 | 百, 120 | 千, 121 | 萬, 122 | 億, 123 | 兆, 124 | 京, 125 | 垓, 126 | 秭, 127 | 穰, 128 | 溝, 129 | 澗, 130 | 正, 131 | 載, 132 | 極, 133 | } 134 | 135 | impl ChineseExponent { 136 | #[cfg(feature = "number-to-chinese")] 137 | #[inline] 138 | pub(crate) const fn to_str( 139 | self, 140 | chinese_variant: ChineseVariant, 141 | chinese_case: ChineseCase, 142 | ) -> &'static str { 143 | match self { 144 | Self::分 => "分", 145 | Self::角 => "角", 146 | Self::個 => match chinese_variant { 147 | ChineseVariant::Traditional => "個", 148 | ChineseVariant::Simple => "个", 149 | }, 150 | Self::十 => match chinese_case { 151 | ChineseCase::Upper => "拾", 152 | ChineseCase::Lower => "十", 153 | }, 154 | Self::百 => match chinese_case { 155 | ChineseCase::Upper => "佰", 156 | ChineseCase::Lower => "百", 157 | }, 158 | Self::千 => match chinese_case { 159 | ChineseCase::Upper => "仟", 160 | ChineseCase::Lower => "千", 161 | }, 162 | Self::萬 => match chinese_variant { 163 | ChineseVariant::Traditional => "萬", 164 | ChineseVariant::Simple => "万", 165 | }, 166 | Self::億 => match chinese_variant { 167 | ChineseVariant::Traditional => "億", 168 | ChineseVariant::Simple => "亿", 169 | }, 170 | Self::兆 => "兆", 171 | Self::京 => "京", 172 | Self::垓 => "垓", 173 | Self::秭 => "秭", 174 | Self::穰 => "穰", 175 | Self::溝 => match chinese_variant { 176 | ChineseVariant::Traditional => "溝", 177 | ChineseVariant::Simple => "沟", 178 | }, 179 | Self::澗 => match chinese_variant { 180 | ChineseVariant::Traditional => "澗", 181 | ChineseVariant::Simple => "涧", 182 | }, 183 | Self::正 => "正", 184 | Self::載 => match chinese_variant { 185 | ChineseVariant::Traditional => "載", 186 | ChineseVariant::Simple => "载", 187 | }, 188 | Self::極 => match chinese_variant { 189 | ChineseVariant::Traditional => "極", 190 | ChineseVariant::Simple => "极", 191 | }, 192 | } 193 | } 194 | 195 | #[cfg(feature = "chinese-to-number")] 196 | #[inline] 197 | pub(crate) const fn from_char(character: char) -> Option { 198 | match character { 199 | '分' => Some(Self::分), 200 | '角' => Some(Self::角), 201 | '個' | '个' => Some(Self::個), 202 | '十' | '拾' => Some(Self::十), 203 | '百' | '佰' => Some(Self::百), 204 | '千' | '仟' => Some(Self::千), 205 | '萬' | '万' => Some(Self::萬), 206 | '億' | '亿' => Some(Self::億), 207 | '兆' => Some(Self::兆), 208 | '京' => Some(Self::京), 209 | '垓' => Some(Self::垓), 210 | '秭' => Some(Self::秭), 211 | '穰' => Some(Self::穰), 212 | '溝' | '沟' => Some(Self::溝), 213 | '澗' | '涧' => Some(Self::澗), 214 | '正' => Some(Self::正), 215 | '載' | '载' => Some(Self::載), 216 | '極' | '极' => Some(Self::極), 217 | _ => None, 218 | } 219 | } 220 | } 221 | 222 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 223 | #[allow(dead_code)] 224 | #[repr(u8)] 225 | pub(crate) enum ChineseSign { 226 | 正, 227 | 負, 228 | } 229 | 230 | impl ChineseSign { 231 | #[cfg(feature = "number-to-chinese")] 232 | #[inline] 233 | pub(crate) const fn to_str(self, chinese_variant: ChineseVariant) -> &'static str { 234 | match self { 235 | Self::正 => "正", 236 | Self::負 => match chinese_variant { 237 | ChineseVariant::Traditional => "負", 238 | ChineseVariant::Simple => "负", 239 | }, 240 | } 241 | } 242 | 243 | #[cfg(feature = "chinese-to-number")] 244 | #[inline] 245 | pub(crate) const fn from_char(character: char) -> Option { 246 | match character { 247 | '正' => Some(Self::正), 248 | '負' | '负' => Some(Self::負), 249 | _ => None, 250 | } 251 | } 252 | } 253 | 254 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 255 | pub(crate) struct ChinesePoint; 256 | 257 | impl ChinesePoint { 258 | #[cfg(feature = "number-to-chinese")] 259 | #[inline] 260 | pub(crate) const fn to_str(chinese_variant: ChineseVariant) -> &'static str { 261 | match chinese_variant { 262 | ChineseVariant::Traditional => "點", 263 | ChineseVariant::Simple => "点", 264 | } 265 | } 266 | 267 | #[cfg(feature = "chinese-to-number")] 268 | #[inline] 269 | pub(crate) const fn from_char(character: char) -> Option { 270 | match character { 271 | '點' | '点' => Some(ChinesePoint), 272 | _ => None, 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /src/chinese_count_method.rs: -------------------------------------------------------------------------------- 1 | use enum_ordinalize::Ordinalize; 2 | 3 | /// 根據 **五經算術** 將大的單位分為 **上數** (`High`)、**中數** (`Middle`)、**下數** (`Low`) 三種類型,再加上現代使用的 **萬進** (`TenThousand`)。 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ordinalize)] 5 | #[ordinalize(impl_trait = false)] 6 | #[ordinalize(variants(pub fn variants, doc = "算術類型的所有變體的陣列。"))] 7 | pub enum ChineseCountMethod { 8 | /// 下數者,十十變之。若言十萬曰億,十億曰兆,十兆曰京也。 9 | Low, 10 | /// 萬進者,一萬變之。若言萬萬曰億,萬億曰兆,萬兆曰京也。 11 | TenThousand, 12 | /// 中數者,萬萬變之。若言萬萬曰億,萬萬億曰兆,萬萬兆曰京也。 13 | Middle, 14 | /// 上數者,數窮則變。若言萬萬曰億,億億曰兆、兆兆曰京也。 15 | High, 16 | } 17 | -------------------------------------------------------------------------------- /src/chinese_to_number/chinese_to_number_error.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Formatter}; 2 | #[cfg(feature = "std")] 3 | use std::error::Error; 4 | 5 | /// 將中文數字轉成數值時發生的錯誤。 6 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 7 | pub enum ChineseToNumberError { 8 | ChineseNumberEmpty, 9 | ChineseNumberIncorrect { char_index: usize }, 10 | Overflow, 11 | Underflow, 12 | } 13 | 14 | impl Display for ChineseToNumberError { 15 | #[inline] 16 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { 17 | match self { 18 | ChineseToNumberError::ChineseNumberEmpty => { 19 | f.write_str("a chinese number cannot be empty") 20 | }, 21 | ChineseToNumberError::ChineseNumberIncorrect { 22 | char_index, 23 | } => f.write_fmt(format_args!( 24 | "the chinese number is incorrect (position: {})", 25 | char_index 26 | )), 27 | ChineseToNumberError::Overflow => f.write_str("number is too large"), 28 | ChineseToNumberError::Underflow => f.write_str("number is too small"), 29 | } 30 | } 31 | } 32 | 33 | #[cfg(feature = "std")] 34 | impl Error for ChineseToNumberError {} 35 | -------------------------------------------------------------------------------- /src/chinese_to_number/functions.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use core::cmp::Ordering; 3 | 4 | #[cfg(not(feature = "std"))] 5 | #[allow(unused_imports)] 6 | use num_traits::float::FloatCore; 7 | 8 | use crate::{ 9 | ChineseCountMethod, ChineseExponent, ChineseNumber, ChineseSign, ChineseToNumberError, 10 | }; 11 | 12 | #[inline] 13 | pub(crate) fn to_chars_vec>(s: S) -> Vec { 14 | s.as_ref().chars().filter(|c| !c.is_whitespace()).collect() 15 | } 16 | 17 | fn get_exp_base( 18 | method: ChineseCountMethod, 19 | exp: ChineseExponent, 20 | ) -> Result { 21 | match method { 22 | ChineseCountMethod::Low => match exp { 23 | ChineseExponent::個 => Ok(1), 24 | _ => { 25 | debug_assert!(exp > ChineseExponent::個); 26 | 27 | Ok(10u128.pow((exp.ordinal() - ChineseExponent::個.ordinal()) as u32)) 28 | }, 29 | }, 30 | ChineseCountMethod::TenThousand => match exp { 31 | ChineseExponent::個 => Ok(1), 32 | ChineseExponent::十 => Ok(10), 33 | ChineseExponent::百 => Ok(100), 34 | ChineseExponent::千 => Ok(1000), 35 | _ => { 36 | debug_assert!(exp > ChineseExponent::千); 37 | 38 | 1_0000u128 39 | .checked_pow((exp.ordinal() - ChineseExponent::千.ordinal()) as u32) 40 | .ok_or(ChineseToNumberError::Overflow) 41 | }, 42 | }, 43 | ChineseCountMethod::Middle => match exp { 44 | ChineseExponent::個 => Ok(1), 45 | ChineseExponent::十 => Ok(10), 46 | ChineseExponent::百 => Ok(100), 47 | ChineseExponent::千 => Ok(1000), 48 | ChineseExponent::萬 => Ok(1_0000), 49 | _ => { 50 | debug_assert!(exp > ChineseExponent::萬); 51 | 52 | 1_0000_0000u128 53 | .checked_pow((exp.ordinal() - ChineseExponent::萬.ordinal()) as u32) 54 | .ok_or(ChineseToNumberError::Overflow) 55 | }, 56 | }, 57 | ChineseCountMethod::High => match exp { 58 | ChineseExponent::個 => Ok(1), 59 | ChineseExponent::十 => Ok(10), 60 | ChineseExponent::百 => Ok(100), 61 | ChineseExponent::千 => Ok(1000), 62 | _ => { 63 | debug_assert!(exp > ChineseExponent::千); 64 | 65 | let mut w = 1_0000u128; 66 | 67 | for _ in 0..exp.ordinal() - ChineseExponent::萬.ordinal() { 68 | w = w.checked_pow(2).ok_or(ChineseToNumberError::Overflow)?; 69 | } 70 | 71 | Ok(w) 72 | }, 73 | }, 74 | } 75 | } 76 | 77 | pub(crate) fn chinese_to_unsigned_integer_unit( 78 | method: ChineseCountMethod, 79 | chars: &[char], 80 | mut pointer: usize, 81 | level: ChineseExponent, 82 | ) -> Result<(u128, Option<(usize, ChineseExponent)>), ChineseToNumberError> { 83 | debug_assert!(!chars.is_empty() && pointer < chars.len()); 84 | 85 | let base = get_exp_base(method, level)?; 86 | 87 | let (n, exp) = match ChineseNumber::from_char(chars[pointer]) { 88 | Some(n) if n == ChineseNumber::十 => { 89 | if pointer == 0 { 90 | return Ok(( 91 | (n.ordinal() as u128) 92 | .checked_mul(base) 93 | .ok_or(ChineseToNumberError::Overflow)?, 94 | None, 95 | )); 96 | } 97 | 98 | (0u128, ChineseExponent::十) 99 | }, 100 | Some(n) => { 101 | if pointer == 0 { 102 | return Ok(( 103 | (n.ordinal() as u128) 104 | .checked_mul(base) 105 | .ok_or(ChineseToNumberError::Overflow)?, 106 | None, 107 | )); 108 | } 109 | 110 | pointer -= 1; 111 | 112 | loop { 113 | match ChineseExponent::from_char(chars[pointer]) { 114 | Some(exp) if exp > ChineseExponent::個 => { 115 | if pointer == 0 { 116 | if exp == ChineseExponent::十 { 117 | return Ok(( 118 | ((10 + n.ordinal()) as u128) 119 | .checked_mul(base) 120 | .ok_or(ChineseToNumberError::Overflow)?, 121 | None, 122 | )); 123 | } else { 124 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 125 | char_index: pointer, 126 | }); 127 | } 128 | } 129 | 130 | break (n.ordinal() as u128, exp); 131 | }, 132 | _ => match ChineseNumber::from_char(chars[pointer]) { 133 | Some(ChineseNumber::零) => { 134 | if pointer == 0 { 135 | return Ok(( 136 | (n.ordinal() as u128) 137 | .checked_mul(base) 138 | .ok_or(ChineseToNumberError::Overflow)?, 139 | None, 140 | )); 141 | } 142 | 143 | pointer -= 1; 144 | 145 | continue; 146 | }, 147 | _ => { 148 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 149 | char_index: pointer, 150 | }) 151 | }, 152 | }, 153 | } 154 | } 155 | }, 156 | _ => { 157 | if pointer == 0 { 158 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 159 | char_index: pointer 160 | }); 161 | } 162 | 163 | match ChineseExponent::from_char(chars[pointer]) { 164 | Some(exp) if exp < level => (0u128, exp), 165 | _ => { 166 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 167 | char_index: pointer, 168 | }) 169 | }, 170 | } 171 | }, 172 | }; 173 | 174 | let mut sum = n; 175 | let mut next = Some((pointer, exp)); 176 | 177 | while let Some((pointer, exp)) = next { 178 | match exp.cmp(&level) { 179 | Ordering::Greater => { 180 | break; 181 | }, 182 | Ordering::Less => { 183 | let result = chinese_to_unsigned_integer_unit(method, chars, pointer - 1, exp)?; 184 | 185 | sum = sum.checked_add(result.0).ok_or(ChineseToNumberError::Overflow)?; 186 | 187 | next = result.1; 188 | }, 189 | Ordering::Equal => { 190 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 191 | char_index: pointer 192 | }); 193 | }, 194 | } 195 | } 196 | 197 | sum = sum.checked_mul(base).ok_or(ChineseToNumberError::Overflow)?; 198 | 199 | Ok((sum, next)) 200 | } 201 | 202 | pub(crate) fn chinese_to_unsigned_integer( 203 | method: ChineseCountMethod, 204 | chars: &[char], 205 | ) -> Result { 206 | let length = chars.len(); 207 | 208 | if length == 0 { 209 | return Err(ChineseToNumberError::ChineseNumberEmpty); 210 | } 211 | 212 | let mut pointer = length - 1; 213 | 214 | let mut exp = match ChineseExponent::from_char(chars[pointer]) { 215 | Some(exp) if exp > ChineseExponent::個 => { 216 | if pointer == 0 { 217 | if exp == ChineseExponent::十 { 218 | return Ok(10); 219 | } else { 220 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 221 | char_index: pointer, 222 | }); 223 | } 224 | } 225 | 226 | exp 227 | }, 228 | _ => { 229 | if length >= 3 { 230 | // look ahead 231 | 232 | let left_char = chars[pointer - 1]; 233 | 234 | if let Some(ChineseNumber::零) = ChineseNumber::from_char(left_char) { 235 | // do nothing 236 | } else { 237 | match ChineseExponent::from_char(left_char) { 238 | Some(exp) if exp >= ChineseExponent::百 => { 239 | let high = chinese_to_unsigned_integer(method, &chars[..pointer])?; 240 | 241 | let low = 242 | chinese_to_unsigned_integer_unit(method, &chars[pointer..], 0, exp) 243 | .map_err(|mut err| { 244 | if let ChineseToNumberError::ChineseNumberIncorrect { 245 | char_index, 246 | } = &mut err 247 | { 248 | *char_index = pointer; 249 | } 250 | 251 | err 252 | })? 253 | .0 254 | / 10; 255 | 256 | return high.checked_add(low).ok_or(ChineseToNumberError::Overflow); 257 | }, 258 | _ => (), 259 | } 260 | } 261 | } 262 | 263 | pointer += 1; 264 | ChineseExponent::個 265 | }, 266 | }; 267 | 268 | let mut sum = 0u128; 269 | 270 | loop { 271 | let result = chinese_to_unsigned_integer_unit(method, chars, pointer - 1, exp)?; 272 | 273 | sum = sum.checked_add(result.0).ok_or(ChineseToNumberError::Overflow)?; 274 | 275 | if let Some((p, e)) = result.1 { 276 | pointer = p; 277 | exp = e; 278 | 279 | continue; 280 | } 281 | 282 | break; 283 | } 284 | 285 | Ok(sum) 286 | } 287 | 288 | pub(crate) fn chinese_to_signed_integer( 289 | method: ChineseCountMethod, 290 | chars: &[char], 291 | ) -> Result { 292 | let length = chars.len(); 293 | 294 | if length == 0 { 295 | return Err(ChineseToNumberError::ChineseNumberEmpty); 296 | } 297 | 298 | let c = chars[0]; 299 | 300 | let (sign, offset) = match ChineseSign::from_char(c) { 301 | Some(sign) => (sign, 1), 302 | None => (ChineseSign::正, 0), 303 | }; 304 | 305 | let uint = match chinese_to_unsigned_integer(method, &chars[offset..]) { 306 | Ok(n) => n, 307 | Err(error) => { 308 | return match error { 309 | ChineseToNumberError::ChineseNumberIncorrect { 310 | char_index: index, 311 | } => Err(ChineseToNumberError::ChineseNumberIncorrect { 312 | char_index: index + offset, 313 | }), 314 | ChineseToNumberError::Overflow if sign == ChineseSign::負 => { 315 | Err(ChineseToNumberError::Underflow) 316 | }, 317 | _ => Err(error), 318 | }; 319 | }, 320 | }; 321 | 322 | match sign { 323 | ChineseSign::正 => { 324 | if uint > i128::MAX as u128 { 325 | return Err(ChineseToNumberError::Overflow); 326 | } 327 | 328 | Ok(uint as i128) 329 | }, 330 | ChineseSign::負 => { 331 | let m = i128::MAX as u128 + 1; 332 | 333 | if uint > m { 334 | return Err(ChineseToNumberError::Underflow); 335 | } 336 | 337 | if uint == m { 338 | Ok(i128::MIN) 339 | } else { 340 | Ok(-(uint as i128)) 341 | } 342 | }, 343 | } 344 | } 345 | 346 | // TODO f64 347 | 348 | fn get_exp_base_f64(method: ChineseCountMethod, exp: ChineseExponent) -> f64 { 349 | match method { 350 | ChineseCountMethod::Low => match exp { 351 | ChineseExponent::個 => 1f64, 352 | _ => { 353 | debug_assert!(exp > ChineseExponent::個); 354 | 10f64.powi((exp.ordinal() - ChineseExponent::個.ordinal()) as i32) 355 | }, 356 | }, 357 | ChineseCountMethod::TenThousand => match exp { 358 | ChineseExponent::個 => 1f64, 359 | ChineseExponent::十 => 10f64, 360 | ChineseExponent::百 => 100f64, 361 | ChineseExponent::千 => 1000f64, 362 | _ => { 363 | debug_assert!(exp > ChineseExponent::千); 364 | 365 | 1_0000f64.powi((exp.ordinal() - ChineseExponent::千.ordinal()) as i32) 366 | }, 367 | }, 368 | ChineseCountMethod::Middle => match exp { 369 | ChineseExponent::個 => 1f64, 370 | ChineseExponent::十 => 10f64, 371 | ChineseExponent::百 => 100f64, 372 | ChineseExponent::千 => 1000f64, 373 | ChineseExponent::萬 => 1_0000f64, 374 | _ => { 375 | debug_assert!(exp > ChineseExponent::萬); 376 | 377 | 1_0000_0000f64.powi((exp.ordinal() - ChineseExponent::萬.ordinal()) as i32) 378 | }, 379 | }, 380 | ChineseCountMethod::High => match exp { 381 | ChineseExponent::個 => 1f64, 382 | ChineseExponent::十 => 10f64, 383 | ChineseExponent::百 => 100f64, 384 | ChineseExponent::千 => 1000f64, 385 | _ => { 386 | debug_assert!(exp > ChineseExponent::千); 387 | 388 | let mut w = 1_0000f64; 389 | 390 | for _ in 0..exp.ordinal() - ChineseExponent::萬.ordinal() { 391 | w *= w; 392 | } 393 | 394 | w 395 | }, 396 | }, 397 | } 398 | } 399 | 400 | pub(crate) fn chinese_to_f64_unit( 401 | method: ChineseCountMethod, 402 | chars: &[char], 403 | mut pointer: usize, 404 | level: ChineseExponent, 405 | ) -> Result<(f64, Option<(usize, ChineseExponent)>), ChineseToNumberError> { 406 | debug_assert!(!chars.is_empty() && pointer < chars.len()); 407 | 408 | let base = get_exp_base_f64(method, level); 409 | 410 | let (n, exp) = match ChineseNumber::from_char(chars[pointer]) { 411 | Some(n) if n == ChineseNumber::十 => { 412 | if pointer == 0 { 413 | return Ok(((n.ordinal() as f64) * base, None)); 414 | } 415 | 416 | (0f64, ChineseExponent::十) 417 | }, 418 | Some(n) => { 419 | if pointer == 0 { 420 | return Ok(((n.ordinal() as f64) * base, None)); 421 | } 422 | 423 | pointer -= 1; 424 | 425 | loop { 426 | match ChineseExponent::from_char(chars[pointer]) { 427 | Some(exp) if exp > ChineseExponent::個 => { 428 | if pointer == 0 { 429 | if exp == ChineseExponent::十 { 430 | return Ok((((10 + n.ordinal()) as f64) * base, None)); 431 | } else { 432 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 433 | char_index: pointer, 434 | }); 435 | } 436 | } 437 | 438 | break (n.ordinal() as f64, exp); 439 | }, 440 | _ => match ChineseNumber::from_char(chars[pointer]) { 441 | Some(ChineseNumber::零) => { 442 | if pointer == 0 { 443 | return Ok(((n.ordinal() as f64) * base, None)); 444 | } 445 | 446 | pointer -= 1; 447 | 448 | continue; 449 | }, 450 | _ => { 451 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 452 | char_index: pointer, 453 | }) 454 | }, 455 | }, 456 | } 457 | } 458 | }, 459 | _ => { 460 | if pointer == 0 { 461 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 462 | char_index: pointer 463 | }); 464 | } 465 | 466 | match ChineseExponent::from_char(chars[pointer]) { 467 | Some(exp) if exp < level => (0f64, exp), 468 | _ => { 469 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 470 | char_index: pointer, 471 | }) 472 | }, 473 | } 474 | }, 475 | }; 476 | 477 | let mut sum = n; 478 | let mut next = Some((pointer, exp)); 479 | 480 | while let Some((pointer, exp)) = next { 481 | match exp.cmp(&level) { 482 | Ordering::Greater => { 483 | break; 484 | }, 485 | Ordering::Less => { 486 | let result = chinese_to_f64_unit(method, chars, pointer - 1, exp)?; 487 | 488 | sum += result.0; 489 | 490 | next = result.1; 491 | }, 492 | Ordering::Equal => { 493 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 494 | char_index: pointer 495 | }); 496 | }, 497 | } 498 | } 499 | 500 | sum *= base; 501 | 502 | Ok((sum, next)) 503 | } 504 | 505 | pub(crate) fn chinese_to_unsigned_f64( 506 | method: ChineseCountMethod, 507 | chars: &[char], 508 | ) -> Result { 509 | let length = chars.len(); 510 | 511 | if length == 0 { 512 | return Err(ChineseToNumberError::ChineseNumberEmpty); 513 | } 514 | 515 | let mut pointer = length - 1; 516 | 517 | let mut exp = match ChineseExponent::from_char(chars[pointer]) { 518 | Some(exp) if exp > ChineseExponent::個 => { 519 | if pointer == 0 { 520 | if exp == ChineseExponent::十 { 521 | return Ok(10f64); 522 | } else { 523 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 524 | char_index: pointer, 525 | }); 526 | } 527 | } 528 | 529 | exp 530 | }, 531 | _ => { 532 | pointer += 1; 533 | ChineseExponent::個 534 | }, 535 | }; 536 | 537 | let mut sum = 0f64; 538 | 539 | loop { 540 | let result = chinese_to_f64_unit(method, chars, pointer - 1, exp)?; 541 | 542 | sum += result.0; 543 | 544 | if let Some((p, e)) = result.1 { 545 | pointer = p; 546 | exp = e; 547 | 548 | continue; 549 | } 550 | 551 | break; 552 | } 553 | 554 | Ok(sum) 555 | } 556 | 557 | pub(crate) fn chinese_to_f64( 558 | method: ChineseCountMethod, 559 | chars: &[char], 560 | ) -> Result { 561 | let length = chars.len(); 562 | 563 | if length == 0 { 564 | return Err(ChineseToNumberError::ChineseNumberEmpty); 565 | } 566 | 567 | let mut end = length - 1; 568 | let mut fraction = 0.00; 569 | 570 | if let Some(ChineseExponent::分) = ChineseExponent::from_char(chars[end]) { 571 | if end == 0 { 572 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 573 | char_index: end 574 | }); 575 | } 576 | 577 | end -= 1; 578 | 579 | match ChineseNumber::from_char(chars[end]) { 580 | Some(n) if n != ChineseNumber::十 => { 581 | fraction += n.ordinal() as f64 * 0.01; 582 | 583 | if end == 0 { 584 | return Ok(fraction); 585 | } 586 | 587 | end -= 1; 588 | }, 589 | _ => { 590 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 591 | char_index: end 592 | }); 593 | }, 594 | } 595 | } 596 | 597 | if let Some(ChineseExponent::角) = ChineseExponent::from_char(chars[end]) { 598 | if end == 0 { 599 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 600 | char_index: end 601 | }); 602 | } 603 | 604 | end -= 1; 605 | 606 | match ChineseNumber::from_char(chars[end]) { 607 | Some(n) if n != ChineseNumber::十 => { 608 | fraction += n.ordinal() as f64 * 0.1; 609 | 610 | if end == 0 { 611 | return Ok(fraction); 612 | } 613 | 614 | end -= 1; 615 | }, 616 | _ => { 617 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 618 | char_index: end 619 | }); 620 | }, 621 | } 622 | } 623 | 624 | let c = chars[0]; 625 | 626 | let (sign, offset) = match ChineseSign::from_char(c) { 627 | Some(sign) => (sign, 1), 628 | None => (ChineseSign::正, 0), 629 | }; 630 | 631 | let f = match chinese_to_unsigned_f64(method, &chars[offset..=end]) { 632 | Ok(n) => n + fraction, 633 | Err(error) => { 634 | return match error { 635 | ChineseToNumberError::ChineseNumberIncorrect { 636 | char_index: index, 637 | } => Err(ChineseToNumberError::ChineseNumberIncorrect { 638 | char_index: index + offset, 639 | }), 640 | ChineseToNumberError::Overflow if sign == ChineseSign::負 => { 641 | Err(ChineseToNumberError::Underflow) 642 | }, 643 | _ => Err(error), 644 | }; 645 | }, 646 | }; 647 | 648 | match sign { 649 | ChineseSign::正 => Ok(f), 650 | ChineseSign::負 => Ok(-f), 651 | } 652 | } 653 | -------------------------------------------------------------------------------- /src/chinese_to_number/functions_test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::*; 4 | 5 | #[test] 6 | fn test_chinese_to_unsigned_integer_low() { 7 | macro_rules! test { 8 | ($expect:expr, $value:expr) => { 9 | assert_eq!( 10 | $expect, 11 | chinese_to_unsigned_integer(ChineseCountMethod::Low, &to_chars_vec($value)) 12 | .unwrap() 13 | ); 14 | }; 15 | } 16 | 17 | test!(0, "零"); 18 | test!(1, "一"); 19 | test!(2, "貳"); 20 | test!(10, "十"); 21 | test!(11, "十一"); 22 | test!(20, "二十"); 23 | test!(100, "一百"); 24 | test!(101, "一百零一"); 25 | test!(110, "一百一十"); 26 | test!(111, "一百一十一"); 27 | test!(200, "兩百"); 28 | test!(1000, "一千"); 29 | test!(1001, "一千零一"); 30 | test!(1010, "一千零一十"); 31 | test!(1011, "一千零一十一"); 32 | test!(1100, "一千一百"); 33 | test!(1101, "一千一百零一"); 34 | test!(1110, "一千一百一十"); 35 | test!(2000, "二千"); 36 | test!(1_0000, "一萬"); 37 | test!(1_0001, "一萬零一"); 38 | test!(10_0000, "一億"); 39 | test!(10_0100, "一億零一百"); 40 | test!(1_0000_0000, "一垓"); 41 | test!(1_0000_1000, "一垓零一千"); 42 | test!(10_0000_0000, "一秭"); 43 | test!(1_0000_0000_0000, "一澗"); 44 | test!(1_0000_1000_0000, "一澗零一京"); 45 | test!(10_0000_0000_0000, "一正"); 46 | test!(1000_0000_0000_0000, "一極"); 47 | test!(1000_1000_0000_0000, "一極零一溝"); 48 | test!(9000_0900_0090_0009, "九極零九穰零九億零九"); 49 | } 50 | 51 | #[test] 52 | fn test_chinese_to_unsigned_integer_ten_thousand() { 53 | macro_rules! test { 54 | ($expect:expr, $value:expr) => { 55 | assert_eq!( 56 | $expect, 57 | chinese_to_unsigned_integer(ChineseCountMethod::TenThousand, &to_chars_vec($value)) 58 | .unwrap() 59 | ); 60 | }; 61 | } 62 | 63 | test!(0, "零"); 64 | test!(1, "一"); 65 | test!(2, "貳"); 66 | test!(10, "十"); 67 | test!(11, "十一"); 68 | test!(20, "二十"); 69 | test!(100, "一百"); 70 | test!(101, "一百零一"); 71 | test!(110, "一百一十"); 72 | test!(111, "一百一十一"); 73 | test!(200, "兩百"); 74 | test!(1000, "一千"); 75 | test!(1001, "一千零一"); 76 | test!(1010, "一千零一十"); 77 | test!(1011, "一千零一十一"); 78 | test!(1100, "一千一百"); 79 | test!(1101, "一千一百零一"); 80 | test!(1110, "一千一百一十"); 81 | test!(2000, "二千"); 82 | test!(1_0000, "一萬"); 83 | test!(1_0001, "一萬零一"); 84 | test!(10_0000, "十萬"); 85 | test!(10_0100, "十萬零一百"); 86 | test!(1_0000_0000, "一億"); 87 | test!(1_0000_1000, "一億零一千"); 88 | test!(10_0000_0000, "十億"); 89 | test!(1_0000_0000_0000, "一兆"); 90 | test!(1_0000_1000_0000, "一兆零一千萬"); 91 | test!(10_0000_0000_0000, "十兆"); 92 | test!(1_0000_0000_0000_0000, "一京"); 93 | test!(1_0000_1000_0000_0000, "一京零一千億"); 94 | test!(9_9000_0900_0090_0009, "九京九千兆零九百億零九十萬零九"); 95 | } 96 | 97 | #[test] 98 | fn test_chinese_to_unsigned_integer_middle() { 99 | macro_rules! test { 100 | ($expect:expr, $value:expr) => { 101 | assert_eq!( 102 | $expect, 103 | chinese_to_unsigned_integer(ChineseCountMethod::Middle, &to_chars_vec($value)) 104 | .unwrap() 105 | ); 106 | }; 107 | } 108 | 109 | test!(0, "零"); 110 | test!(1, "一"); 111 | test!(2, "貳"); 112 | test!(10, "十"); 113 | test!(11, "十一"); 114 | test!(20, "二十"); 115 | test!(100, "一百"); 116 | test!(101, "一百零一"); 117 | test!(110, "一百一十"); 118 | test!(111, "一百一十一"); 119 | test!(200, "兩百"); 120 | test!(1000, "一千"); 121 | test!(1001, "一千零一"); 122 | test!(1010, "一千零一十"); 123 | test!(1011, "一千零一十一"); 124 | test!(1100, "一千一百"); 125 | test!(1101, "一千一百零一"); 126 | test!(1110, "一千一百一十"); 127 | test!(2000, "二千"); 128 | test!(1_0000, "一萬"); 129 | test!(1_0001, "一萬零一"); 130 | test!(10_0000, "十萬"); 131 | test!(10_0100, "十萬零一百"); 132 | test!(1_0000_0000, "一億"); 133 | test!(1_0000_1000, "一億零一千"); 134 | test!(10_0000_0000, "十億"); 135 | test!(1_0000_0000_0000, "一萬億"); 136 | test!(1_0000_1000_0000, "一萬億零一千萬"); 137 | test!(10_0000_0000_0000, "十萬億"); 138 | test!(1_0000_0000_0000_0000, "一兆"); 139 | test!(1_0000_1000_0000_0000, "一兆零一千億"); 140 | test!(10_0000_0000_0000_0000, "十兆"); 141 | test!(1_0000_0000_0000_0000_0000, "一萬兆"); 142 | test!(1_0000_0000_0000_0000_0000_0000, "一京"); 143 | test!(9_0000_0000_9000_0900_0090_0009, "九京零九千萬零九百億零九十萬零九"); 144 | } 145 | 146 | #[test] 147 | fn test_chinese_to_unsigned_integer_high() { 148 | macro_rules! test { 149 | ($expect:expr, $value:expr) => { 150 | assert_eq!( 151 | $expect, 152 | chinese_to_unsigned_integer(ChineseCountMethod::High, &to_chars_vec($value)) 153 | .unwrap() 154 | ); 155 | }; 156 | } 157 | 158 | test!(0, "零"); 159 | test!(1, "一"); 160 | test!(2, "貳"); 161 | test!(10, "十"); 162 | test!(11, "十一"); 163 | test!(20, "二十"); 164 | test!(100, "一百"); 165 | test!(101, "一百零一"); 166 | test!(110, "一百一十"); 167 | test!(111, "一百一十一"); 168 | test!(200, "兩百"); 169 | test!(1000, "一千"); 170 | test!(1001, "一千零一"); 171 | test!(1010, "一千零一十"); 172 | test!(1011, "一千零一十一"); 173 | test!(1100, "一千一百"); 174 | test!(1101, "一千一百零一"); 175 | test!(1110, "一千一百一十"); 176 | test!(2000, "二千"); 177 | test!(1_0000, "一萬"); 178 | test!(1_0001, "一萬零一"); 179 | test!(10_0000, "十萬"); 180 | test!(10_0100, "十萬零一百"); 181 | test!(1_0000_0000, "一億"); 182 | test!(1_0000_1000, "一億零一千"); 183 | test!(10_0000_0000, "十億"); 184 | test!(1_0000_0000_0000, "一萬億"); 185 | test!(1_0000_1000_0000, "一萬億零一千萬"); 186 | test!(10_0000_0000_0000, "十萬億"); 187 | test!(1_0000_0000_0000_0000, "一兆"); 188 | test!(1_0000_1000_0000_0000, "一兆零一千億"); 189 | test!(10_0000_0000_0000_0000, "十兆"); 190 | test!(1_0000_0000_0000_0000_0000, "一萬兆"); 191 | test!(1_0000_0000_0000_0000_0000_0000, "一億兆"); 192 | test!(1_0000_0000_0000_0000_0000_0000_0000, "一萬億兆"); 193 | test!(1_0000_0000_0000_0000_0000_0000_0000_0000, "一京"); 194 | test!(9_0000_0000_0000_0000_9000_0900_0090_0009, "九京零九千萬零九百億零九十萬零九"); 195 | } 196 | 197 | #[test] 198 | fn test_chinese_to_signed_integer_low() { 199 | macro_rules! test { 200 | ($expect:expr, $value:expr) => { 201 | assert_eq!( 202 | $expect, 203 | chinese_to_signed_integer(ChineseCountMethod::Low, &to_chars_vec($value)).unwrap() 204 | ); 205 | }; 206 | } 207 | 208 | test!(9000_0900_0090_0009, "九極零九穰零九億零九"); 209 | test!(-9000_0900_0090_0009, "負九極零九穰零九億零九"); 210 | } 211 | 212 | #[test] 213 | fn test_chinese_to_signed_integer_ten_thousand() { 214 | macro_rules! test { 215 | ($expect:expr, $value:expr) => { 216 | assert_eq!( 217 | $expect, 218 | chinese_to_signed_integer(ChineseCountMethod::TenThousand, &to_chars_vec($value)) 219 | .unwrap() 220 | ); 221 | }; 222 | } 223 | test!(9_9000_0900_0090_0009, "九京零九千萬零九百億零九十萬零九"); 224 | test!(-9_9000_0900_0090_0009, "負九京零九千萬零九百億零九十萬零九"); 225 | } 226 | 227 | #[test] 228 | fn test_chinese_to_signed_integer_middle() { 229 | macro_rules! test { 230 | ($expect:expr, $value:expr) => { 231 | assert_eq!( 232 | $expect, 233 | chinese_to_signed_integer(ChineseCountMethod::Middle, &to_chars_vec($value)) 234 | .unwrap() 235 | ); 236 | }; 237 | } 238 | 239 | test!(9_0000_0000_9000_0900_0090_0009, "九京零九千萬零九百億零九十萬零九"); 240 | test!(-9_0000_0000_9000_0900_0090_0009, "負九京零九千萬零九百億零九十萬零九"); 241 | } 242 | 243 | #[test] 244 | fn test_chinese_to_signed_integer_high() { 245 | macro_rules! test { 246 | ($expect:expr, $value:expr) => { 247 | assert_eq!( 248 | $expect, 249 | chinese_to_signed_integer(ChineseCountMethod::High, &to_chars_vec($value)).unwrap() 250 | ); 251 | }; 252 | } 253 | test!(9_0000_0000_0000_0000_9000_0900_0090_0009, "九京零九千萬零九百億零九十萬零九"); 254 | test!(-9_0000_0000_0000_0000_9000_0900_0090_0009, "負九京零九千萬零九百億零九十萬零九"); 255 | } 256 | 257 | // TODO f64 258 | 259 | #[test] 260 | fn test_chinese_to_f64_low() { 261 | macro_rules! test { 262 | ($expect:expr, $value:expr) => { 263 | assert_eq!( 264 | $expect, 265 | chinese_to_f64(ChineseCountMethod::Low, &to_chars_vec($value)).unwrap() 266 | ); 267 | }; 268 | } 269 | 270 | test!(0f64, "零"); 271 | test!(0.01f64, "一分"); 272 | test!(0.1f64, "一角"); 273 | test!(0.11f64, "一角一分"); 274 | test!(1f64, "一"); 275 | test!(1.23f64, "一二角三分"); 276 | test!(2f64, "貳"); 277 | test!(10f64, "十"); 278 | test!(11f64, "十一"); 279 | test!(20f64, "二十"); 280 | test!(100f64, "一百"); 281 | test!(101f64, "一百零一"); 282 | test!(110f64, "一百一十"); 283 | test!(111f64, "一百一十一"); 284 | test!(200f64, "兩百"); 285 | test!(1000f64, "一千"); 286 | test!(1001f64, "一千零一"); 287 | test!(1010f64, "一千零一十"); 288 | test!(1011f64, "一千零一十一"); 289 | test!(1100f64, "一千一百"); 290 | test!(1101f64, "一千一百零一"); 291 | test!(1110f64, "一千一百一十"); 292 | test!(2000f64, "二千"); 293 | test!(1_0000f64, "一萬"); 294 | test!(1_0001f64, "一萬零一"); 295 | test!(10_0000f64, "一億"); 296 | test!(10_0100f64, "一億零一百"); 297 | test!(1_0000_0000f64, "一垓"); 298 | test!(1_0000_1000f64, "一垓零一千"); 299 | test!(10_0000_0000f64, "一秭"); 300 | test!(1_0000_0000_0000f64, "一澗"); 301 | test!(1_0000_1000_0000f64, "一澗零一京"); 302 | test!(10_0000_0000_0000f64, "一正"); 303 | test!(1000_0000_0000_0000f64, "一極"); 304 | test!(1000_1000_0000_0000f64, "一極零一溝"); 305 | test!(-1000_1000_0000_0000f64, "負一極零一溝"); 306 | } 307 | 308 | #[test] 309 | fn test_chinese_to_f64_ten_thousand() { 310 | macro_rules! test { 311 | ($expect:expr, $value:expr) => { 312 | assert_eq!( 313 | $expect, 314 | chinese_to_f64(ChineseCountMethod::TenThousand, &to_chars_vec($value)).unwrap() 315 | ); 316 | }; 317 | } 318 | 319 | test!(0f64, "零"); 320 | test!(0.01f64, "一分"); 321 | test!(0.1f64, "一角"); 322 | test!(0.11f64, "一角一分"); 323 | test!(1f64, "一"); 324 | test!(1.23f64, "一二角三分"); 325 | test!(2f64, "貳"); 326 | test!(10f64, "十"); 327 | test!(11f64, "十一"); 328 | test!(20f64, "二十"); 329 | test!(100f64, "一百"); 330 | test!(101f64, "一百零一"); 331 | test!(110f64, "一百一十"); 332 | test!(111f64, "一百一十一"); 333 | test!(200f64, "兩百"); 334 | test!(1000f64, "一千"); 335 | test!(1001f64, "一千零一"); 336 | test!(1010f64, "一千零一十"); 337 | test!(1011f64, "一千零一十一"); 338 | test!(1100f64, "一千一百"); 339 | test!(1101f64, "一千一百零一"); 340 | test!(1110f64, "一千一百一十"); 341 | test!(2000f64, "二千"); 342 | test!(1_0000f64, "一萬"); 343 | test!(1_0001f64, "一萬零一"); 344 | test!(10_0000f64, "十萬"); 345 | test!(10_0100f64, "十萬零一百"); 346 | test!(1_0000_0000f64, "一億"); 347 | test!(1_0000_1000f64, "一億零一千"); 348 | test!(10_0000_0000f64, "十億"); 349 | test!(1_0000_0000_0000f64, "一兆"); 350 | test!(1_0000_1000_0000f64, "一兆零一千萬"); 351 | test!(10_0000_0000_0000f64, "十兆"); 352 | test!(1_0000_0000_0000_0000f64, "一京"); 353 | test!(1_0000_1000_0000_0000f64, "一京零一千億"); 354 | test!(-1_0000_1000_0000_0000f64, "負一京零一千億"); 355 | } 356 | 357 | #[test] 358 | fn test_chinese_to_f64_middle() { 359 | macro_rules! test { 360 | ($expect:expr, $value:expr) => { 361 | assert_eq!( 362 | $expect, 363 | chinese_to_f64(ChineseCountMethod::Middle, &to_chars_vec($value)).unwrap() 364 | ); 365 | }; 366 | } 367 | 368 | test!(0f64, "零"); 369 | test!(1f64, "一"); 370 | test!(2f64, "貳"); 371 | test!(10f64, "十"); 372 | test!(11f64, "十一"); 373 | test!(20f64, "二十"); 374 | test!(100f64, "一百"); 375 | test!(101f64, "一百零一"); 376 | test!(110f64, "一百一十"); 377 | test!(111f64, "一百一十一"); 378 | test!(200f64, "兩百"); 379 | test!(1000f64, "一千"); 380 | test!(1001f64, "一千零一"); 381 | test!(1010f64, "一千零一十"); 382 | test!(1011f64, "一千零一十一"); 383 | test!(1100f64, "一千一百"); 384 | test!(1101f64, "一千一百零一"); 385 | test!(1110f64, "一千一百一十"); 386 | test!(2000f64, "二千"); 387 | test!(1_0000f64, "一萬"); 388 | test!(1_0001f64, "一萬零一"); 389 | test!(10_0000f64, "十萬"); 390 | test!(10_0100f64, "十萬零一百"); 391 | test!(1_0000_0000f64, "一億"); 392 | test!(1_0000_1000f64, "一億零一千"); 393 | test!(10_0000_0000f64, "十億"); 394 | test!(1_0000_0000_0000f64, "一萬億"); 395 | test!(1_0000_1000_0000f64, "一萬億零一千萬"); 396 | test!(10_0000_0000_0000f64, "十萬億"); 397 | test!(1_0000_0000_0000_0000f64, "一兆"); 398 | test!(1_0000_1000_0000_0000f64, "一兆零一千億"); 399 | test!(10_0000_0000_0000_0000f64, "十兆"); 400 | test!(1_0000_0000_0000_0000_0000f64, "一萬兆"); 401 | test!(1_0000_0000_0000_0000_0000_0000f64, "一京"); 402 | test!(-1_0000_0000_0000_0000_0000_0000f64, "負一京"); 403 | } 404 | 405 | #[test] 406 | fn test_chinese_to_f64_high() { 407 | macro_rules! test { 408 | ($expect:expr, $value:expr) => { 409 | assert_eq!( 410 | $expect, 411 | chinese_to_f64(ChineseCountMethod::High, &to_chars_vec($value)).unwrap() 412 | ); 413 | }; 414 | } 415 | 416 | test!(0f64, "零"); 417 | test!(1f64, "一"); 418 | test!(2f64, "貳"); 419 | test!(10f64, "十"); 420 | test!(11f64, "十一"); 421 | test!(20f64, "二十"); 422 | test!(100f64, "一百"); 423 | test!(101f64, "一百零一"); 424 | test!(110f64, "一百一十"); 425 | test!(111f64, "一百一十一"); 426 | test!(200f64, "兩百"); 427 | test!(1000f64, "一千"); 428 | test!(1001f64, "一千零一"); 429 | test!(1010f64, "一千零一十"); 430 | test!(1011f64, "一千零一十一"); 431 | test!(1100f64, "一千一百"); 432 | test!(1101f64, "一千一百零一"); 433 | test!(1110f64, "一千一百一十"); 434 | test!(2000f64, "二千"); 435 | test!(1_0000f64, "一萬"); 436 | test!(1_0001f64, "一萬零一"); 437 | test!(10_0000f64, "十萬"); 438 | test!(10_0100f64, "十萬零一百"); 439 | test!(1_0000_0000f64, "一億"); 440 | test!(1_0000_1000f64, "一億零一千"); 441 | test!(10_0000_0000f64, "十億"); 442 | test!(1_0000_0000_0000f64, "一萬億"); 443 | test!(1_0000_1000_0000f64, "一萬億零一千萬"); 444 | test!(10_0000_0000_0000f64, "十萬億"); 445 | test!(1_0000_0000_0000_0000f64, "一兆"); 446 | test!(1_0000_1000_0000_0000f64, "一兆零一千億"); 447 | test!(10_0000_0000_0000_0000f64, "十兆"); 448 | test!(1_0000_0000_0000_0000_0000f64, "一萬兆"); 449 | test!(1_0000_0000_0000_0000_0000_0000f64, "一億兆"); 450 | test!(1_0000_0000_0000_0000_0000_0000_0000f64, "一萬億兆"); 451 | test!(1_0000_0000_0000_0000_0000_0000_0000_0000f64, "一京"); 452 | } 453 | -------------------------------------------------------------------------------- /src/chinese_to_number/mod.rs: -------------------------------------------------------------------------------- 1 | mod chinese_to_number_error; 2 | mod functions; 3 | mod naive; 4 | mod traits; 5 | 6 | mod functions_test; 7 | 8 | pub use chinese_to_number_error::*; 9 | use functions::*; 10 | pub use naive::*; 11 | pub use traits::*; 12 | 13 | use crate::ChineseCountMethod; 14 | 15 | /// 將中文數字轉成 `u8` 整數。 16 | #[inline] 17 | pub fn from_chinese_to_u8>(chinese_number: S) -> Result { 18 | let chars = to_chars_vec(chinese_number.as_ref()); 19 | 20 | let n = chinese_to_unsigned_integer(ChineseCountMethod::Low, &chars)?; 21 | 22 | if n > u8::MAX as u128 { 23 | return Err(ChineseToNumberError::Overflow); 24 | } 25 | 26 | Ok(n as u8) 27 | } 28 | 29 | /// 將中文數字轉成 `u16` 整數。 30 | #[inline] 31 | pub fn from_chinese_to_u16>(chinese_number: S) -> Result { 32 | let chars = to_chars_vec(chinese_number.as_ref()); 33 | 34 | let n = chinese_to_unsigned_integer(ChineseCountMethod::Low, &chars)?; 35 | 36 | if n > u16::MAX as u128 { 37 | return Err(ChineseToNumberError::Overflow); 38 | } 39 | 40 | Ok(n as u16) 41 | } 42 | 43 | /// 將中文數字轉成 `u32` 整數。使用 **「下數」**。 44 | #[inline] 45 | pub fn from_chinese_to_u32_low>( 46 | chinese_number: S, 47 | ) -> Result { 48 | let chars = to_chars_vec(chinese_number.as_ref()); 49 | 50 | let n = chinese_to_unsigned_integer(ChineseCountMethod::Low, &chars)?; 51 | 52 | if n > u32::MAX as u128 { 53 | return Err(ChineseToNumberError::Overflow); 54 | } 55 | 56 | Ok(n as u32) 57 | } 58 | 59 | /// 將中文數字轉成 `u32` 整數。使用 **「萬進」**。 60 | #[inline] 61 | pub fn from_chinese_to_u32_ten_thousand>( 62 | chinese_number: S, 63 | ) -> Result { 64 | let chars = to_chars_vec(chinese_number.as_ref()); 65 | 66 | let n = chinese_to_unsigned_integer(ChineseCountMethod::TenThousand, &chars)?; 67 | 68 | if n > u32::MAX as u128 { 69 | return Err(ChineseToNumberError::Overflow); 70 | } 71 | 72 | Ok(n as u32) 73 | } 74 | 75 | /// 將中文數字轉成 `u32` 整數。使用 **「中數」**。 76 | #[inline] 77 | pub fn from_chinese_to_u32_middle>( 78 | chinese_number: S, 79 | ) -> Result { 80 | let chars = to_chars_vec(chinese_number.as_ref()); 81 | 82 | let n = chinese_to_unsigned_integer(ChineseCountMethod::Middle, &chars)?; 83 | 84 | if n > u32::MAX as u128 { 85 | return Err(ChineseToNumberError::Overflow); 86 | } 87 | 88 | Ok(n as u32) 89 | } 90 | 91 | /// 將中文數字轉成 `u32` 整數。使用 **「上數」**。 92 | #[inline] 93 | pub fn from_chinese_to_u32_high>( 94 | chinese_number: S, 95 | ) -> Result { 96 | let chars = to_chars_vec(chinese_number.as_ref()); 97 | 98 | let n = chinese_to_unsigned_integer(ChineseCountMethod::High, &chars)?; 99 | 100 | if n > u32::MAX as u128 { 101 | return Err(ChineseToNumberError::Overflow); 102 | } 103 | 104 | Ok(n as u32) 105 | } 106 | 107 | /// 將中文數字轉成 `u64` 整數。使用 **「下數」**。 108 | #[inline] 109 | pub fn from_chinese_to_u64_low>( 110 | chinese_number: S, 111 | ) -> Result { 112 | let chars = to_chars_vec(chinese_number.as_ref()); 113 | 114 | let n = chinese_to_unsigned_integer(ChineseCountMethod::Low, &chars)?; 115 | 116 | if n > u64::MAX as u128 { 117 | return Err(ChineseToNumberError::Overflow); 118 | } 119 | 120 | Ok(n as u64) 121 | } 122 | 123 | /// 將中文數字轉成 `u64` 整數。使用 **「萬進」**。 124 | #[inline] 125 | pub fn from_chinese_to_u64_ten_thousand>( 126 | chinese_number: S, 127 | ) -> Result { 128 | let chars = to_chars_vec(chinese_number.as_ref()); 129 | 130 | let n = chinese_to_unsigned_integer(ChineseCountMethod::TenThousand, &chars)?; 131 | 132 | if n > u64::MAX as u128 { 133 | return Err(ChineseToNumberError::Overflow); 134 | } 135 | 136 | Ok(n as u64) 137 | } 138 | 139 | /// 將中文數字轉成 `u64` 整數。使用 **「中數」**。 140 | #[inline] 141 | pub fn from_chinese_to_u64_middle>( 142 | chinese_number: S, 143 | ) -> Result { 144 | let chars = to_chars_vec(chinese_number.as_ref()); 145 | 146 | let n = chinese_to_unsigned_integer(ChineseCountMethod::Middle, &chars)?; 147 | 148 | if n > u64::MAX as u128 { 149 | return Err(ChineseToNumberError::Overflow); 150 | } 151 | 152 | Ok(n as u64) 153 | } 154 | 155 | /// 將中文數字轉成 `u64` 整數。使用 **「上數」**。 156 | #[inline] 157 | pub fn from_chinese_to_u64_high>( 158 | chinese_number: S, 159 | ) -> Result { 160 | let chars = to_chars_vec(chinese_number.as_ref()); 161 | 162 | let n = chinese_to_unsigned_integer(ChineseCountMethod::High, &chars)?; 163 | 164 | if n > u64::MAX as u128 { 165 | return Err(ChineseToNumberError::Overflow); 166 | } 167 | 168 | Ok(n as u64) 169 | } 170 | 171 | /// 將中文數字轉成 `u128` 整數。使用 **「下數」**。 172 | #[inline] 173 | pub fn from_chinese_to_u128_low>( 174 | chinese_number: S, 175 | ) -> Result { 176 | let chars = to_chars_vec(chinese_number.as_ref()); 177 | 178 | chinese_to_unsigned_integer(ChineseCountMethod::Low, &chars) 179 | } 180 | 181 | /// 將中文數字轉成 `u128` 整數。使用 **「萬進」**。 182 | #[inline] 183 | pub fn from_chinese_to_u128_ten_thousand>( 184 | chinese_number: S, 185 | ) -> Result { 186 | let chars = to_chars_vec(chinese_number.as_ref()); 187 | 188 | chinese_to_unsigned_integer(ChineseCountMethod::TenThousand, &chars) 189 | } 190 | 191 | /// 將中文數字轉成 `u128` 整數。使用 **「中數」**。 192 | #[inline] 193 | pub fn from_chinese_to_u128_middle>( 194 | chinese_number: S, 195 | ) -> Result { 196 | let chars = to_chars_vec(chinese_number.as_ref()); 197 | 198 | chinese_to_unsigned_integer(ChineseCountMethod::Middle, &chars) 199 | } 200 | 201 | /// 將中文數字轉成 `u128` 整數。使用 **「上數」**。 202 | #[inline] 203 | pub fn from_chinese_to_u128_high>( 204 | chinese_number: S, 205 | ) -> Result { 206 | let chars = to_chars_vec(chinese_number.as_ref()); 207 | 208 | chinese_to_unsigned_integer(ChineseCountMethod::High, &chars) 209 | } 210 | 211 | /// 將中文數字轉成 `usize` 整數。使用 **「下數」**。 212 | #[inline] 213 | pub fn from_chinese_to_usize_low>( 214 | chinese_number: S, 215 | ) -> Result { 216 | let chars = to_chars_vec(chinese_number.as_ref()); 217 | 218 | let n = chinese_to_unsigned_integer(ChineseCountMethod::Low, &chars)?; 219 | 220 | if n > usize::MAX as u128 { 221 | return Err(ChineseToNumberError::Overflow); 222 | } 223 | 224 | Ok(n as usize) 225 | } 226 | 227 | /// 將中文數字轉成 `usize` 整數。使用 **「萬進」**。 228 | #[inline] 229 | pub fn from_chinese_to_usize_ten_thousand>( 230 | chinese_number: S, 231 | ) -> Result { 232 | let chars = to_chars_vec(chinese_number.as_ref()); 233 | 234 | let n = chinese_to_unsigned_integer(ChineseCountMethod::TenThousand, &chars)?; 235 | 236 | if n > usize::MAX as u128 { 237 | return Err(ChineseToNumberError::Overflow); 238 | } 239 | 240 | Ok(n as usize) 241 | } 242 | 243 | /// 將中文數字轉成 `usize` 整數。使用 **「中數」**。 244 | #[inline] 245 | pub fn from_chinese_to_usize_middle>( 246 | chinese_number: S, 247 | ) -> Result { 248 | let chars = to_chars_vec(chinese_number.as_ref()); 249 | 250 | let n = chinese_to_unsigned_integer(ChineseCountMethod::Middle, &chars)?; 251 | 252 | if n > usize::MAX as u128 { 253 | return Err(ChineseToNumberError::Overflow); 254 | } 255 | 256 | Ok(n as usize) 257 | } 258 | 259 | /// 將中文數字轉成 `usize` 整數。使用 **「上數」**。 260 | #[inline] 261 | pub fn from_chinese_to_usize_high>( 262 | chinese_number: S, 263 | ) -> Result { 264 | let chars = to_chars_vec(chinese_number.as_ref()); 265 | 266 | let n = chinese_to_unsigned_integer(ChineseCountMethod::High, &chars)?; 267 | 268 | if n > usize::MAX as u128 { 269 | return Err(ChineseToNumberError::Overflow); 270 | } 271 | 272 | Ok(n as usize) 273 | } 274 | 275 | /// 將中文數字轉成 `i8` 整數。 276 | #[inline] 277 | pub fn from_chinese_to_i8>(chinese_number: S) -> Result { 278 | let chars = to_chars_vec(chinese_number.as_ref()); 279 | 280 | let n = chinese_to_signed_integer(ChineseCountMethod::Low, &chars)?; 281 | 282 | if n > i8::MAX as i128 { 283 | return Err(ChineseToNumberError::Overflow); 284 | } else if n < i8::MIN as i128 { 285 | return Err(ChineseToNumberError::Underflow); 286 | } 287 | 288 | Ok(n as i8) 289 | } 290 | 291 | /// 將中文數字轉成 `i16` 整數。 292 | #[inline] 293 | pub fn from_chinese_to_i16>(chinese_number: S) -> Result { 294 | let chars = to_chars_vec(chinese_number.as_ref()); 295 | 296 | let n = chinese_to_signed_integer(ChineseCountMethod::Low, &chars)?; 297 | 298 | if n > i16::MAX as i128 { 299 | return Err(ChineseToNumberError::Overflow); 300 | } else if n < i16::MIN as i128 { 301 | return Err(ChineseToNumberError::Underflow); 302 | } 303 | 304 | Ok(n as i16) 305 | } 306 | 307 | /// 將中文數字轉成 `i32` 整數。使用 **「下數」**。 308 | #[inline] 309 | pub fn from_chinese_to_i32_low>( 310 | chinese_number: S, 311 | ) -> Result { 312 | let chars = to_chars_vec(chinese_number.as_ref()); 313 | 314 | let n = chinese_to_signed_integer(ChineseCountMethod::Low, &chars)?; 315 | 316 | if n > i32::MAX as i128 { 317 | return Err(ChineseToNumberError::Overflow); 318 | } else if n < i32::MIN as i128 { 319 | return Err(ChineseToNumberError::Underflow); 320 | } 321 | 322 | Ok(n as i32) 323 | } 324 | 325 | /// 將中文數字轉成 `i32` 整數。使用 **「萬進」**。 326 | #[inline] 327 | pub fn from_chinese_to_i32_ten_thousand>( 328 | chinese_number: S, 329 | ) -> Result { 330 | let chars = to_chars_vec(chinese_number.as_ref()); 331 | 332 | let n = chinese_to_signed_integer(ChineseCountMethod::TenThousand, &chars)?; 333 | 334 | if n > i32::MAX as i128 { 335 | return Err(ChineseToNumberError::Overflow); 336 | } else if n < i32::MIN as i128 { 337 | return Err(ChineseToNumberError::Underflow); 338 | } 339 | 340 | Ok(n as i32) 341 | } 342 | 343 | /// 將中文數字轉成 `i32` 整數。使用 **「中數」**。 344 | #[inline] 345 | pub fn from_chinese_to_i32_middle>( 346 | chinese_number: S, 347 | ) -> Result { 348 | let chars = to_chars_vec(chinese_number.as_ref()); 349 | 350 | let n = chinese_to_signed_integer(ChineseCountMethod::Middle, &chars)?; 351 | 352 | if n > i32::MAX as i128 { 353 | return Err(ChineseToNumberError::Overflow); 354 | } else if n < i32::MIN as i128 { 355 | return Err(ChineseToNumberError::Underflow); 356 | } 357 | 358 | Ok(n as i32) 359 | } 360 | 361 | /// 將中文數字轉成 `i32` 整數。使用 **「上數」**。 362 | #[inline] 363 | pub fn from_chinese_to_i32_high>( 364 | chinese_number: S, 365 | ) -> Result { 366 | let chars = to_chars_vec(chinese_number.as_ref()); 367 | 368 | let n = chinese_to_signed_integer(ChineseCountMethod::High, &chars)?; 369 | 370 | if n > i32::MAX as i128 { 371 | return Err(ChineseToNumberError::Overflow); 372 | } else if n < i32::MIN as i128 { 373 | return Err(ChineseToNumberError::Underflow); 374 | } 375 | 376 | Ok(n as i32) 377 | } 378 | 379 | /// 將中文數字轉成 `i64` 整數。使用 **「下數」**。 380 | #[inline] 381 | pub fn from_chinese_to_i64_low>( 382 | chinese_number: S, 383 | ) -> Result { 384 | let chars = to_chars_vec(chinese_number.as_ref()); 385 | 386 | let n = chinese_to_signed_integer(ChineseCountMethod::Low, &chars)?; 387 | 388 | if n > i64::MAX as i128 { 389 | return Err(ChineseToNumberError::Overflow); 390 | } else if n < i64::MIN as i128 { 391 | return Err(ChineseToNumberError::Underflow); 392 | } 393 | 394 | Ok(n as i64) 395 | } 396 | 397 | /// 將中文數字轉成 `i64` 整數。使用 **「萬進」**。 398 | #[inline] 399 | pub fn from_chinese_to_i64_ten_thousand>( 400 | chinese_number: S, 401 | ) -> Result { 402 | let chars = to_chars_vec(chinese_number.as_ref()); 403 | 404 | let n = chinese_to_signed_integer(ChineseCountMethod::TenThousand, &chars)?; 405 | 406 | if n > i64::MAX as i128 { 407 | return Err(ChineseToNumberError::Overflow); 408 | } else if n < i64::MIN as i128 { 409 | return Err(ChineseToNumberError::Underflow); 410 | } 411 | 412 | Ok(n as i64) 413 | } 414 | 415 | /// 將中文數字轉成 `i64` 整數。使用 **「中數」**。 416 | #[inline] 417 | pub fn from_chinese_to_i64_middle>( 418 | chinese_number: S, 419 | ) -> Result { 420 | let chars = to_chars_vec(chinese_number.as_ref()); 421 | 422 | let n = chinese_to_signed_integer(ChineseCountMethod::Middle, &chars)?; 423 | 424 | if n > i64::MAX as i128 { 425 | return Err(ChineseToNumberError::Overflow); 426 | } else if n < i64::MIN as i128 { 427 | return Err(ChineseToNumberError::Underflow); 428 | } 429 | 430 | Ok(n as i64) 431 | } 432 | 433 | /// 將中文數字轉成 `i64` 整數。使用 **「上數」**。 434 | #[inline] 435 | pub fn from_chinese_to_i64_high>( 436 | chinese_number: S, 437 | ) -> Result { 438 | let chars = to_chars_vec(chinese_number.as_ref()); 439 | 440 | let n = chinese_to_signed_integer(ChineseCountMethod::High, &chars)?; 441 | 442 | if n > i64::MAX as i128 { 443 | return Err(ChineseToNumberError::Overflow); 444 | } else if n < i64::MIN as i128 { 445 | return Err(ChineseToNumberError::Underflow); 446 | } 447 | 448 | Ok(n as i64) 449 | } 450 | 451 | /// 將中文數字轉成 `i128` 整數。使用 **「下數」**。 452 | #[inline] 453 | pub fn from_chinese_to_i128_low>( 454 | chinese_number: S, 455 | ) -> Result { 456 | let chars = to_chars_vec(chinese_number.as_ref()); 457 | 458 | chinese_to_signed_integer(ChineseCountMethod::Low, &chars) 459 | } 460 | 461 | /// 將中文數字轉成 `i128` 整數。使用 **「萬進」**。 462 | #[inline] 463 | pub fn from_chinese_to_i128_ten_thousand>( 464 | chinese_number: S, 465 | ) -> Result { 466 | let chars = to_chars_vec(chinese_number.as_ref()); 467 | 468 | chinese_to_signed_integer(ChineseCountMethod::TenThousand, &chars) 469 | } 470 | 471 | /// 將中文數字轉成 `i128` 整數。使用 **「中數」**。 472 | #[inline] 473 | pub fn from_chinese_to_i128_middle>( 474 | chinese_number: S, 475 | ) -> Result { 476 | let chars = to_chars_vec(chinese_number.as_ref()); 477 | 478 | chinese_to_signed_integer(ChineseCountMethod::Middle, &chars) 479 | } 480 | 481 | /// 將中文數字轉成 `i128` 整數。使用 **「上數」**。 482 | #[inline] 483 | pub fn from_chinese_to_i128_high>( 484 | chinese_number: S, 485 | ) -> Result { 486 | let chars = to_chars_vec(chinese_number.as_ref()); 487 | 488 | chinese_to_signed_integer(ChineseCountMethod::High, &chars) 489 | } 490 | 491 | /// 將中文數字轉成 `isize` 整數。使用 **「下數」**。 492 | #[inline] 493 | pub fn from_chinese_to_isize_low>( 494 | chinese_number: S, 495 | ) -> Result { 496 | let chars = to_chars_vec(chinese_number.as_ref()); 497 | 498 | let n = chinese_to_signed_integer(ChineseCountMethod::Low, &chars)?; 499 | 500 | if n > isize::MAX as i128 { 501 | return Err(ChineseToNumberError::Overflow); 502 | } else if n < isize::MIN as i128 { 503 | return Err(ChineseToNumberError::Underflow); 504 | } 505 | 506 | Ok(n as isize) 507 | } 508 | 509 | /// 將中文數字轉成 `isize` 整數。使用 **「萬進」**。 510 | #[inline] 511 | pub fn from_chinese_to_isize_ten_thousand>( 512 | chinese_number: S, 513 | ) -> Result { 514 | let chars = to_chars_vec(chinese_number.as_ref()); 515 | 516 | let n = chinese_to_signed_integer(ChineseCountMethod::TenThousand, &chars)?; 517 | 518 | if n > isize::MAX as i128 { 519 | return Err(ChineseToNumberError::Overflow); 520 | } else if n < isize::MIN as i128 { 521 | return Err(ChineseToNumberError::Underflow); 522 | } 523 | 524 | Ok(n as isize) 525 | } 526 | 527 | /// 將中文數字轉成 `isize` 整數。使用 **「中數」**。 528 | #[inline] 529 | pub fn from_chinese_to_isize_middle>( 530 | chinese_number: S, 531 | ) -> Result { 532 | let chars = to_chars_vec(chinese_number.as_ref()); 533 | 534 | let n = chinese_to_signed_integer(ChineseCountMethod::Middle, &chars)?; 535 | 536 | if n > isize::MAX as i128 { 537 | return Err(ChineseToNumberError::Overflow); 538 | } else if n < isize::MIN as i128 { 539 | return Err(ChineseToNumberError::Underflow); 540 | } 541 | 542 | Ok(n as isize) 543 | } 544 | 545 | /// 將中文數字轉成 `isize` 整數。使用 **「上數」**。 546 | #[inline] 547 | pub fn from_chinese_to_isize_high>( 548 | chinese_number: S, 549 | ) -> Result { 550 | let chars = to_chars_vec(chinese_number.as_ref()); 551 | 552 | let n = chinese_to_signed_integer(ChineseCountMethod::High, &chars)?; 553 | 554 | if n > isize::MAX as i128 { 555 | return Err(ChineseToNumberError::Overflow); 556 | } else if n < isize::MIN as i128 { 557 | return Err(ChineseToNumberError::Underflow); 558 | } 559 | 560 | Ok(n as isize) 561 | } 562 | 563 | /// 將中文數字轉成 `f32` 浮點數。使用 **「下數」**。 564 | #[inline] 565 | pub fn from_chinese_to_f32_low>( 566 | chinese_number: S, 567 | ) -> Result { 568 | let chars = to_chars_vec(chinese_number.as_ref()); 569 | 570 | chinese_to_f64(ChineseCountMethod::Low, &chars).map(|f| f as f32) 571 | } 572 | 573 | /// 將中文數字轉成 `f32` 浮點數。使用 **「萬進」**。 574 | #[inline] 575 | pub fn from_chinese_to_f32_ten_thousand>( 576 | chinese_number: S, 577 | ) -> Result { 578 | let chars = to_chars_vec(chinese_number.as_ref()); 579 | 580 | chinese_to_f64(ChineseCountMethod::TenThousand, &chars).map(|f| f as f32) 581 | } 582 | 583 | /// 將中文數字轉成 `f32` 浮點數。使用 **「中數」**。 584 | #[inline] 585 | pub fn from_chinese_to_f32_middle>( 586 | chinese_number: S, 587 | ) -> Result { 588 | let chars = to_chars_vec(chinese_number.as_ref()); 589 | 590 | chinese_to_f64(ChineseCountMethod::Middle, &chars).map(|f| f as f32) 591 | } 592 | 593 | /// 將中文數字轉成 `f32` 浮點數。使用 **「上數」**。 594 | #[inline] 595 | pub fn from_chinese_to_f32_high>( 596 | chinese_number: S, 597 | ) -> Result { 598 | let chars = to_chars_vec(chinese_number.as_ref()); 599 | 600 | chinese_to_f64(ChineseCountMethod::High, &chars).map(|f| f as f32) 601 | } 602 | 603 | /// 將中文數字轉成 `f64` 浮點數。使用 **「下數」**。 604 | #[inline] 605 | pub fn from_chinese_to_f64_low>( 606 | chinese_number: S, 607 | ) -> Result { 608 | let chars = to_chars_vec(chinese_number.as_ref()); 609 | 610 | chinese_to_f64(ChineseCountMethod::Low, &chars) 611 | } 612 | 613 | /// 將中文數字轉成 `f64` 浮點數。使用 **「萬進」**。 614 | #[inline] 615 | pub fn from_chinese_to_f64_ten_thousand>( 616 | chinese_number: S, 617 | ) -> Result { 618 | let chars = to_chars_vec(chinese_number.as_ref()); 619 | 620 | chinese_to_f64(ChineseCountMethod::TenThousand, &chars) 621 | } 622 | 623 | /// 將中文數字轉成 `f64` 浮點數。使用 **「中數」**。 624 | #[inline] 625 | pub fn from_chinese_to_f64_middle>( 626 | chinese_number: S, 627 | ) -> Result { 628 | let chars = to_chars_vec(chinese_number.as_ref()); 629 | 630 | chinese_to_f64(ChineseCountMethod::Middle, &chars) 631 | } 632 | 633 | /// 將中文數字轉成 `f64` 浮點數。使用 **「上數」**。 634 | #[inline] 635 | pub fn from_chinese_to_f64_high>( 636 | chinese_number: S, 637 | ) -> Result { 638 | let chars = to_chars_vec(chinese_number.as_ref()); 639 | 640 | chinese_to_f64(ChineseCountMethod::High, &chars) 641 | } 642 | -------------------------------------------------------------------------------- /src/chinese_to_number/naive.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(feature = "std"))] 2 | #[allow(unused_imports)] 3 | use num_traits::float::FloatCore; 4 | 5 | use super::to_chars_vec; 6 | use crate::{ 7 | chinese_characters::{ChineseNumber, ChinesePoint, ChineseSign}, 8 | ChineseToNumberError, 9 | }; 10 | 11 | fn chinese_to_unsigned_integer(chars: &[char]) -> Result { 12 | let length = chars.len(); 13 | 14 | if length == 0 { 15 | return Err(ChineseToNumberError::ChineseNumberEmpty); 16 | } 17 | 18 | let mut sum = 0u128; 19 | 20 | for (char_index, &char) in chars.iter().enumerate() { 21 | let d = match ChineseNumber::from_char(char) { 22 | Some(cn) if cn != ChineseNumber::十 => cn.ordinal() as u128, 23 | _ => { 24 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 25 | char_index, 26 | }); 27 | }, 28 | }; 29 | 30 | sum = sum.checked_mul(10).ok_or(ChineseToNumberError::Overflow)?; 31 | 32 | sum = sum.checked_add(d).ok_or(ChineseToNumberError::Overflow)?; 33 | } 34 | 35 | Ok(sum) 36 | } 37 | 38 | fn chinese_to_signed_integer(chars: &[char]) -> Result { 39 | let length = chars.len(); 40 | 41 | if length == 0 { 42 | return Err(ChineseToNumberError::ChineseNumberEmpty); 43 | } 44 | 45 | let c = chars[0]; 46 | 47 | let (sign, offset) = match ChineseSign::from_char(c) { 48 | Some(sign) => (sign, 1), 49 | None => (ChineseSign::正, 0), 50 | }; 51 | 52 | let uint = match chinese_to_unsigned_integer(&chars[offset..]) { 53 | Ok(n) => n, 54 | Err(error) => { 55 | return match error { 56 | ChineseToNumberError::ChineseNumberIncorrect { 57 | char_index: index, 58 | } => Err(ChineseToNumberError::ChineseNumberIncorrect { 59 | char_index: index + offset, 60 | }), 61 | ChineseToNumberError::Overflow if sign == ChineseSign::負 => { 62 | Err(ChineseToNumberError::Underflow) 63 | }, 64 | _ => Err(error), 65 | }; 66 | }, 67 | }; 68 | 69 | match sign { 70 | ChineseSign::正 => { 71 | if uint > i128::MAX as u128 { 72 | return Err(ChineseToNumberError::Overflow); 73 | } 74 | 75 | Ok(uint as i128) 76 | }, 77 | ChineseSign::負 => { 78 | let m = i128::MAX as u128 + 1; 79 | 80 | if uint > m { 81 | return Err(ChineseToNumberError::Underflow); 82 | } 83 | 84 | if uint == m { 85 | Ok(i128::MIN) 86 | } else { 87 | Ok(-(uint as i128)) 88 | } 89 | }, 90 | } 91 | } 92 | 93 | /// 將中文數字轉成 `u8` 整數。不進行單位計算。 94 | #[inline] 95 | pub fn from_chinese_to_u8_naive>( 96 | chinese_number: S, 97 | ) -> Result { 98 | let chars = to_chars_vec(chinese_number.as_ref()); 99 | 100 | let n = chinese_to_unsigned_integer(&chars)?; 101 | 102 | if n > u8::MAX as u128 { 103 | return Err(ChineseToNumberError::Overflow); 104 | } 105 | 106 | Ok(n as u8) 107 | } 108 | 109 | /// 將中文數字轉成 `u16` 整數。不進行單位計算。 110 | #[inline] 111 | pub fn from_chinese_to_u16_naive>( 112 | chinese_number: S, 113 | ) -> Result { 114 | let chars = to_chars_vec(chinese_number.as_ref()); 115 | 116 | let n = chinese_to_unsigned_integer(&chars)?; 117 | 118 | if n > u16::MAX as u128 { 119 | return Err(ChineseToNumberError::Overflow); 120 | } 121 | 122 | Ok(n as u16) 123 | } 124 | 125 | /// 將中文數字轉成 `u32` 整數。不進行單位計算。 126 | #[inline] 127 | pub fn from_chinese_to_u32_naive>( 128 | chinese_number: S, 129 | ) -> Result { 130 | let chars = to_chars_vec(chinese_number.as_ref()); 131 | 132 | let n = chinese_to_unsigned_integer(&chars)?; 133 | 134 | if n > u32::MAX as u128 { 135 | return Err(ChineseToNumberError::Overflow); 136 | } 137 | 138 | Ok(n as u32) 139 | } 140 | 141 | /// 將中文數字轉成 `u64` 整數。不進行單位計算。 142 | #[inline] 143 | pub fn from_chinese_to_u64_naive>( 144 | chinese_number: S, 145 | ) -> Result { 146 | let chars = to_chars_vec(chinese_number.as_ref()); 147 | 148 | let n = chinese_to_unsigned_integer(&chars)?; 149 | 150 | if n > u64::MAX as u128 { 151 | return Err(ChineseToNumberError::Overflow); 152 | } 153 | 154 | Ok(n as u64) 155 | } 156 | 157 | /// 將中文數字轉成 `u128` 整數。不進行單位計算。 158 | #[inline] 159 | pub fn from_chinese_to_u128_naive>( 160 | chinese_number: S, 161 | ) -> Result { 162 | let chars = to_chars_vec(chinese_number.as_ref()); 163 | 164 | chinese_to_unsigned_integer(&chars) 165 | } 166 | 167 | /// 將中文數字轉成 `usize` 整數。不進行單位計算。 168 | #[inline] 169 | pub fn from_chinese_to_usize_naive>( 170 | chinese_number: S, 171 | ) -> Result { 172 | let chars = to_chars_vec(chinese_number.as_ref()); 173 | 174 | let n = chinese_to_unsigned_integer(&chars)?; 175 | 176 | if n > usize::MAX as u128 { 177 | return Err(ChineseToNumberError::Overflow); 178 | } 179 | 180 | Ok(n as usize) 181 | } 182 | 183 | /// 將中文數字轉成 `i8` 整數。不進行單位計算。 184 | #[inline] 185 | pub fn from_chinese_to_i8_naive>( 186 | chinese_number: S, 187 | ) -> Result { 188 | let chars = to_chars_vec(chinese_number.as_ref()); 189 | 190 | let n = chinese_to_signed_integer(&chars)?; 191 | 192 | if n > i8::MAX as i128 { 193 | return Err(ChineseToNumberError::Overflow); 194 | } else if n < i8::MIN as i128 { 195 | return Err(ChineseToNumberError::Underflow); 196 | } 197 | 198 | Ok(n as i8) 199 | } 200 | 201 | /// 將中文數字轉成 `i16` 整數。不進行單位計算。 202 | #[inline] 203 | pub fn from_chinese_to_i16_naive>( 204 | chinese_number: S, 205 | ) -> Result { 206 | let chars = to_chars_vec(chinese_number.as_ref()); 207 | 208 | let n = chinese_to_signed_integer(&chars)?; 209 | 210 | if n > i16::MAX as i128 { 211 | return Err(ChineseToNumberError::Overflow); 212 | } else if n < i16::MIN as i128 { 213 | return Err(ChineseToNumberError::Underflow); 214 | } 215 | 216 | Ok(n as i16) 217 | } 218 | 219 | /// 將中文數字轉成 `i32` 整數。不進行單位計算。 220 | #[inline] 221 | pub fn from_chinese_to_i32_naive>( 222 | chinese_number: S, 223 | ) -> Result { 224 | let chars = to_chars_vec(chinese_number.as_ref()); 225 | 226 | let n = chinese_to_signed_integer(&chars)?; 227 | 228 | if n > i32::MAX as i128 { 229 | return Err(ChineseToNumberError::Overflow); 230 | } else if n < i32::MIN as i128 { 231 | return Err(ChineseToNumberError::Underflow); 232 | } 233 | 234 | Ok(n as i32) 235 | } 236 | 237 | /// 將中文數字轉成 `i64` 整數。不進行單位計算。 238 | #[inline] 239 | pub fn from_chinese_to_i64_naive>( 240 | chinese_number: S, 241 | ) -> Result { 242 | let chars = to_chars_vec(chinese_number.as_ref()); 243 | 244 | let n = chinese_to_signed_integer(&chars)?; 245 | 246 | if n > i64::MAX as i128 { 247 | return Err(ChineseToNumberError::Overflow); 248 | } else if n < i64::MIN as i128 { 249 | return Err(ChineseToNumberError::Underflow); 250 | } 251 | 252 | Ok(n as i64) 253 | } 254 | 255 | /// 將中文數字轉成 `i128` 整數。不進行單位計算。 256 | #[inline] 257 | pub fn from_chinese_to_i128_naive>( 258 | chinese_number: S, 259 | ) -> Result { 260 | let chars = to_chars_vec(chinese_number.as_ref()); 261 | 262 | chinese_to_signed_integer(&chars) 263 | } 264 | 265 | /// 將中文數字轉成 `isize` 整數。不進行單位計算。 266 | #[inline] 267 | pub fn from_chinese_to_isize_naive>( 268 | chinese_number: S, 269 | ) -> Result { 270 | let chars = to_chars_vec(chinese_number.as_ref()); 271 | 272 | let n = chinese_to_signed_integer(&chars)?; 273 | 274 | if n > isize::MAX as i128 { 275 | return Err(ChineseToNumberError::Overflow); 276 | } else if n < isize::MIN as i128 { 277 | return Err(ChineseToNumberError::Underflow); 278 | } 279 | 280 | Ok(n as isize) 281 | } 282 | 283 | // TODO f64 284 | 285 | fn chinese_to_f64(chars: &[char]) -> Result { 286 | let length = chars.len(); 287 | 288 | if length == 0 { 289 | return Err(ChineseToNumberError::ChineseNumberEmpty); 290 | } 291 | 292 | let (sign, offset) = match ChineseSign::from_char(chars[0]) { 293 | Some(sign) => (sign, 1), 294 | None => (ChineseSign::正, 0), 295 | }; 296 | 297 | let mut sum = 0f64; 298 | 299 | let mut iter = chars[offset..].iter().enumerate(); 300 | 301 | for (i, &char) in iter.by_ref() { 302 | let d = match ChineseNumber::from_char(char) { 303 | Some(cn) if cn != ChineseNumber::十 => cn.ordinal() as f64, 304 | _ => match ChinesePoint::from_char(char) { 305 | Some(_) => break, 306 | None => { 307 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 308 | char_index: i + offset, 309 | }) 310 | }, 311 | }, 312 | }; 313 | 314 | sum *= 10.0; 315 | 316 | sum += d; 317 | } 318 | 319 | let mut c = 1i32; 320 | 321 | for (i, &char) in iter { 322 | let d = match ChineseNumber::from_char(char) { 323 | Some(cn) if cn != ChineseNumber::十 => cn.ordinal() as f64, 324 | _ => { 325 | return Err(ChineseToNumberError::ChineseNumberIncorrect { 326 | char_index: i + offset 327 | }) 328 | }, 329 | }; 330 | 331 | sum += d * 0.1f64.powi(c); 332 | c += 1; 333 | } 334 | 335 | match sign { 336 | ChineseSign::正 => Ok(sum), 337 | ChineseSign::負 => Ok(-sum), 338 | } 339 | } 340 | 341 | /// 將中文數字轉成 `f32` 浮點數。不進行單位計算。 342 | #[inline] 343 | pub fn from_chinese_to_f32_naive>( 344 | chinese_number: S, 345 | ) -> Result { 346 | let chars = to_chars_vec(chinese_number.as_ref()); 347 | 348 | chinese_to_f64(&chars).map(|f| f as f32) 349 | } 350 | 351 | /// 將中文數字轉成 `f64` 浮點數。不進行單位計算。 352 | #[inline] 353 | pub fn from_chinese_to_f64_naive>( 354 | chinese_number: S, 355 | ) -> Result { 356 | let chars = to_chars_vec(chinese_number.as_ref()); 357 | 358 | chinese_to_f64(&chars) 359 | } 360 | -------------------------------------------------------------------------------- /src/chinese_to_number/traits.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | /// 讓 Rust 程式語言的字串型別擁有將中文數字轉成數值的能力。 4 | pub trait ChineseToNumber { 5 | /// 將中文數字轉成數值。 6 | /// 7 | /// ## 範例 8 | /// 9 | /// ```rust 10 | /// use chinese_number::{ChineseCountMethod, ChineseToNumber}; 11 | /// 12 | /// assert_eq!(1234567890123456789u64, "一百二十三京四千五百六十七兆八千九百零一億二千三百四十五萬六千七百八十九".to_number(ChineseCountMethod::TenThousand).unwrap()); 13 | /// ``` 14 | fn to_number(&self, method: ChineseCountMethod) -> Result; 15 | 16 | /// 將中文數字直接轉成數值,不進行單位計算。 17 | /// 18 | /// ## 範例 19 | /// 20 | /// ```rust 21 | /// use chinese_number::{ChineseCountMethod, ChineseToNumber}; 22 | /// 23 | /// assert_eq!(123456789u64, "一二三四五六七八九".to_number_naive().unwrap()); 24 | /// ``` 25 | fn to_number_naive(&self) -> Result; 26 | } 27 | 28 | impl> ChineseToNumber for T { 29 | #[inline] 30 | fn to_number(&self, _method: ChineseCountMethod) -> Result { 31 | from_chinese_to_u8(self) 32 | } 33 | 34 | #[inline] 35 | fn to_number_naive(&self) -> Result { 36 | from_chinese_to_u8_naive(self) 37 | } 38 | } 39 | 40 | impl> ChineseToNumber for T { 41 | #[inline] 42 | fn to_number(&self, _method: ChineseCountMethod) -> Result { 43 | from_chinese_to_u16(self) 44 | } 45 | 46 | #[inline] 47 | fn to_number_naive(&self) -> Result { 48 | from_chinese_to_u16_naive(self) 49 | } 50 | } 51 | 52 | impl> ChineseToNumber for T { 53 | #[inline] 54 | fn to_number(&self, method: ChineseCountMethod) -> Result { 55 | match method { 56 | ChineseCountMethod::Low => from_chinese_to_u32_low(self), 57 | ChineseCountMethod::TenThousand => from_chinese_to_u32_ten_thousand(self), 58 | ChineseCountMethod::Middle => from_chinese_to_u32_middle(self), 59 | ChineseCountMethod::High => from_chinese_to_u32_high(self), 60 | } 61 | } 62 | 63 | #[inline] 64 | fn to_number_naive(&self) -> Result { 65 | from_chinese_to_u32_naive(self) 66 | } 67 | } 68 | 69 | impl> ChineseToNumber for T { 70 | #[inline] 71 | fn to_number(&self, method: ChineseCountMethod) -> Result { 72 | match method { 73 | ChineseCountMethod::Low => from_chinese_to_u64_low(self), 74 | ChineseCountMethod::TenThousand => from_chinese_to_u64_ten_thousand(self), 75 | ChineseCountMethod::Middle => from_chinese_to_u64_middle(self), 76 | ChineseCountMethod::High => from_chinese_to_u64_high(self), 77 | } 78 | } 79 | 80 | #[inline] 81 | fn to_number_naive(&self) -> Result { 82 | from_chinese_to_u64_naive(self) 83 | } 84 | } 85 | 86 | impl> ChineseToNumber for T { 87 | #[inline] 88 | fn to_number(&self, method: ChineseCountMethod) -> Result { 89 | match method { 90 | ChineseCountMethod::Low => from_chinese_to_u128_low(self), 91 | ChineseCountMethod::TenThousand => from_chinese_to_u128_ten_thousand(self), 92 | ChineseCountMethod::Middle => from_chinese_to_u128_middle(self), 93 | ChineseCountMethod::High => from_chinese_to_u128_high(self), 94 | } 95 | } 96 | 97 | #[inline] 98 | fn to_number_naive(&self) -> Result { 99 | from_chinese_to_u128_naive(self) 100 | } 101 | } 102 | 103 | impl> ChineseToNumber for T { 104 | #[inline] 105 | fn to_number(&self, method: ChineseCountMethod) -> Result { 106 | match method { 107 | ChineseCountMethod::Low => from_chinese_to_usize_low(self), 108 | ChineseCountMethod::TenThousand => from_chinese_to_usize_ten_thousand(self), 109 | ChineseCountMethod::Middle => from_chinese_to_usize_middle(self), 110 | ChineseCountMethod::High => from_chinese_to_usize_high(self), 111 | } 112 | } 113 | 114 | #[inline] 115 | fn to_number_naive(&self) -> Result { 116 | from_chinese_to_usize_naive(self) 117 | } 118 | } 119 | 120 | impl> ChineseToNumber for T { 121 | #[inline] 122 | fn to_number(&self, _method: ChineseCountMethod) -> Result { 123 | from_chinese_to_i8(self) 124 | } 125 | 126 | #[inline] 127 | fn to_number_naive(&self) -> Result { 128 | from_chinese_to_i8_naive(self) 129 | } 130 | } 131 | 132 | impl> ChineseToNumber for T { 133 | #[inline] 134 | fn to_number(&self, _method: ChineseCountMethod) -> Result { 135 | from_chinese_to_i16(self) 136 | } 137 | 138 | #[inline] 139 | fn to_number_naive(&self) -> Result { 140 | from_chinese_to_i16_naive(self) 141 | } 142 | } 143 | 144 | impl> ChineseToNumber for T { 145 | #[inline] 146 | fn to_number(&self, method: ChineseCountMethod) -> Result { 147 | match method { 148 | ChineseCountMethod::Low => from_chinese_to_i32_low(self), 149 | ChineseCountMethod::TenThousand => from_chinese_to_i32_ten_thousand(self), 150 | ChineseCountMethod::Middle => from_chinese_to_i32_middle(self), 151 | ChineseCountMethod::High => from_chinese_to_i32_high(self), 152 | } 153 | } 154 | 155 | #[inline] 156 | fn to_number_naive(&self) -> Result { 157 | from_chinese_to_i32_naive(self) 158 | } 159 | } 160 | 161 | impl> ChineseToNumber for T { 162 | #[inline] 163 | fn to_number(&self, method: ChineseCountMethod) -> Result { 164 | match method { 165 | ChineseCountMethod::Low => from_chinese_to_i64_low(self), 166 | ChineseCountMethod::TenThousand => from_chinese_to_i64_ten_thousand(self), 167 | ChineseCountMethod::Middle => from_chinese_to_i64_middle(self), 168 | ChineseCountMethod::High => from_chinese_to_i64_high(self), 169 | } 170 | } 171 | 172 | #[inline] 173 | fn to_number_naive(&self) -> Result { 174 | from_chinese_to_i64_naive(self) 175 | } 176 | } 177 | 178 | impl> ChineseToNumber for T { 179 | #[inline] 180 | fn to_number(&self, method: ChineseCountMethod) -> Result { 181 | match method { 182 | ChineseCountMethod::Low => from_chinese_to_i128_low(self), 183 | ChineseCountMethod::TenThousand => from_chinese_to_i128_ten_thousand(self), 184 | ChineseCountMethod::Middle => from_chinese_to_i128_middle(self), 185 | ChineseCountMethod::High => from_chinese_to_i128_high(self), 186 | } 187 | } 188 | 189 | #[inline] 190 | fn to_number_naive(&self) -> Result { 191 | from_chinese_to_i128_naive(self) 192 | } 193 | } 194 | 195 | impl> ChineseToNumber for T { 196 | #[inline] 197 | fn to_number(&self, method: ChineseCountMethod) -> Result { 198 | match method { 199 | ChineseCountMethod::Low => from_chinese_to_isize_low(self), 200 | ChineseCountMethod::TenThousand => from_chinese_to_isize_ten_thousand(self), 201 | ChineseCountMethod::Middle => from_chinese_to_isize_middle(self), 202 | ChineseCountMethod::High => from_chinese_to_isize_high(self), 203 | } 204 | } 205 | 206 | #[inline] 207 | fn to_number_naive(&self) -> Result { 208 | from_chinese_to_isize_naive(self) 209 | } 210 | } 211 | 212 | impl> ChineseToNumber for T { 213 | #[inline] 214 | fn to_number(&self, method: ChineseCountMethod) -> Result { 215 | match method { 216 | ChineseCountMethod::Low => from_chinese_to_f32_low(self), 217 | ChineseCountMethod::TenThousand => from_chinese_to_f32_ten_thousand(self), 218 | ChineseCountMethod::Middle => from_chinese_to_f32_middle(self), 219 | ChineseCountMethod::High => from_chinese_to_f32_high(self), 220 | } 221 | } 222 | 223 | #[inline] 224 | fn to_number_naive(&self) -> Result { 225 | from_chinese_to_f32_naive(self) 226 | } 227 | } 228 | 229 | impl> ChineseToNumber for T { 230 | #[inline] 231 | fn to_number(&self, method: ChineseCountMethod) -> Result { 232 | match method { 233 | ChineseCountMethod::Low => from_chinese_to_f64_low(self), 234 | ChineseCountMethod::TenThousand => from_chinese_to_f64_ten_thousand(self), 235 | ChineseCountMethod::Middle => from_chinese_to_f64_middle(self), 236 | ChineseCountMethod::High => from_chinese_to_f64_high(self), 237 | } 238 | } 239 | 240 | #[inline] 241 | fn to_number_naive(&self) -> Result { 242 | from_chinese_to_f64_naive(self) 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | # Chinese Number 3 | 4 | Convert primitive numbers to Chinese numbers, or parse Chinese numbers to primitive numbers. 5 | 6 | This crate can convert Rust's primitive number data types to Chinese numbers as strings. For example, **123** can be converted into **一二三**, **一百二十三** or **壹佰貳拾參**. It supports both Traditional Chinese and Simple Chinese, and it supports different methods to count the scale as well. Also, Chinese numbers in strings can be parsed to primitive number data types. 7 | 8 | ## Example 9 | 10 | ```rust 11 | # #[cfg(all(feature = "number-to-chinese", feature = "chinese-to-number"))] 12 | # { 13 | use chinese_number::{ChineseCase, ChineseCountMethod, ChineseVariant, NumberToChinese, ChineseToNumber}; 14 | 15 | assert_eq!("一二三", 123i8.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower)); 16 | 17 | assert_eq!("壹佰貳拾參", 123i8.to_chinese(ChineseVariant::Traditional, ChineseCase::Upper, ChineseCountMethod::TenThousand).unwrap()); 18 | assert_eq!("壹佰贰拾叁", 123i8.to_chinese(ChineseVariant::Simple, ChineseCase::Upper, ChineseCountMethod::TenThousand).unwrap()); 19 | 20 | assert_eq!("一百二十三", 123i8.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::TenThousand).unwrap()); 21 | 22 | assert_eq!("一極二載三正四澗五溝六穰七秭八垓九京零一億二萬三千四百五十六", 1234567890123456i64.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::Low).unwrap()); 23 | assert_eq!("十二穰三千四百五十六秭七千八百九十垓一千二百三十四京五千六百七十八兆九千零一十二億三千四百五十六萬七千八百九十", 123456789012345678901234567890i128.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::TenThousand).unwrap()); 24 | assert_eq!("十二萬三千四百五十六京七千八百九十萬一千二百三十四兆五千六百七十八萬九千零一十二億三千四百五十六萬七千八百九十", 123456789012345678901234567890i128.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::Middle).unwrap()); 25 | assert_eq!("十二萬三千四百五十六億七千八百九十萬一千二百三十四兆五千六百七十八萬九千零一十二億三千四百五十六萬七千八百九十", 123456789012345678901234567890i128.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::High).unwrap()); 26 | 27 | assert_eq!("一角二分", 0.12f64.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::TenThousand).unwrap()); 28 | 29 | assert_eq!(123i8, "一二三".to_number_naive().unwrap()); 30 | 31 | assert_eq!(123i8, "一百二十三".to_number(ChineseCountMethod::TenThousand).unwrap()); 32 | assert_eq!(-30303i16, "負三萬零三百零三".to_number(ChineseCountMethod::TenThousand).unwrap()); 33 | assert_eq!(3212345678u32, "三十二億一千二百三十四萬五千六百七十八".to_number(ChineseCountMethod::TenThousand).unwrap()); 34 | assert_eq!(10010001001001001000u64, "一千零一京零一兆零一十億零一百萬一千".to_number(ChineseCountMethod::TenThousand).unwrap()); 35 | 36 | assert_eq!(1000000u64, "一兆".to_number(ChineseCountMethod::Low).unwrap()); 37 | assert_eq!(1000000000000u64, "一兆".to_number(ChineseCountMethod::TenThousand).unwrap()); 38 | assert_eq!(10000000000000000u64, "一兆".to_number(ChineseCountMethod::Middle).unwrap()); 39 | assert_eq!(10000000000000000u64, "一兆".to_number(ChineseCountMethod::High).unwrap()); 40 | 41 | assert_eq!(120u64, "一百二".to_number(ChineseCountMethod::TenThousand).unwrap()); 42 | assert_eq!(2300u64, "兩千三".to_number(ChineseCountMethod::TenThousand).unwrap()); 43 | assert_eq!(34000u64, "三萬四".to_number(ChineseCountMethod::TenThousand).unwrap()); 44 | assert_eq!(105000u64, "十萬五".to_number(ChineseCountMethod::TenThousand).unwrap()); 45 | assert_eq!(150000000u64, "一億五".to_number(ChineseCountMethod::TenThousand).unwrap()); 46 | # } 47 | ``` 48 | 49 | ## No Std 50 | 51 | Disable the default features to compile this crate without std. 52 | 53 | ```toml 54 | [dependencies.chinese-number] 55 | version = "*" 56 | default-features = false 57 | features = ["number-to-chinese", "chinese-to-number"] 58 | ``` 59 | */ 60 | 61 | #![cfg_attr(not(feature = "std"), no_std)] 62 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 63 | 64 | extern crate alloc; 65 | 66 | #[cfg(feature = "number-to-chinese")] 67 | mod number_to_chinese; 68 | 69 | #[cfg(feature = "chinese-to-number")] 70 | mod chinese_to_number; 71 | 72 | mod chinese_case; 73 | #[cfg(any(feature = "chinese-to-number", feature = "number-to-chinese"))] 74 | mod chinese_characters; 75 | mod chinese_count_method; 76 | 77 | pub use chinese_case::*; 78 | #[cfg(any(feature = "chinese-to-number", feature = "number-to-chinese"))] 79 | pub(crate) use chinese_characters::*; 80 | pub use chinese_count_method::*; 81 | #[cfg(feature = "chinese-to-number")] 82 | pub use chinese_to_number::*; 83 | pub use chinese_variant::*; 84 | #[cfg(feature = "number-to-chinese")] 85 | pub use number_to_chinese::*; 86 | -------------------------------------------------------------------------------- /src/number_to_chinese/functions.rs: -------------------------------------------------------------------------------- 1 | use alloc::string::{String, ToString}; 2 | 3 | use num_bigint::BigUint; 4 | #[cfg(not(feature = "std"))] 5 | #[allow(unused_imports)] 6 | use num_traits::float::FloatCore; 7 | use num_traits::{FromPrimitive, ToPrimitive, Zero}; 8 | 9 | use crate::{ChineseCase, ChineseCountMethod, ChineseExponent, ChineseNumber, ChineseVariant}; 10 | 11 | pub(crate) fn unsigned_integer_to_chinese_low( 12 | chinese_variant: ChineseVariant, 13 | chinese_case: ChineseCase, 14 | dependent: bool, 15 | mut value: u128, 16 | ) -> String { 17 | debug_assert!(value < 1_0000_0000_0000_0000); 18 | 19 | let mut s = String::new(); 20 | 21 | let mut lower_d = (value % 10) as u8; 22 | value /= 10; 23 | 24 | if lower_d > 0 { 25 | s.push_str( 26 | unsafe { ChineseNumber::from_ordinal_unsafe(lower_d) } 27 | .to_str(chinese_variant, chinese_case), 28 | ); 29 | } else if value == 0 { 30 | return ChineseNumber::零.to_str(chinese_variant, chinese_case).to_string(); 31 | } 32 | 33 | let d = (value % 10) as u8; 34 | value /= 10; 35 | 36 | if d > 0 { 37 | s.insert_str(0, ChineseExponent::十.to_str(chinese_variant, chinese_case)); 38 | 39 | if value > 0 || dependent || d > 1 { 40 | s.insert_str( 41 | 0, 42 | unsafe { ChineseNumber::from_ordinal_unsafe(d) } 43 | .to_str(chinese_variant, chinese_case), 44 | ); 45 | } 46 | } 47 | 48 | if value == 0 { 49 | return s; 50 | } 51 | 52 | lower_d = d; 53 | 54 | let mut i = ChineseExponent::百.ordinal(); 55 | 56 | loop { 57 | let d = (value % 10) as u8; 58 | value /= 10; 59 | 60 | if d > 0 { 61 | if lower_d < 1 && !s.is_empty() { 62 | s.insert_str(0, ChineseNumber::零.to_str(chinese_variant, chinese_case)); 63 | } 64 | 65 | s.insert_str( 66 | 0, 67 | unsafe { ChineseExponent::from_ordinal_unsafe(i) } 68 | .to_str(chinese_variant, chinese_case), 69 | ); 70 | 71 | s.insert_str( 72 | 0, 73 | unsafe { ChineseNumber::from_ordinal_unsafe(d) } 74 | .to_str(chinese_variant, chinese_case), 75 | ); 76 | } 77 | 78 | if value == 0 { 79 | break; 80 | } 81 | 82 | lower_d = d; 83 | 84 | i += 1; 85 | } 86 | 87 | s 88 | } 89 | 90 | pub(crate) fn unsigned_integer_to_chinese_ten_thousand( 91 | chinese_variant: ChineseVariant, 92 | chinese_case: ChineseCase, 93 | dependent: bool, 94 | mut value: u128, 95 | ) -> String { 96 | let mut lower_d = value % 1_0000; 97 | value /= 1_0000; 98 | 99 | let mut has_more = value > 0; 100 | 101 | let mut s = if lower_d > 0 { 102 | unsigned_integer_to_chinese_low( 103 | chinese_variant, 104 | chinese_case, 105 | dependent || has_more, 106 | lower_d, 107 | ) 108 | } else if value == 0 { 109 | return ChineseNumber::零.to_str(chinese_variant, chinese_case).to_string(); 110 | } else { 111 | String::new() 112 | }; 113 | 114 | if !has_more { 115 | return s; 116 | } 117 | 118 | let mut i = ChineseExponent::萬.ordinal(); 119 | 120 | loop { 121 | let d = value % 1_0000; 122 | value /= 1_0000; 123 | 124 | has_more = value > 0; 125 | 126 | if d > 0 { 127 | if lower_d < 1000 && !s.is_empty() { 128 | s.insert_str(0, ChineseNumber::零.to_str(chinese_variant, chinese_case)); 129 | } 130 | 131 | s.insert_str( 132 | 0, 133 | unsafe { ChineseExponent::from_ordinal_unsafe(i) } 134 | .to_str(chinese_variant, chinese_case), 135 | ); 136 | 137 | s.insert_str( 138 | 0, 139 | unsigned_integer_to_chinese_low( 140 | chinese_variant, 141 | chinese_case, 142 | dependent || has_more, 143 | d, 144 | ) 145 | .as_str(), 146 | ); 147 | } 148 | 149 | if !has_more { 150 | break; 151 | } 152 | 153 | lower_d = d; 154 | 155 | i += 1; 156 | } 157 | 158 | s 159 | } 160 | 161 | pub(crate) fn big_unsigned_integer_to_chinese_ten_thousand( 162 | chinese_variant: ChineseVariant, 163 | chinese_case: ChineseCase, 164 | dependent: bool, 165 | mut value: BigUint, 166 | ) -> String { 167 | debug_assert!(value < BigUint::from(10u8).pow(52)); 168 | 169 | let big_0 = BigUint::zero(); 170 | let big_1_0000 = BigUint::from(1_0000u16); 171 | 172 | let mut lower_d = (value.clone() % &big_1_0000).to_u128().unwrap(); 173 | value /= &big_1_0000; 174 | 175 | let mut has_more = value > big_0; 176 | 177 | let mut s = if lower_d > 0 { 178 | unsigned_integer_to_chinese_low( 179 | chinese_variant, 180 | chinese_case, 181 | dependent || has_more, 182 | lower_d, 183 | ) 184 | } else if value == big_0 { 185 | return ChineseNumber::零.to_str(chinese_variant, chinese_case).to_string(); 186 | } else { 187 | String::new() 188 | }; 189 | 190 | if !has_more { 191 | return s; 192 | } 193 | 194 | let mut i = ChineseExponent::萬.ordinal(); 195 | 196 | loop { 197 | let d = (value.clone() % &big_1_0000).to_u128().unwrap(); 198 | value /= &big_1_0000; 199 | 200 | has_more = value > big_0; 201 | 202 | if d > 0 { 203 | if lower_d < 1000 && !s.is_empty() { 204 | s.insert_str(0, ChineseNumber::零.to_str(chinese_variant, chinese_case)); 205 | } 206 | 207 | s.insert_str( 208 | 0, 209 | unsafe { ChineseExponent::from_ordinal_unsafe(i) } 210 | .to_str(chinese_variant, chinese_case), 211 | ); 212 | 213 | s.insert_str( 214 | 0, 215 | unsigned_integer_to_chinese_low( 216 | chinese_variant, 217 | chinese_case, 218 | dependent || has_more, 219 | d, 220 | ) 221 | .as_str(), 222 | ); 223 | } 224 | 225 | if !has_more { 226 | break; 227 | } 228 | 229 | lower_d = d; 230 | 231 | i += 1; 232 | } 233 | 234 | s 235 | } 236 | 237 | pub(crate) fn unsigned_integer_to_chinese_middle( 238 | chinese_variant: ChineseVariant, 239 | chinese_case: ChineseCase, 240 | dependent: bool, 241 | mut value: u128, 242 | ) -> String { 243 | let mut lower_d = value % 1_0000_0000; 244 | value /= 1_0000_0000; 245 | 246 | let mut has_more = value > 0; 247 | 248 | let mut s = if lower_d > 0 { 249 | unsigned_integer_to_chinese_ten_thousand( 250 | chinese_variant, 251 | chinese_case, 252 | dependent || has_more, 253 | lower_d, 254 | ) 255 | } else if value == 0 { 256 | return ChineseNumber::零.to_str(chinese_variant, chinese_case).to_string(); 257 | } else { 258 | String::new() 259 | }; 260 | 261 | if !has_more { 262 | return s; 263 | } 264 | 265 | let mut i = ChineseExponent::億.ordinal(); 266 | 267 | loop { 268 | let d = value % 1_0000_0000; 269 | value /= 1_0000_0000; 270 | 271 | has_more = value > 0; 272 | 273 | if d > 0 { 274 | if lower_d < 1000_0000 && !s.is_empty() { 275 | s.insert_str(0, ChineseNumber::零.to_str(chinese_variant, chinese_case)); 276 | } 277 | 278 | s.insert_str( 279 | 0, 280 | unsafe { ChineseExponent::from_ordinal_unsafe(i) } 281 | .to_str(chinese_variant, chinese_case), 282 | ); 283 | 284 | s.insert_str( 285 | 0, 286 | unsigned_integer_to_chinese_ten_thousand( 287 | chinese_variant, 288 | chinese_case, 289 | dependent || has_more, 290 | d, 291 | ) 292 | .as_str(), 293 | ); 294 | } 295 | 296 | if !has_more { 297 | break; 298 | } 299 | 300 | lower_d = d; 301 | 302 | i += 1; 303 | } 304 | 305 | s 306 | } 307 | 308 | pub(crate) fn big_unsigned_integer_to_chinese_middle( 309 | chinese_variant: ChineseVariant, 310 | chinese_case: ChineseCase, 311 | dependent: bool, 312 | mut value: BigUint, 313 | ) -> String { 314 | debug_assert!(value < BigUint::from(10u8).pow(96)); 315 | 316 | let big_0 = BigUint::zero(); 317 | let big_1_0000_0000 = BigUint::from(1_0000_0000u32); 318 | 319 | let mut lower_d = (value.clone() % &big_1_0000_0000).to_u128().unwrap(); 320 | value /= &big_1_0000_0000; 321 | 322 | let mut has_more = value > big_0; 323 | 324 | let mut s = if lower_d > 0 { 325 | unsigned_integer_to_chinese_ten_thousand( 326 | chinese_variant, 327 | chinese_case, 328 | dependent || has_more, 329 | lower_d, 330 | ) 331 | } else if value == big_0 { 332 | return ChineseNumber::零.to_str(chinese_variant, chinese_case).to_string(); 333 | } else { 334 | String::new() 335 | }; 336 | 337 | if !has_more { 338 | return s; 339 | } 340 | 341 | let mut i = ChineseExponent::億.ordinal(); 342 | 343 | loop { 344 | let d = (value.clone() % &big_1_0000_0000).to_u128().unwrap(); 345 | value /= &big_1_0000_0000; 346 | 347 | has_more = value > big_0; 348 | 349 | if d > 0 { 350 | if lower_d < 1000_0000 && !s.is_empty() { 351 | s.insert_str(0, ChineseNumber::零.to_str(chinese_variant, chinese_case)); 352 | } 353 | 354 | s.insert_str( 355 | 0, 356 | unsafe { ChineseExponent::from_ordinal_unsafe(i) } 357 | .to_str(chinese_variant, chinese_case), 358 | ); 359 | 360 | s.insert_str( 361 | 0, 362 | unsigned_integer_to_chinese_ten_thousand( 363 | chinese_variant, 364 | chinese_case, 365 | dependent || has_more, 366 | d, 367 | ) 368 | .as_str(), 369 | ); 370 | } 371 | 372 | if !has_more { 373 | break; 374 | } 375 | 376 | lower_d = d; 377 | 378 | i += 1; 379 | } 380 | 381 | s 382 | } 383 | 384 | pub(crate) fn unsigned_integer_to_chinese_high( 385 | chinese_variant: ChineseVariant, 386 | chinese_case: ChineseCase, 387 | dependent: bool, 388 | mut value: u128, 389 | ) -> String { 390 | let mut w = 1_0000_0000_0000_0000; 391 | 392 | let mut lower_d = value % w; 393 | value /= w; 394 | 395 | let mut has_more = value > 0; 396 | 397 | let mut s = if lower_d > 0 { 398 | unsigned_integer_to_chinese_middle( 399 | chinese_variant, 400 | chinese_case, 401 | dependent || has_more, 402 | lower_d, 403 | ) 404 | } else if value == 0 { 405 | return ChineseNumber::零.to_str(chinese_variant, chinese_case).to_string(); 406 | } else { 407 | String::new() 408 | }; 409 | 410 | if !has_more { 411 | return s; 412 | } 413 | 414 | let mut i = ChineseExponent::兆.ordinal(); 415 | 416 | let mut previous_w = w; 417 | 418 | loop { 419 | let d = value % w; 420 | value /= w; 421 | 422 | has_more = value > 0; 423 | 424 | if d > 0 { 425 | if lower_d < previous_w / 10 && !s.is_empty() { 426 | s.insert_str(0, ChineseNumber::零.to_str(chinese_variant, chinese_case)); 427 | } 428 | 429 | s.insert_str( 430 | 0, 431 | unsafe { ChineseExponent::from_ordinal_unsafe(i) } 432 | .to_str(chinese_variant, chinese_case), 433 | ); 434 | 435 | s.insert_str( 436 | 0, 437 | unsigned_integer_to_chinese_high( 438 | chinese_variant, 439 | chinese_case, 440 | dependent || has_more, 441 | d, 442 | ) 443 | .as_str(), 444 | ); 445 | } 446 | 447 | if !has_more { 448 | break; 449 | } 450 | 451 | lower_d = d; 452 | 453 | i += 1; 454 | 455 | previous_w = w; 456 | w *= w; 457 | } 458 | 459 | s 460 | } 461 | 462 | pub(crate) fn big_unsigned_integer_to_chinese_high( 463 | chinese_variant: ChineseVariant, 464 | chinese_case: ChineseCase, 465 | dependent: bool, 466 | mut value: BigUint, 467 | ) -> String { 468 | let big_0 = BigUint::zero(); 469 | let big_10 = BigUint::from(10u8); 470 | 471 | let mut w = BigUint::from(1_0000_0000_0000_0000u64); 472 | 473 | let mut lower_d = value.clone() % &w; 474 | value /= &w; 475 | 476 | let mut has_more = value > big_0; 477 | 478 | let mut s = if lower_d > big_0 { 479 | unsigned_integer_to_chinese_middle( 480 | chinese_variant, 481 | chinese_case, 482 | dependent || has_more, 483 | lower_d.to_u128().unwrap(), 484 | ) 485 | } else if value == big_0 { 486 | return ChineseNumber::零.to_str(chinese_variant, chinese_case).to_string(); 487 | } else { 488 | String::new() 489 | }; 490 | 491 | if !has_more { 492 | return s; 493 | } 494 | 495 | let mut i = ChineseExponent::兆.ordinal(); 496 | 497 | let mut previous_w = w.clone(); 498 | 499 | loop { 500 | let d = value.clone() % &w; 501 | value /= &w; 502 | 503 | has_more = value > big_0; 504 | 505 | if d > big_0 { 506 | if lower_d < previous_w / &big_10 && !s.is_empty() { 507 | s.insert_str(0, ChineseNumber::零.to_str(chinese_variant, chinese_case)); 508 | } 509 | 510 | s.insert_str( 511 | 0, 512 | unsafe { ChineseExponent::from_ordinal_unsafe(i) } 513 | .to_str(chinese_variant, chinese_case), 514 | ); 515 | 516 | s.insert_str( 517 | 0, 518 | big_unsigned_integer_to_chinese_high( 519 | chinese_variant, 520 | chinese_case, 521 | dependent || has_more, 522 | d.clone(), 523 | ) 524 | .as_str(), 525 | ); 526 | } 527 | 528 | if !has_more { 529 | break; 530 | } 531 | 532 | lower_d = d; 533 | 534 | i += 1; 535 | 536 | previous_w = w.clone(); 537 | w = w.clone() * w; 538 | } 539 | 540 | s 541 | } 542 | 543 | pub(crate) fn positive_float_to_chinese( 544 | chinese_variant: ChineseVariant, 545 | chinese_case: ChineseCase, 546 | method: ChineseCountMethod, 547 | value: f64, 548 | ) -> String { 549 | let (integer, fraction) = { 550 | let integer = BigUint::from_f64(value.trunc()).unwrap(); 551 | let fraction = ((value.fract() * 100.0).round() % 100f64) as u8; 552 | 553 | (integer, fraction) 554 | }; 555 | 556 | let big_0 = BigUint::zero(); 557 | 558 | let mut s = if integer > big_0 { 559 | match method { 560 | ChineseCountMethod::Low => unsigned_integer_to_chinese_low( 561 | chinese_variant, 562 | chinese_case, 563 | false, 564 | integer.to_u128().unwrap(), 565 | ), 566 | ChineseCountMethod::TenThousand => big_unsigned_integer_to_chinese_ten_thousand( 567 | chinese_variant, 568 | chinese_case, 569 | false, 570 | integer.clone(), 571 | ), 572 | ChineseCountMethod::Middle => big_unsigned_integer_to_chinese_middle( 573 | chinese_variant, 574 | chinese_case, 575 | false, 576 | integer.clone(), 577 | ), 578 | ChineseCountMethod::High => big_unsigned_integer_to_chinese_high( 579 | chinese_variant, 580 | chinese_case, 581 | false, 582 | integer.clone(), 583 | ), 584 | } 585 | } else { 586 | String::new() 587 | }; 588 | 589 | if fraction >= 10 { 590 | let msd = fraction / 10; 591 | let lsd = fraction % 10; 592 | 593 | s.push_str( 594 | unsafe { ChineseNumber::from_ordinal_unsafe(msd) } 595 | .to_str(chinese_variant, chinese_case), 596 | ); 597 | 598 | s.push_str(ChineseExponent::角.to_str(chinese_variant, chinese_case)); 599 | 600 | if lsd > 0 { 601 | s.push_str( 602 | unsafe { ChineseNumber::from_ordinal_unsafe(lsd) } 603 | .to_str(chinese_variant, chinese_case), 604 | ); 605 | 606 | s.push_str(ChineseExponent::分.to_str(chinese_variant, chinese_case)); 607 | } 608 | } else if fraction >= 1 { 609 | s.push_str( 610 | unsafe { ChineseNumber::from_ordinal_unsafe(fraction) } 611 | .to_str(chinese_variant, chinese_case), 612 | ); 613 | 614 | s.push_str(ChineseExponent::分.to_str(chinese_variant, chinese_case)); 615 | } else if integer == big_0 { 616 | s.push_str(ChineseNumber::零.to_str(chinese_variant, chinese_case)); 617 | } 618 | 619 | s 620 | } 621 | -------------------------------------------------------------------------------- /src/number_to_chinese/functions_test.rs: -------------------------------------------------------------------------------- 1 | #![cfg(test)] 2 | 3 | use super::*; 4 | 5 | #[test] 6 | fn test_unsigned_integer_to_chinese_low() { 7 | macro_rules! test { 8 | ($expect:expr, $value:expr) => { 9 | assert_eq!( 10 | $expect, 11 | unsigned_integer_to_chinese_low( 12 | ChineseVariant::Traditional, 13 | ChineseCase::Lower, 14 | false, 15 | $value 16 | ) 17 | ); 18 | }; 19 | } 20 | 21 | test!("零", 0); 22 | test!("一", 1); 23 | test!("十", 10); 24 | test!("二十", 20); 25 | test!("五十五", 55); 26 | test!("一萬", 1_0000); 27 | test!("一萬零一", 1_0001); 28 | test!("一萬零一十", 1_0010); 29 | test!("一億", 10_0000); 30 | test!("一億零一", 10_0001); 31 | } 32 | 33 | #[test] 34 | fn test_unsigned_integer_to_chinese_ten_thousand() { 35 | macro_rules! test { 36 | ($expect:expr, $value:expr) => { 37 | assert_eq!( 38 | $expect, 39 | unsigned_integer_to_chinese_ten_thousand( 40 | ChineseVariant::Traditional, 41 | ChineseCase::Lower, 42 | false, 43 | $value 44 | ) 45 | ); 46 | }; 47 | } 48 | 49 | test!("零", 0); 50 | test!("一", 1); 51 | test!("十", 10); 52 | test!("一萬", 1_0000); 53 | test!("一萬零一", 1_0001); 54 | test!("一萬零一十", 1_0010); 55 | test!("十萬", 10_0000); 56 | test!("十萬零一", 10_0001); 57 | test!("一億", 1_0000_0000); 58 | test!("一億零一", 1_0000_0001); 59 | test!("一億零一萬", 1_0001_0000); 60 | } 61 | 62 | #[test] 63 | fn test_big_unsigned_integer_to_chinese_ten_thousand() { 64 | macro_rules! test { 65 | ($expect:expr, $value:expr) => { 66 | assert_eq!( 67 | $expect, 68 | big_unsigned_integer_to_chinese_ten_thousand( 69 | ChineseVariant::Traditional, 70 | ChineseCase::Lower, 71 | false, 72 | ($value as u128).into() 73 | ) 74 | ); 75 | }; 76 | } 77 | 78 | test!("零", 0); 79 | test!("一", 1); 80 | test!("十", 10); 81 | test!("一萬", 1_0000); 82 | test!("一萬零一", 1_0001); 83 | test!("一萬零一十", 1_0010); 84 | test!("十萬", 10_0000); 85 | test!("十萬零一", 10_0001); 86 | test!("一億", 1_0000_0000); 87 | test!("一億零一", 1_0000_0001); 88 | test!("一億零一萬", 1_0001_0000); 89 | } 90 | 91 | #[test] 92 | fn test_unsigned_integer_to_chinese_middle() { 93 | macro_rules! test { 94 | ($expect:expr, $value:expr) => { 95 | assert_eq!( 96 | $expect, 97 | unsigned_integer_to_chinese_middle( 98 | ChineseVariant::Traditional, 99 | ChineseCase::Lower, 100 | false, 101 | $value 102 | ) 103 | ); 104 | }; 105 | } 106 | 107 | test!("零", 0); 108 | test!("一", 1); 109 | test!("十", 10); 110 | test!("一萬", 1_0000); 111 | test!("一萬零一", 1_0001); 112 | test!("一萬零一十", 1_0010); 113 | test!("十萬", 10_0000); 114 | test!("十萬零一", 10_0001); 115 | test!("一億", 1_0000_0000); 116 | test!("一萬億", 1_0000_0000_0000); 117 | test!("一萬零一億", 1_0001_0000_0000); 118 | } 119 | 120 | #[test] 121 | fn test_big_unsigned_integer_to_chinese_middle() { 122 | macro_rules! test { 123 | ($expect:expr, $value:expr) => { 124 | assert_eq!( 125 | $expect, 126 | big_unsigned_integer_to_chinese_middle( 127 | ChineseVariant::Traditional, 128 | ChineseCase::Lower, 129 | false, 130 | ($value as u128).into() 131 | ) 132 | ); 133 | }; 134 | } 135 | 136 | test!("零", 0); 137 | test!("一", 1); 138 | test!("十", 10); 139 | test!("一萬", 1_0000); 140 | test!("一萬零一", 1_0001); 141 | test!("一萬零一十", 1_0010); 142 | test!("十萬", 10_0000); 143 | test!("十萬零一", 10_0001); 144 | test!("一億", 1_0000_0000); 145 | test!("一萬億", 1_0000_0000_0000); 146 | test!("一萬零一億", 1_0001_0000_0000); 147 | } 148 | 149 | #[test] 150 | fn test_unsigned_integer_to_chinese_high() { 151 | macro_rules! test { 152 | ($expect:expr, $value:expr) => { 153 | assert_eq!( 154 | $expect, 155 | unsigned_integer_to_chinese_high( 156 | ChineseVariant::Traditional, 157 | ChineseCase::Lower, 158 | false, 159 | $value 160 | ) 161 | ); 162 | }; 163 | } 164 | 165 | test!("零", 0); 166 | test!("一", 1); 167 | test!("十", 10); 168 | test!("一萬", 1_0000); 169 | test!("一萬零一", 1_0001); 170 | test!("一萬零一十", 1_0010); 171 | test!("十萬", 10_0000); 172 | test!("十萬零一", 10_0001); 173 | test!("一億", 1_0000_0000); 174 | test!("一萬億", 1_0000_0000_0000); 175 | test!("一兆", 1_0000_0000_0000_0000); 176 | test!("一兆零一萬億", 1_0001_0000_0000_0000); 177 | test!("一萬兆", 1_0000_0000_0000_0000_0000); 178 | test!("一億兆", 1_0000_0000_0000_0000_0000_0000); 179 | test!("一萬億兆", 1_0000_0000_0000_0000_0000_0000_0000); 180 | test!("一京", 1_0000_0000_0000_0000_0000_0000_0000_0000); 181 | } 182 | 183 | #[test] 184 | fn test_big_unsigned_integer_to_chinese_high() { 185 | macro_rules! test { 186 | ($expect:expr, $value:expr) => { 187 | assert_eq!( 188 | $expect, 189 | big_unsigned_integer_to_chinese_high( 190 | ChineseVariant::Traditional, 191 | ChineseCase::Lower, 192 | false, 193 | ($value as u128).into() 194 | ) 195 | ); 196 | }; 197 | } 198 | 199 | test!("零", 0); 200 | test!("一", 1); 201 | test!("十", 10); 202 | test!("一萬", 1_0000); 203 | test!("一萬零一", 1_0001); 204 | test!("一萬零一十", 1_0010); 205 | test!("十萬", 10_0000); 206 | test!("十萬零一", 10_0001); 207 | test!("一億", 1_0000_0000); 208 | test!("一萬億", 1_0000_0000_0000); 209 | test!("一兆", 1_0000_0000_0000_0000); 210 | test!("一兆零一萬億", 1_0001_0000_0000_0000); 211 | test!("一萬兆", 1_0000_0000_0000_0000_0000); 212 | test!("一億兆", 1_0000_0000_0000_0000_0000_0000); 213 | test!("一萬億兆", 1_0000_0000_0000_0000_0000_0000_0000); 214 | test!("一京", 1_0000_0000_0000_0000_0000_0000_0000_0000); 215 | } 216 | 217 | #[test] 218 | fn test_fraction_compat() { 219 | macro_rules! test { 220 | ($expect:expr, $value:expr) => { 221 | assert_eq!( 222 | $expect, 223 | positive_float_to_chinese( 224 | ChineseVariant::Traditional, 225 | ChineseCase::Lower, 226 | ChineseCountMethod::TenThousand, 227 | $value 228 | ) 229 | ); 230 | }; 231 | } 232 | 233 | test!("零", 0.0); 234 | test!("一分", 0.01); 235 | test!("一角", 0.1); 236 | test!("五角五分", 0.55); 237 | test!("九十九九角九分", 99.99); 238 | } 239 | -------------------------------------------------------------------------------- /src/number_to_chinese/mod.rs: -------------------------------------------------------------------------------- 1 | mod functions; 2 | mod naive; 3 | mod number_to_chinese_error; 4 | mod traits; 5 | 6 | mod functions_test; 7 | 8 | use alloc::string::String; 9 | 10 | use functions::*; 11 | pub use naive::*; 12 | pub use number_to_chinese_error::*; 13 | pub use traits::*; 14 | 15 | use crate::{ChineseCase, ChineseCountMethod, ChineseSign, ChineseVariant}; 16 | 17 | // TODO unsigned integer 18 | 19 | /// 將 `u8` 整數轉成中文數字。 20 | #[inline] 21 | pub fn from_u8_to_chinese( 22 | chinese_variant: ChineseVariant, 23 | chinese_case: ChineseCase, 24 | value: u8, 25 | ) -> String { 26 | from_u128_to_chinese_low(chinese_variant, chinese_case, value as u128).unwrap() 27 | } 28 | 29 | /// 將 `u16` 整數轉成中文數字。 30 | #[inline] 31 | pub fn from_u16_to_chinese( 32 | chinese_variant: ChineseVariant, 33 | chinese_case: ChineseCase, 34 | value: u16, 35 | ) -> String { 36 | from_u128_to_chinese_low(chinese_variant, chinese_case, value as u128).unwrap() 37 | } 38 | 39 | /// 將 `u32` 整數轉成中文數字,使用 **「下數」**。 40 | #[inline] 41 | pub fn from_u32_to_chinese_low( 42 | chinese_variant: ChineseVariant, 43 | chinese_case: ChineseCase, 44 | value: u32, 45 | ) -> String { 46 | from_u128_to_chinese_low(chinese_variant, chinese_case, value as u128).unwrap() 47 | } 48 | 49 | /// 將 `u32` 整數轉成中文數字,使用 **「萬進」**。 50 | #[inline] 51 | pub fn from_u32_to_chinese_ten_thousand( 52 | chinese_variant: ChineseVariant, 53 | chinese_case: ChineseCase, 54 | value: u32, 55 | ) -> String { 56 | from_u128_to_chinese_ten_thousand(chinese_variant, chinese_case, value as u128) 57 | } 58 | 59 | /// 將 `u32` 整數轉成中文數字,使用 **「中數」**。 60 | #[inline] 61 | pub fn from_u32_to_chinese_middle( 62 | chinese_variant: ChineseVariant, 63 | chinese_case: ChineseCase, 64 | value: u32, 65 | ) -> String { 66 | from_u128_to_chinese_middle(chinese_variant, chinese_case, value as u128) 67 | } 68 | 69 | /// 將 `u32` 整數轉成中文數字,使用 **「上數」**。 70 | #[inline] 71 | pub fn from_u32_to_chinese_high( 72 | chinese_variant: ChineseVariant, 73 | chinese_case: ChineseCase, 74 | value: u32, 75 | ) -> String { 76 | from_u128_to_chinese_high(chinese_variant, chinese_case, value as u128) 77 | } 78 | 79 | /// 將 `u64` 整數轉成中文數字,使用 **「下數」**。數值不能大於或等於 `1_0000_0000_0000_0000`。 80 | #[inline] 81 | pub fn from_u64_to_chinese_low( 82 | chinese_variant: ChineseVariant, 83 | chinese_case: ChineseCase, 84 | value: u64, 85 | ) -> Result { 86 | from_u128_to_chinese_low(chinese_variant, chinese_case, value as u128) 87 | } 88 | 89 | /// 將 `u64` 整數轉成中文數字,使用 **「萬進」**。 90 | #[inline] 91 | pub fn from_u64_to_chinese_ten_thousand( 92 | chinese_variant: ChineseVariant, 93 | chinese_case: ChineseCase, 94 | value: u64, 95 | ) -> String { 96 | from_u128_to_chinese_ten_thousand(chinese_variant, chinese_case, value as u128) 97 | } 98 | 99 | /// 將 `u64` 整數轉成中文數字,使用 **「中數」**。 100 | #[inline] 101 | pub fn from_u64_to_chinese_middle( 102 | chinese_variant: ChineseVariant, 103 | chinese_case: ChineseCase, 104 | value: u64, 105 | ) -> String { 106 | from_u128_to_chinese_middle(chinese_variant, chinese_case, value as u128) 107 | } 108 | 109 | /// 將 `u64` 整數轉成中文數字,使用 **「上數」**。 110 | #[inline] 111 | pub fn from_u64_to_chinese_high( 112 | chinese_variant: ChineseVariant, 113 | chinese_case: ChineseCase, 114 | value: u64, 115 | ) -> String { 116 | from_u128_to_chinese_high(chinese_variant, chinese_case, value as u128) 117 | } 118 | 119 | /// 將 `u128` 整數轉成中文數字,使用 **「下數」**。數值不能大於或等於 `1_0000_0000_0000_0000`。 120 | #[inline] 121 | pub fn from_u128_to_chinese_low( 122 | chinese_variant: ChineseVariant, 123 | chinese_case: ChineseCase, 124 | value: u128, 125 | ) -> Result { 126 | if value >= 1_0000_0000_0000_0000 { 127 | return Err(NumberToChineseError::Overflow); 128 | } 129 | 130 | Ok(unsigned_integer_to_chinese_low(chinese_variant, chinese_case, false, value)) 131 | } 132 | 133 | /// 將 `u128` 整數轉成中文數字,使用 **「萬進」**。 134 | #[inline] 135 | pub fn from_u128_to_chinese_ten_thousand( 136 | chinese_variant: ChineseVariant, 137 | chinese_case: ChineseCase, 138 | value: u128, 139 | ) -> String { 140 | unsigned_integer_to_chinese_ten_thousand(chinese_variant, chinese_case, false, value) 141 | } 142 | 143 | /// 將 `u128` 整數轉成中文數字,使用 **「中數」**。 144 | #[inline] 145 | pub fn from_u128_to_chinese_middle( 146 | chinese_variant: ChineseVariant, 147 | chinese_case: ChineseCase, 148 | value: u128, 149 | ) -> String { 150 | unsigned_integer_to_chinese_middle(chinese_variant, chinese_case, false, value) 151 | } 152 | 153 | /// 將 `u128` 整數轉成中文數字,使用 **「上數」**。 154 | #[inline] 155 | pub fn from_u128_to_chinese_high( 156 | chinese_variant: ChineseVariant, 157 | chinese_case: ChineseCase, 158 | value: u128, 159 | ) -> String { 160 | unsigned_integer_to_chinese_high(chinese_variant, chinese_case, false, value) 161 | } 162 | 163 | /// 將 `usize` 整數轉成中文數字,使用 **「下數」**。數值不能大於或等於 `1_0000_0000_0000_0000`。 164 | #[inline] 165 | pub fn from_usize_to_chinese_low( 166 | chinese_variant: ChineseVariant, 167 | chinese_case: ChineseCase, 168 | value: usize, 169 | ) -> Result { 170 | from_u128_to_chinese_low(chinese_variant, chinese_case, value as u128) 171 | } 172 | 173 | /// 將 `usize` 整數轉成中文數字,使用 **「萬進」**。 174 | #[inline] 175 | pub fn from_usize_to_chinese_ten_thousand( 176 | chinese_variant: ChineseVariant, 177 | chinese_case: ChineseCase, 178 | value: usize, 179 | ) -> String { 180 | from_u128_to_chinese_ten_thousand(chinese_variant, chinese_case, value as u128) 181 | } 182 | 183 | /// 將 `usize` 整數轉成中文數字,使用 **「中數」**。 184 | #[inline] 185 | pub fn from_usize_to_chinese_middle( 186 | chinese_variant: ChineseVariant, 187 | chinese_case: ChineseCase, 188 | value: usize, 189 | ) -> String { 190 | from_u128_to_chinese_middle(chinese_variant, chinese_case, value as u128) 191 | } 192 | 193 | /// 將 `usize` 整數轉成中文數字,使用 **「上數」**。 194 | #[inline] 195 | pub fn from_usize_to_chinese_high( 196 | chinese_variant: ChineseVariant, 197 | chinese_case: ChineseCase, 198 | value: usize, 199 | ) -> String { 200 | from_u128_to_chinese_high(chinese_variant, chinese_case, value as u128) 201 | } 202 | 203 | // TODO signed integer 204 | 205 | /// 將 `i8` 整數轉成中文數字。 206 | #[inline] 207 | pub fn from_i8_to_chinese( 208 | chinese_variant: ChineseVariant, 209 | chinese_case: ChineseCase, 210 | value: i8, 211 | ) -> String { 212 | from_i128_to_chinese_low(chinese_variant, chinese_case, value as i128).unwrap() 213 | } 214 | 215 | /// 將 `i16` 整數轉成中文數字。 216 | #[inline] 217 | pub fn from_i16_to_chinese( 218 | chinese_variant: ChineseVariant, 219 | chinese_case: ChineseCase, 220 | value: i16, 221 | ) -> String { 222 | from_i128_to_chinese_low(chinese_variant, chinese_case, value as i128).unwrap() 223 | } 224 | 225 | /// 將 `i32` 整數轉成中文數字,使用 **「下數」**。 226 | #[inline] 227 | pub fn from_i32_to_chinese_low( 228 | chinese_variant: ChineseVariant, 229 | chinese_case: ChineseCase, 230 | value: i32, 231 | ) -> String { 232 | from_i128_to_chinese_low(chinese_variant, chinese_case, value as i128).unwrap() 233 | } 234 | 235 | /// 將 `i32` 整數轉成中文數字,使用 **「萬進」**。 236 | #[inline] 237 | pub fn from_i32_to_chinese_ten_thousand( 238 | chinese_variant: ChineseVariant, 239 | chinese_case: ChineseCase, 240 | value: i32, 241 | ) -> String { 242 | from_i128_to_chinese_ten_thousand(chinese_variant, chinese_case, value as i128) 243 | } 244 | 245 | /// 將 `i32` 整數轉成中文數字,使用 **「中數」**。 246 | #[inline] 247 | pub fn from_i32_to_chinese_middle( 248 | chinese_variant: ChineseVariant, 249 | chinese_case: ChineseCase, 250 | value: i32, 251 | ) -> String { 252 | from_i128_to_chinese_middle(chinese_variant, chinese_case, value as i128) 253 | } 254 | 255 | /// 將 `i32` 整數轉成中文數字,使用 **「上數」**。 256 | #[inline] 257 | pub fn from_i32_to_chinese_high( 258 | chinese_variant: ChineseVariant, 259 | chinese_case: ChineseCase, 260 | value: i32, 261 | ) -> String { 262 | from_i128_to_chinese_high(chinese_variant, chinese_case, value as i128) 263 | } 264 | 265 | /// 將 `i64` 整數轉成中文數字,使用 **「下數」**。數值的絕對值不能大於或等於 `1_0000_0000_0000_0000`。 266 | #[inline] 267 | pub fn from_i64_to_chinese_low( 268 | chinese_variant: ChineseVariant, 269 | chinese_case: ChineseCase, 270 | value: i64, 271 | ) -> Result { 272 | from_i128_to_chinese_low(chinese_variant, chinese_case, value as i128) 273 | } 274 | 275 | /// 將 `i64` 整數轉成中文數字,使用 **「萬進」**。 276 | #[inline] 277 | pub fn from_i64_to_chinese_ten_thousand( 278 | chinese_variant: ChineseVariant, 279 | chinese_case: ChineseCase, 280 | value: i64, 281 | ) -> String { 282 | from_i128_to_chinese_ten_thousand(chinese_variant, chinese_case, value as i128) 283 | } 284 | 285 | /// 將 `i64` 整數轉成中文數字,使用 **「中數」**。 286 | #[inline] 287 | pub fn from_i64_to_chinese_middle( 288 | chinese_variant: ChineseVariant, 289 | chinese_case: ChineseCase, 290 | value: i64, 291 | ) -> String { 292 | from_i128_to_chinese_middle(chinese_variant, chinese_case, value as i128) 293 | } 294 | 295 | /// 將 `i64` 整數轉成中文數字,使用 **「上數」**。 296 | #[inline] 297 | pub fn from_i64_to_chinese_high( 298 | chinese_variant: ChineseVariant, 299 | chinese_case: ChineseCase, 300 | value: i64, 301 | ) -> String { 302 | from_i128_to_chinese_high(chinese_variant, chinese_case, value as i128) 303 | } 304 | 305 | /// 將 `i128` 整數轉成中文數字,使用 **「下數」**。數值的絕對值不能大於或等於 `1_0000_0000_0000_0000`。 306 | #[inline] 307 | pub fn from_i128_to_chinese_low( 308 | chinese_variant: ChineseVariant, 309 | chinese_case: ChineseCase, 310 | value: i128, 311 | ) -> Result { 312 | if value < 0 { 313 | let mut s = 314 | from_u128_to_chinese_low(chinese_variant, chinese_case, -(value + 1) as u128 + 1) 315 | .map_err(|err| match err { 316 | NumberToChineseError::Overflow => NumberToChineseError::Underflow, 317 | _ => err, 318 | })?; 319 | 320 | s.insert_str(0, ChineseSign::負.to_str(chinese_variant)); 321 | 322 | Ok(s) 323 | } else { 324 | from_u128_to_chinese_low(chinese_variant, chinese_case, value as u128) 325 | } 326 | } 327 | 328 | /// 將 `i128` 整數轉成中文數字,使用 **「萬進」**。 329 | #[inline] 330 | pub fn from_i128_to_chinese_ten_thousand( 331 | chinese_variant: ChineseVariant, 332 | chinese_case: ChineseCase, 333 | value: i128, 334 | ) -> String { 335 | if value < 0 { 336 | let mut s = from_u128_to_chinese_ten_thousand( 337 | chinese_variant, 338 | chinese_case, 339 | -(value + 1) as u128 + 1, 340 | ); 341 | 342 | s.insert_str(0, ChineseSign::負.to_str(chinese_variant)); 343 | 344 | s 345 | } else { 346 | from_u128_to_chinese_ten_thousand(chinese_variant, chinese_case, value as u128) 347 | } 348 | } 349 | 350 | /// 將 `i128` 整數轉成中文數字,使用 **「中數」**。 351 | #[inline] 352 | pub fn from_i128_to_chinese_middle( 353 | chinese_variant: ChineseVariant, 354 | chinese_case: ChineseCase, 355 | value: i128, 356 | ) -> String { 357 | if value < 0 { 358 | let mut s = 359 | from_u128_to_chinese_middle(chinese_variant, chinese_case, -(value + 1) as u128 + 1); 360 | 361 | s.insert_str(0, ChineseSign::負.to_str(chinese_variant)); 362 | 363 | s 364 | } else { 365 | from_u128_to_chinese_middle(chinese_variant, chinese_case, value as u128) 366 | } 367 | } 368 | 369 | /// 將 `i128` 整數轉成中文數字,使用 **「上數」**。 370 | #[inline] 371 | pub fn from_i128_to_chinese_high( 372 | chinese_variant: ChineseVariant, 373 | chinese_case: ChineseCase, 374 | value: i128, 375 | ) -> String { 376 | if value < 0 { 377 | let mut s = 378 | from_u128_to_chinese_high(chinese_variant, chinese_case, -(value + 1) as u128 + 1); 379 | 380 | s.insert_str(0, ChineseSign::負.to_str(chinese_variant)); 381 | 382 | s 383 | } else { 384 | from_u128_to_chinese_high(chinese_variant, chinese_case, value as u128) 385 | } 386 | } 387 | 388 | /// 將 `isize` 整數轉成中文數字,使用 **「下數」**。數值的絕對值不能大於或等於 `1_0000_0000_0000_0000`。 389 | #[inline] 390 | pub fn from_isize_to_chinese_low( 391 | chinese_variant: ChineseVariant, 392 | chinese_case: ChineseCase, 393 | value: isize, 394 | ) -> Result { 395 | from_i128_to_chinese_low(chinese_variant, chinese_case, value as i128) 396 | } 397 | 398 | /// 將 `isize` 整數轉成中文數字,使用 **「萬進」**。 399 | #[inline] 400 | pub fn from_isize_to_chinese_ten_thousand( 401 | chinese_variant: ChineseVariant, 402 | chinese_case: ChineseCase, 403 | value: isize, 404 | ) -> String { 405 | from_i128_to_chinese_ten_thousand(chinese_variant, chinese_case, value as i128) 406 | } 407 | 408 | /// 將 `isize` 整數轉成中文數字,使用 **「中數」**。 409 | #[inline] 410 | pub fn from_isize_to_chinese_middle( 411 | chinese_variant: ChineseVariant, 412 | chinese_case: ChineseCase, 413 | value: isize, 414 | ) -> String { 415 | from_i128_to_chinese_middle(chinese_variant, chinese_case, value as i128) 416 | } 417 | 418 | /// 將 `isize` 整數轉成中文數字,使用 **「上數」**。 419 | #[inline] 420 | pub fn from_isize_to_chinese_high( 421 | chinese_variant: ChineseVariant, 422 | chinese_case: ChineseCase, 423 | value: isize, 424 | ) -> String { 425 | from_i128_to_chinese_high(chinese_variant, chinese_case, value as i128) 426 | } 427 | 428 | // TODO float 429 | 430 | /// 將 `f32` 浮點數轉成中文數字,使用 **「下數」**。數值的絕對值不能大於或等於 `1_0000_0000_0000_0000`。 431 | #[inline] 432 | pub fn from_f32_to_chinese_low( 433 | chinese_variant: ChineseVariant, 434 | chinese_case: ChineseCase, 435 | value: f32, 436 | ) -> Result { 437 | from_f64_to_chinese_low(chinese_variant, chinese_case, value as f64) 438 | } 439 | 440 | /// 將 `f32` 浮點數轉成中文數字,使用 **「萬進」**。 441 | #[inline] 442 | pub fn from_f32_to_chinese_ten_thousand( 443 | chinese_variant: ChineseVariant, 444 | chinese_case: ChineseCase, 445 | value: f32, 446 | ) -> String { 447 | from_f64_to_chinese_ten_thousand(chinese_variant, chinese_case, value as f64).unwrap() 448 | } 449 | 450 | /// 將 `f32` 浮點數轉成中文數字,使用 **「中數」**。 451 | #[inline] 452 | pub fn from_f32_to_chinese_middle( 453 | chinese_variant: ChineseVariant, 454 | chinese_case: ChineseCase, 455 | value: f32, 456 | ) -> String { 457 | from_f64_to_chinese_middle(chinese_variant, chinese_case, value as f64).unwrap() 458 | } 459 | 460 | /// 將 `f32` 浮點數轉成中文數字,使用 **「上數」**。 461 | #[inline] 462 | pub fn from_f32_to_chinese_high( 463 | chinese_variant: ChineseVariant, 464 | chinese_case: ChineseCase, 465 | value: f32, 466 | ) -> String { 467 | from_f64_to_chinese_high(chinese_variant, chinese_case, value as f64) 468 | } 469 | 470 | #[inline] 471 | fn from_f64_to_chinese( 472 | chinese_variant: ChineseVariant, 473 | chinese_case: ChineseCase, 474 | method: ChineseCountMethod, 475 | value: f64, 476 | ) -> String { 477 | if value < 0.0 { 478 | let mut s = positive_float_to_chinese(chinese_variant, chinese_case, method, -value); 479 | 480 | s.insert_str(0, ChineseSign::負.to_str(chinese_variant)); 481 | 482 | s 483 | } else { 484 | positive_float_to_chinese(chinese_variant, chinese_case, method, value) 485 | } 486 | } 487 | 488 | /// 將 `f64` 浮點數轉成中文數字,使用 **「下數」**。數值的絕對值不能大於或等於 `1_0000_0000_0000_0000`。 489 | #[inline] 490 | pub fn from_f64_to_chinese_low( 491 | chinese_variant: ChineseVariant, 492 | chinese_case: ChineseCase, 493 | value: f64, 494 | ) -> Result { 495 | if value >= 1_0000_0000_0000_0000f64 { 496 | return Err(NumberToChineseError::Overflow); 497 | } else if value <= -1_0000_0000_0000_0000f64 { 498 | return Err(NumberToChineseError::Underflow); 499 | } 500 | 501 | Ok(from_f64_to_chinese(chinese_variant, chinese_case, ChineseCountMethod::Low, value)) 502 | } 503 | 504 | /// 將 `f64` 浮點數轉成中文數字,使用 **「萬進」**。數值的絕對值不能大於或等於 `1e52`。 505 | #[inline] 506 | pub fn from_f64_to_chinese_ten_thousand( 507 | chinese_variant: ChineseVariant, 508 | chinese_case: ChineseCase, 509 | value: f64, 510 | ) -> Result { 511 | if value >= 1e52 { 512 | return Err(NumberToChineseError::Overflow); 513 | } else if value <= -1e52 { 514 | return Err(NumberToChineseError::Underflow); 515 | } 516 | 517 | Ok(from_f64_to_chinese(chinese_variant, chinese_case, ChineseCountMethod::TenThousand, value)) 518 | } 519 | 520 | /// 將 `f64` 浮點數轉成中文數字,使用 **「中數」**。數值的絕對值不能大於或等於 `1e96`。 521 | #[inline] 522 | pub fn from_f64_to_chinese_middle( 523 | chinese_variant: ChineseVariant, 524 | chinese_case: ChineseCase, 525 | value: f64, 526 | ) -> Result { 527 | if value >= 1e96 { 528 | return Err(NumberToChineseError::Overflow); 529 | } else if value <= -1e96 { 530 | return Err(NumberToChineseError::Underflow); 531 | } 532 | 533 | Ok(from_f64_to_chinese(chinese_variant, chinese_case, ChineseCountMethod::Middle, value)) 534 | } 535 | 536 | /// 將 `f64` 浮點數轉成中文數字,使用 **「上數」**。 537 | #[inline] 538 | pub fn from_f64_to_chinese_high( 539 | chinese_variant: ChineseVariant, 540 | chinese_case: ChineseCase, 541 | value: f64, 542 | ) -> String { 543 | from_f64_to_chinese(chinese_variant, chinese_case, ChineseCountMethod::High, value) 544 | } 545 | -------------------------------------------------------------------------------- /src/number_to_chinese/naive.rs: -------------------------------------------------------------------------------- 1 | use alloc::{ 2 | string::{String, ToString}, 3 | vec::Vec, 4 | }; 5 | 6 | use chinese_variant::ChineseVariant; 7 | use num_bigint::BigUint; 8 | #[cfg(not(feature = "std"))] 9 | #[allow(unused_imports)] 10 | use num_traits::float::FloatCore; 11 | use num_traits::{FromPrimitive, ToPrimitive, Zero}; 12 | 13 | use crate::{ 14 | chinese_characters::{ChineseNumber, ChinesePoint, ChineseSign}, 15 | ChineseCase, 16 | }; 17 | 18 | fn unsigned_integer_to_chinese( 19 | chinese_variant: ChineseVariant, 20 | chinese_case: ChineseCase, 21 | mut value: u128, 22 | ) -> String { 23 | if value == 0 { 24 | return ChineseNumber::零.to_str(chinese_variant, chinese_case).to_string(); 25 | } 26 | 27 | let mut numbers: Vec = Vec::with_capacity(1); 28 | 29 | while value > 0 { 30 | let n = (value % 10) as u8; 31 | value /= 10; 32 | 33 | numbers.push(unsafe { ChineseNumber::from_ordinal_unsafe(n) }); 34 | } 35 | 36 | numbers.into_iter().rev().map(|cn| cn.to_str(chinese_variant, chinese_case)).collect() 37 | } 38 | 39 | fn big_unsigned_integer_to_chinese( 40 | chinese_variant: ChineseVariant, 41 | chinese_case: ChineseCase, 42 | mut value: BigUint, 43 | ) -> String { 44 | let big_0 = BigUint::zero(); 45 | let big_10 = BigUint::from(10u8); 46 | 47 | if value == big_0 { 48 | return ChineseNumber::零.to_str(chinese_variant, chinese_case).to_string(); 49 | } 50 | 51 | let mut numbers: Vec = Vec::with_capacity(1); 52 | 53 | while value > big_0 { 54 | let n = (value.clone() % &big_10).to_u8().unwrap(); 55 | value /= &big_10; 56 | 57 | numbers.push(unsafe { ChineseNumber::from_ordinal_unsafe(n) }); 58 | } 59 | 60 | numbers.into_iter().rev().map(|cn| cn.to_str(chinese_variant, chinese_case)).collect() 61 | } 62 | 63 | fn positive_float_to_chinese( 64 | chinese_variant: ChineseVariant, 65 | chinese_case: ChineseCase, 66 | value: f64, 67 | ) -> String { 68 | let (integer, fraction) = { 69 | let integer = BigUint::from_f64(value.trunc()).unwrap(); 70 | let fraction = ((value.fract() * 100.0).round() % 100f64) as u8; 71 | 72 | (integer, fraction) 73 | }; 74 | 75 | let mut s = big_unsigned_integer_to_chinese(chinese_variant, chinese_case, integer); 76 | 77 | if fraction > 0 { 78 | s.push_str(ChinesePoint::to_str(chinese_variant)); 79 | 80 | s.push_str( 81 | unsafe { ChineseNumber::from_ordinal_unsafe(fraction / 10) } 82 | .to_str(chinese_variant, chinese_case), 83 | ); 84 | 85 | let d = fraction % 10; 86 | 87 | if d > 0 { 88 | s.push_str( 89 | unsafe { ChineseNumber::from_ordinal_unsafe(d) } 90 | .to_str(chinese_variant, chinese_case), 91 | ); 92 | } 93 | } 94 | 95 | s 96 | } 97 | 98 | /// 將 `u8` 整數轉成中文數字,不進行單位計算。 99 | #[inline] 100 | pub fn from_u8_to_chinese_naive( 101 | chinese_variant: ChineseVariant, 102 | chinese_case: ChineseCase, 103 | value: u8, 104 | ) -> String { 105 | from_u128_to_chinese_naive(chinese_variant, chinese_case, value as u128) 106 | } 107 | 108 | /// 將 `u16` 整數轉成中文數字,不進行單位計算。 109 | #[inline] 110 | pub fn from_u16_to_chinese_naive( 111 | chinese_variant: ChineseVariant, 112 | chinese_case: ChineseCase, 113 | value: u16, 114 | ) -> String { 115 | from_u128_to_chinese_naive(chinese_variant, chinese_case, value as u128) 116 | } 117 | 118 | /// 將 `u32` 整數轉成中文數字,不進行單位計算。 119 | #[inline] 120 | pub fn from_u32_to_chinese_naive( 121 | chinese_variant: ChineseVariant, 122 | chinese_case: ChineseCase, 123 | value: u32, 124 | ) -> String { 125 | from_u128_to_chinese_naive(chinese_variant, chinese_case, value as u128) 126 | } 127 | 128 | /// 將 `u32` 整數轉成中文數字,不進行單位計算。 129 | #[inline] 130 | pub fn from_u64_to_chinese_naive( 131 | chinese_variant: ChineseVariant, 132 | chinese_case: ChineseCase, 133 | value: u64, 134 | ) -> String { 135 | from_u128_to_chinese_naive(chinese_variant, chinese_case, value as u128) 136 | } 137 | 138 | /// 將 `u128` 整數轉成中文數字,不進行單位計算。 139 | #[inline] 140 | pub fn from_u128_to_chinese_naive( 141 | chinese_variant: ChineseVariant, 142 | chinese_case: ChineseCase, 143 | value: u128, 144 | ) -> String { 145 | unsigned_integer_to_chinese(chinese_variant, chinese_case, value) 146 | } 147 | 148 | /// 將 `usize` 整數轉成中文數字,不進行單位計算。 149 | #[inline] 150 | pub fn from_usize_to_chinese_naive( 151 | chinese_variant: ChineseVariant, 152 | chinese_case: ChineseCase, 153 | value: usize, 154 | ) -> String { 155 | unsigned_integer_to_chinese(chinese_variant, chinese_case, value as u128) 156 | } 157 | 158 | /// 將 `i8` 整數轉成中文數字。不進行單位計算。 159 | #[inline] 160 | pub fn from_i8_to_chinese_naive( 161 | chinese_variant: ChineseVariant, 162 | chinese_case: ChineseCase, 163 | value: i8, 164 | ) -> String { 165 | from_i128_to_chinese_naive(chinese_variant, chinese_case, value as i128) 166 | } 167 | 168 | /// 將 `i16` 整數轉成中文數字。不進行單位計算。 169 | #[inline] 170 | pub fn from_i16_to_chinese_naive( 171 | chinese_variant: ChineseVariant, 172 | chinese_case: ChineseCase, 173 | value: i16, 174 | ) -> String { 175 | from_i128_to_chinese_naive(chinese_variant, chinese_case, value as i128) 176 | } 177 | 178 | /// 將 `i32` 整數轉成中文數字。不進行單位計算。 179 | #[inline] 180 | pub fn from_i32_to_chinese_naive( 181 | chinese_variant: ChineseVariant, 182 | chinese_case: ChineseCase, 183 | value: i32, 184 | ) -> String { 185 | from_i128_to_chinese_naive(chinese_variant, chinese_case, value as i128) 186 | } 187 | 188 | /// 將 `i64` 整數轉成中文數字。不進行單位計算。 189 | #[inline] 190 | pub fn from_i64_to_chinese_naive( 191 | chinese_variant: ChineseVariant, 192 | chinese_case: ChineseCase, 193 | value: i64, 194 | ) -> String { 195 | from_i128_to_chinese_naive(chinese_variant, chinese_case, value as i128) 196 | } 197 | 198 | /// 將 `i128` 整數轉成中文數字,不進行單位計算。 199 | #[inline] 200 | pub fn from_i128_to_chinese_naive( 201 | chinese_variant: ChineseVariant, 202 | chinese_case: ChineseCase, 203 | value: i128, 204 | ) -> String { 205 | if value < 0 { 206 | let mut s = 207 | from_u128_to_chinese_naive(chinese_variant, chinese_case, -(value + 1) as u128 + 1); 208 | 209 | s.insert_str(0, ChineseSign::負.to_str(chinese_variant)); 210 | 211 | s 212 | } else { 213 | from_u128_to_chinese_naive(chinese_variant, chinese_case, value as u128) 214 | } 215 | } 216 | 217 | /// 將 `isize` 整數轉成中文數字,不進行單位計算。 218 | #[inline] 219 | pub fn from_isize_to_chinese_naive( 220 | chinese_variant: ChineseVariant, 221 | chinese_case: ChineseCase, 222 | value: isize, 223 | ) -> String { 224 | from_i128_to_chinese_naive(chinese_variant, chinese_case, value as i128) 225 | } 226 | 227 | /// 將 `f32` 整數轉成中文數字,不進行單位計算。 228 | #[inline] 229 | pub fn from_f32_to_chinese_naive( 230 | chinese_variant: ChineseVariant, 231 | chinese_case: ChineseCase, 232 | value: f32, 233 | ) -> String { 234 | from_f64_to_chinese_naive(chinese_variant, chinese_case, value as f64) 235 | } 236 | 237 | #[inline] 238 | fn from_f64_to_chinese( 239 | chinese_variant: ChineseVariant, 240 | chinese_case: ChineseCase, 241 | value: f64, 242 | ) -> String { 243 | if value < 0.0 { 244 | let mut s = positive_float_to_chinese(chinese_variant, chinese_case, -value); 245 | 246 | s.insert_str(0, ChineseSign::負.to_str(chinese_variant)); 247 | 248 | s 249 | } else { 250 | positive_float_to_chinese(chinese_variant, chinese_case, value) 251 | } 252 | } 253 | 254 | /// 將 `f64` 浮點數轉成中文數字,不進行單位計算。 255 | #[inline] 256 | pub fn from_f64_to_chinese_naive( 257 | chinese_variant: ChineseVariant, 258 | chinese_case: ChineseCase, 259 | value: f64, 260 | ) -> String { 261 | from_f64_to_chinese(chinese_variant, chinese_case, value) 262 | } 263 | -------------------------------------------------------------------------------- /src/number_to_chinese/number_to_chinese_error.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Formatter}; 2 | #[cfg(feature = "std")] 3 | use std::error::Error; 4 | 5 | /// 將數值轉成中文數字時發生的錯誤。 6 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 7 | pub enum NumberToChineseError { 8 | Overflow, 9 | Underflow, 10 | } 11 | 12 | impl Display for NumberToChineseError { 13 | #[inline] 14 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { 15 | match self { 16 | NumberToChineseError::Overflow => f.write_str("number is too large"), 17 | NumberToChineseError::Underflow => f.write_str("number is too small"), 18 | } 19 | } 20 | } 21 | 22 | #[cfg(feature = "std")] 23 | impl Error for NumberToChineseError {} 24 | -------------------------------------------------------------------------------- /src/number_to_chinese/traits.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | /// 讓 Rust 程式語言的所有基本數值型別擁有轉成中文數字的能力。 4 | pub trait NumberToChinese { 5 | /// 將數值轉成中文數字。 6 | /// 7 | /// * 如果使用 **「下數」**,則數值的絕對值不能大於或等於 `1_0000_0000_0000_0000`。 8 | /// * 如果使用 **「萬進」**,則數值的絕對值不能大於或等於 `1e52`。 9 | /// * 如果使用 **「中數」**,則數值的絕對值不能大於或等於 `1e96`。 10 | /// 11 | /// ## 範例 12 | /// 13 | /// ```rust 14 | /// use chinese_number::{ChineseCase, ChineseCountMethod, ChineseVariant, NumberToChinese}; 15 | /// 16 | /// assert_eq!("一百二十三京四千五百六十七兆八千九百零一億二千三百四十五萬六千七百八十九", 1234567890123456789u64.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::TenThousand).unwrap()); 17 | /// ``` 18 | fn to_chinese( 19 | self, 20 | chinese_variant: ChineseVariant, 21 | chinese_case: ChineseCase, 22 | method: ChineseCountMethod, 23 | ) -> Result; 24 | 25 | /// 將數值直接轉成中文數字,不進行單位計算。 26 | /// 27 | /// ## 範例 28 | /// 29 | /// ```rust 30 | /// use chinese_number::{ 31 | /// ChineseCase, ChineseCountMethod, ChineseVariant, NumberToChinese, 32 | /// }; 33 | /// 34 | /// assert_eq!( 35 | /// "一二三四五六七八九", 36 | /// 123456789 37 | /// .to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 38 | /// ); 39 | /// ``` 40 | fn to_chinese_naive(self, chinese_variant: ChineseVariant, chinese_case: ChineseCase) 41 | -> String; 42 | } 43 | 44 | impl NumberToChinese for u8 { 45 | #[inline] 46 | fn to_chinese( 47 | self, 48 | chinese_variant: ChineseVariant, 49 | chinese_case: ChineseCase, 50 | method: ChineseCountMethod, 51 | ) -> Result { 52 | (self as u128).to_chinese(chinese_variant, chinese_case, method) 53 | } 54 | 55 | #[inline] 56 | fn to_chinese_naive( 57 | self, 58 | chinese_variant: ChineseVariant, 59 | chinese_case: ChineseCase, 60 | ) -> String { 61 | from_u8_to_chinese_naive(chinese_variant, chinese_case, self) 62 | } 63 | } 64 | 65 | impl NumberToChinese for i8 { 66 | #[inline] 67 | fn to_chinese( 68 | self, 69 | chinese_variant: ChineseVariant, 70 | chinese_case: ChineseCase, 71 | method: ChineseCountMethod, 72 | ) -> Result { 73 | (self as i128).to_chinese(chinese_variant, chinese_case, method) 74 | } 75 | 76 | #[inline] 77 | fn to_chinese_naive( 78 | self, 79 | chinese_variant: ChineseVariant, 80 | chinese_case: ChineseCase, 81 | ) -> String { 82 | from_i8_to_chinese_naive(chinese_variant, chinese_case, self) 83 | } 84 | } 85 | 86 | impl NumberToChinese for u16 { 87 | #[inline] 88 | fn to_chinese( 89 | self, 90 | chinese_variant: ChineseVariant, 91 | chinese_case: ChineseCase, 92 | method: ChineseCountMethod, 93 | ) -> Result { 94 | (self as u128).to_chinese(chinese_variant, chinese_case, method) 95 | } 96 | 97 | #[inline] 98 | fn to_chinese_naive( 99 | self, 100 | chinese_variant: ChineseVariant, 101 | chinese_case: ChineseCase, 102 | ) -> String { 103 | from_u16_to_chinese_naive(chinese_variant, chinese_case, self) 104 | } 105 | } 106 | 107 | impl NumberToChinese for i16 { 108 | #[inline] 109 | fn to_chinese( 110 | self, 111 | chinese_variant: ChineseVariant, 112 | chinese_case: ChineseCase, 113 | method: ChineseCountMethod, 114 | ) -> Result { 115 | (self as i128).to_chinese(chinese_variant, chinese_case, method) 116 | } 117 | 118 | #[inline] 119 | fn to_chinese_naive( 120 | self, 121 | chinese_variant: ChineseVariant, 122 | chinese_case: ChineseCase, 123 | ) -> String { 124 | from_i16_to_chinese_naive(chinese_variant, chinese_case, self) 125 | } 126 | } 127 | 128 | impl NumberToChinese for u32 { 129 | #[inline] 130 | fn to_chinese( 131 | self, 132 | chinese_variant: ChineseVariant, 133 | chinese_case: ChineseCase, 134 | method: ChineseCountMethod, 135 | ) -> Result { 136 | (self as u128).to_chinese(chinese_variant, chinese_case, method) 137 | } 138 | 139 | #[inline] 140 | fn to_chinese_naive( 141 | self, 142 | chinese_variant: ChineseVariant, 143 | chinese_case: ChineseCase, 144 | ) -> String { 145 | from_u32_to_chinese_naive(chinese_variant, chinese_case, self) 146 | } 147 | } 148 | 149 | impl NumberToChinese for i32 { 150 | #[inline] 151 | fn to_chinese( 152 | self, 153 | chinese_variant: ChineseVariant, 154 | chinese_case: ChineseCase, 155 | method: ChineseCountMethod, 156 | ) -> Result { 157 | (self as i128).to_chinese(chinese_variant, chinese_case, method) 158 | } 159 | 160 | #[inline] 161 | fn to_chinese_naive( 162 | self, 163 | chinese_variant: ChineseVariant, 164 | chinese_case: ChineseCase, 165 | ) -> String { 166 | from_i32_to_chinese_naive(chinese_variant, chinese_case, self) 167 | } 168 | } 169 | 170 | impl NumberToChinese for u64 { 171 | #[inline] 172 | fn to_chinese( 173 | self, 174 | chinese_variant: ChineseVariant, 175 | chinese_case: ChineseCase, 176 | method: ChineseCountMethod, 177 | ) -> Result { 178 | (self as u128).to_chinese(chinese_variant, chinese_case, method) 179 | } 180 | 181 | #[inline] 182 | fn to_chinese_naive( 183 | self, 184 | chinese_variant: ChineseVariant, 185 | chinese_case: ChineseCase, 186 | ) -> String { 187 | from_u64_to_chinese_naive(chinese_variant, chinese_case, self) 188 | } 189 | } 190 | 191 | impl NumberToChinese for i64 { 192 | #[inline] 193 | fn to_chinese( 194 | self, 195 | chinese_variant: ChineseVariant, 196 | chinese_case: ChineseCase, 197 | method: ChineseCountMethod, 198 | ) -> Result { 199 | (self as i128).to_chinese(chinese_variant, chinese_case, method) 200 | } 201 | 202 | #[inline] 203 | fn to_chinese_naive( 204 | self, 205 | chinese_variant: ChineseVariant, 206 | chinese_case: ChineseCase, 207 | ) -> String { 208 | from_i64_to_chinese_naive(chinese_variant, chinese_case, self) 209 | } 210 | } 211 | 212 | impl NumberToChinese for u128 { 213 | #[inline] 214 | fn to_chinese( 215 | self, 216 | chinese_variant: ChineseVariant, 217 | chinese_case: ChineseCase, 218 | method: ChineseCountMethod, 219 | ) -> Result { 220 | match method { 221 | ChineseCountMethod::Low => { 222 | from_u128_to_chinese_low(chinese_variant, chinese_case, self) 223 | }, 224 | ChineseCountMethod::TenThousand => { 225 | Ok(from_u128_to_chinese_ten_thousand(chinese_variant, chinese_case, self)) 226 | }, 227 | ChineseCountMethod::Middle => { 228 | Ok(from_u128_to_chinese_middle(chinese_variant, chinese_case, self)) 229 | }, 230 | ChineseCountMethod::High => { 231 | Ok(from_u128_to_chinese_high(chinese_variant, chinese_case, self)) 232 | }, 233 | } 234 | } 235 | 236 | #[inline] 237 | fn to_chinese_naive( 238 | self, 239 | chinese_variant: ChineseVariant, 240 | chinese_case: ChineseCase, 241 | ) -> String { 242 | from_u128_to_chinese_naive(chinese_variant, chinese_case, self) 243 | } 244 | } 245 | 246 | impl NumberToChinese for i128 { 247 | #[inline] 248 | fn to_chinese( 249 | self, 250 | chinese_variant: ChineseVariant, 251 | chinese_case: ChineseCase, 252 | method: ChineseCountMethod, 253 | ) -> Result { 254 | match method { 255 | ChineseCountMethod::Low => { 256 | from_i128_to_chinese_low(chinese_variant, chinese_case, self) 257 | }, 258 | ChineseCountMethod::TenThousand => { 259 | Ok(from_i128_to_chinese_ten_thousand(chinese_variant, chinese_case, self)) 260 | }, 261 | ChineseCountMethod::Middle => { 262 | Ok(from_i128_to_chinese_middle(chinese_variant, chinese_case, self)) 263 | }, 264 | ChineseCountMethod::High => { 265 | Ok(from_i128_to_chinese_high(chinese_variant, chinese_case, self)) 266 | }, 267 | } 268 | } 269 | 270 | #[inline] 271 | fn to_chinese_naive( 272 | self, 273 | chinese_variant: ChineseVariant, 274 | chinese_case: ChineseCase, 275 | ) -> String { 276 | from_i128_to_chinese_naive(chinese_variant, chinese_case, self) 277 | } 278 | } 279 | 280 | impl NumberToChinese for f32 { 281 | #[inline] 282 | fn to_chinese( 283 | self, 284 | chinese_variant: ChineseVariant, 285 | chinese_case: ChineseCase, 286 | method: ChineseCountMethod, 287 | ) -> Result { 288 | (self as f64).to_chinese(chinese_variant, chinese_case, method) 289 | } 290 | 291 | #[inline] 292 | fn to_chinese_naive( 293 | self, 294 | chinese_variant: ChineseVariant, 295 | chinese_case: ChineseCase, 296 | ) -> String { 297 | from_f32_to_chinese_naive(chinese_variant, chinese_case, self) 298 | } 299 | } 300 | 301 | impl NumberToChinese for f64 { 302 | #[inline] 303 | fn to_chinese( 304 | self, 305 | chinese_variant: ChineseVariant, 306 | chinese_case: ChineseCase, 307 | method: ChineseCountMethod, 308 | ) -> Result { 309 | match method { 310 | ChineseCountMethod::Low => from_f64_to_chinese_low(chinese_variant, chinese_case, self), 311 | ChineseCountMethod::TenThousand => { 312 | from_f64_to_chinese_ten_thousand(chinese_variant, chinese_case, self) 313 | }, 314 | ChineseCountMethod::Middle => { 315 | from_f64_to_chinese_middle(chinese_variant, chinese_case, self) 316 | }, 317 | ChineseCountMethod::High => { 318 | Ok(from_f64_to_chinese_high(chinese_variant, chinese_case, self)) 319 | }, 320 | } 321 | } 322 | 323 | #[inline] 324 | fn to_chinese_naive( 325 | self, 326 | chinese_variant: ChineseVariant, 327 | chinese_case: ChineseCase, 328 | ) -> String { 329 | from_f64_to_chinese_naive(chinese_variant, chinese_case, self) 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /tests/chinese_to_number.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "chinese-to-number")] 2 | 3 | use assert_eq_float::assert_eq_float; 4 | use chinese_number::{ChineseCountMethod, ChineseToNumber, ChineseToNumberError}; 5 | 6 | macro_rules! test_group { 7 | ($method:expr) => { 8 | macro_rules! test { 9 | ($expect: expr,$value: expr) => { 10 | assert_eq!($expect, $value.to_number($method).unwrap()); 11 | }; 12 | } 13 | 14 | macro_rules! test_float { 15 | ($expect: expr,$value: expr) => { 16 | assert_eq_float!($expect, $value.to_number($method).unwrap()); 17 | }; 18 | 19 | ($expect: expr,$value: expr,$error: expr) => { 20 | assert_eq_float!($expect, $value.to_number($method).unwrap(), $error); 21 | }; 22 | } 23 | 24 | macro_rules! test_err { 25 | ($expect: expr,$value: expr) => { 26 | test_err!(i8, $expect, $value); 27 | test_err!(u8, $expect, $value); 28 | test_err!(i16, $expect, $value); 29 | test_err!(u16, $expect, $value); 30 | test_err!(i32, $expect, $value); 31 | test_err!(u32, $expect, $value); 32 | test_err!(i64, $expect, $value); 33 | test_err!(u64, $expect, $value); 34 | test_err!(i128, $expect, $value); 35 | test_err!(u128, $expect, $value); 36 | test_err!(isize, $expect, $value); 37 | test_err!(usize, $expect, $value); 38 | test_err!(f32, $expect, $value); 39 | test_err!(f64, $expect, $value); 40 | }; 41 | ($typ: ty,$expect: expr,$value: expr) => { 42 | assert_eq!(Err::<$typ, _>($expect), $value.to_number($method)); 43 | }; 44 | } 45 | }; 46 | } 47 | 48 | macro_rules! test_group_naive { 49 | () => { 50 | macro_rules! test { 51 | ($expect: expr,$value: expr) => { 52 | assert_eq!($expect, $value.to_number_naive().unwrap()); 53 | }; 54 | } 55 | 56 | macro_rules! test_float { 57 | ($expect: expr,$value: expr) => { 58 | assert_eq_float!($expect, $value.to_number_naive().unwrap()); 59 | }; 60 | 61 | ($expect: expr,$value: expr,$error: expr) => { 62 | assert_eq_float!($expect, $value.to_number_naive().unwrap(), $error); 63 | }; 64 | } 65 | 66 | macro_rules! test_err { 67 | ($expect: expr,$value: expr) => { 68 | test_err!(i8, $expect, $value); 69 | test_err!(u8, $expect, $value); 70 | test_err!(i16, $expect, $value); 71 | test_err!(u16, $expect, $value); 72 | test_err!(i32, $expect, $value); 73 | test_err!(u32, $expect, $value); 74 | test_err!(i64, $expect, $value); 75 | test_err!(u64, $expect, $value); 76 | test_err!(i128, $expect, $value); 77 | test_err!(u128, $expect, $value); 78 | test_err!(isize, $expect, $value); 79 | test_err!(usize, $expect, $value); 80 | test_err!(f32, $expect, $value); 81 | test_err!(f64, $expect, $value); 82 | }; 83 | ($typ: ty,$expect: expr,$value: expr) => { 84 | assert_eq!(Err::<$typ, _>($expect), $value.to_number_naive()); 85 | }; 86 | } 87 | }; 88 | } 89 | 90 | #[test] 91 | fn to_number_low() { 92 | test_group!(ChineseCountMethod::Low); 93 | 94 | test!(i8::MAX, "壹佰貳拾柒"); 95 | test!(i8::MIN, "負壹佰貳拾捌"); 96 | test!(u8::MAX, "貳佰伍拾伍"); 97 | test!(i16::MAX, "參萬貳仟柒佰陸拾柒"); 98 | test!(i16::MIN, "負參萬貳仟柒佰陸拾捌"); 99 | test!(u16::MAX, "陸萬伍仟伍佰參拾伍"); 100 | test!(i32::MAX, "貳秭壹垓肆京柒兆肆億捌萬參仟陸佰肆拾柒"); 101 | test!(i32::MIN, "負貳秭壹垓肆京柒兆肆億捌萬參仟陸佰肆拾捌"); 102 | test!(u32::MAX, "肆秭貳垓玖京肆兆玖億陸萬柒仟貳佰玖拾伍"); 103 | test!(9999999999999999i64, "玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖"); 104 | test!(-9999999999999999i64, "負玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖"); 105 | test!(9999999999999999u64, "玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖"); 106 | test!(9999999999999999i128, "玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖"); 107 | test!( 108 | -9999999999999999i128, 109 | "負玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖" 110 | ); 111 | test!(9999999999999999u128, "玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖"); 112 | 113 | test_float!(123.46f32, "壹佰貳拾參肆角陸分"); 114 | test_float!(-123.46f32, "負壹佰貳拾參肆角陸分"); 115 | test_float!(123.46f64, "壹佰貳拾參肆角陸分"); 116 | test_float!(-123.46f64, "負壹佰貳拾參肆角陸分"); 117 | 118 | test_err!(ChineseToNumberError::ChineseNumberEmpty, ""); 119 | 120 | test_err!( 121 | ChineseToNumberError::ChineseNumberIncorrect { 122 | char_index: 0 123 | }, 124 | "a" 125 | ); 126 | test_err!( 127 | ChineseToNumberError::ChineseNumberIncorrect { 128 | char_index: 1 129 | }, 130 | "壹佰貳拾佰" 131 | ); 132 | 133 | test_err!(i8, ChineseToNumberError::Overflow, "壹佰貳拾捌"); 134 | test_err!(i8, ChineseToNumberError::Underflow, "負壹佰貳拾玖"); 135 | } 136 | 137 | #[test] 138 | fn to_number_ten_thousand() { 139 | test_group!(ChineseCountMethod::TenThousand); 140 | 141 | test!(i8::MAX, "壹佰貳拾柒"); 142 | test!(i8::MIN, "負壹佰貳拾捌"); 143 | test!(u8::MAX, "貳佰伍拾伍"); 144 | test!(i16::MAX, "參萬貳仟柒佰陸拾柒"); 145 | test!(i16::MIN, "負參萬貳仟柒佰陸拾捌"); 146 | test!(u16::MAX, "陸萬伍仟伍佰參拾伍"); 147 | test!(i32::MAX, "貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾柒"); 148 | test!(i32::MIN, "負貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾捌"); 149 | test!(u32::MAX, "肆拾貳億玖仟肆佰玖拾陸萬柒仟貳佰玖拾伍"); 150 | test!(i64::MAX, "玖佰貳拾貳京參仟參佰柒拾貳兆零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零柒"); 151 | test!(i64::MIN, "負玖佰貳拾貳京參仟參佰柒拾貳兆零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零捌"); 152 | test!(u64::MAX, "壹仟捌佰肆拾肆京陸仟柒佰肆拾肆兆零柒佰參拾柒億零玖佰伍拾伍萬壹仟陸佰壹拾伍"); 153 | test!(i128::MAX, "壹佰柒拾澗壹仟肆佰壹拾壹溝捌仟參佰肆拾陸穰零肆佰陸拾玖秭貳仟參佰壹拾柒垓參仟壹佰陸拾捌京柒仟參佰零參兆柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾柒"); 154 | test!(i128::MIN, "負壹佰柒拾澗壹仟肆佰壹拾壹溝捌仟參佰肆拾陸穰零肆佰陸拾玖秭貳仟參佰壹拾柒垓參仟壹佰陸拾捌京柒仟參佰零參兆柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾捌"); 155 | test!(u128::MAX, "參佰肆拾澗貳仟捌佰貳拾參溝陸仟陸佰玖拾貳穰零玖佰參拾捌秭肆仟陸佰參拾肆垓陸仟參佰參拾柒京肆仟陸佰零柒兆肆仟參佰壹拾柒億陸仟捌佰貳拾壹萬壹仟肆佰伍拾伍"); 156 | 157 | test_float!(123.46f32, "壹佰貳拾參肆角陸分"); 158 | test_float!(-123.46f32, "負壹佰貳拾參肆角陸分"); 159 | test_float!(123.46f64, "壹佰貳拾參肆角陸分"); 160 | test_float!(-123.46f64, "負壹佰貳拾參肆角陸分"); 161 | 162 | test_err!(ChineseToNumberError::ChineseNumberEmpty, ""); 163 | 164 | test_err!( 165 | ChineseToNumberError::ChineseNumberIncorrect { 166 | char_index: 0 167 | }, 168 | "a" 169 | ); 170 | test_err!( 171 | ChineseToNumberError::ChineseNumberIncorrect { 172 | char_index: 1 173 | }, 174 | "壹佰貳拾佰" 175 | ); 176 | 177 | test_err!(i8, ChineseToNumberError::Overflow, "壹佰貳拾捌"); 178 | test_err!(i8, ChineseToNumberError::Underflow, "負壹佰貳拾玖"); 179 | } 180 | 181 | #[test] 182 | fn to_number_middle() { 183 | test_group!(ChineseCountMethod::Middle); 184 | 185 | test!(i8::MAX, "壹佰貳拾柒"); 186 | test!(i8::MIN, "負壹佰貳拾捌"); 187 | test!(u8::MAX, "貳佰伍拾伍"); 188 | test!(i16::MAX, "參萬貳仟柒佰陸拾柒"); 189 | test!(i16::MIN, "負參萬貳仟柒佰陸拾捌"); 190 | test!(u16::MAX, "陸萬伍仟伍佰參拾伍"); 191 | test!(i32::MAX, "貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾柒"); 192 | test!(i32::MIN, "負貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾捌"); 193 | test!(u32::MAX, "肆拾貳億玖仟肆佰玖拾陸萬柒仟貳佰玖拾伍"); 194 | test!(i64::MAX, "玖佰貳拾貳兆參仟參佰柒拾貳萬零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零柒"); 195 | test!(i64::MIN, "負玖佰貳拾貳兆參仟參佰柒拾貳萬零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零捌"); 196 | test!(u64::MAX, "壹仟捌佰肆拾肆兆陸仟柒佰肆拾肆萬零柒佰參拾柒億零玖佰伍拾伍萬壹仟陸佰壹拾伍"); 197 | test!(i128::MAX, "壹佰柒拾萬壹仟肆佰壹拾壹垓捌仟參佰肆拾陸萬零肆佰陸拾玖京貳仟參佰壹拾柒萬參仟壹佰陸拾捌兆柒仟參佰零參萬柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾柒"); 198 | test!(i128::MIN, "負壹佰柒拾萬壹仟肆佰壹拾壹垓捌仟參佰肆拾陸萬零肆佰陸拾玖京貳仟參佰壹拾柒萬參仟壹佰陸拾捌兆柒仟參佰零參萬柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾捌"); 199 | test!(u128::MAX, "參佰肆拾萬貳仟捌佰貳拾參垓陸仟陸佰玖拾貳萬零玖佰參拾捌京肆仟陸佰參拾肆萬陸仟參佰參拾柒兆肆仟陸佰零柒萬肆仟參佰壹拾柒億陸仟捌佰貳拾壹萬壹仟肆佰伍拾伍"); 200 | 201 | test!(123.46f32, "壹佰貳拾參肆角陸分"); 202 | test!(-123.46f32, "負壹佰貳拾參肆角陸分"); 203 | test!(123.46f64, "壹佰貳拾參肆角陸分"); 204 | test!(-123.46f64, "負壹佰貳拾參肆角陸分"); 205 | 206 | test_float!(f32::MAX, "參佰肆拾萬貳仟捌佰貳拾參垓肆仟陸佰陸拾參萬捌仟伍佰貳拾捌京捌仟伍佰玖拾捌萬壹仟壹佰柒拾兆肆仟壹佰捌拾參萬肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾"); 207 | test_float!(f32::MIN, "負參佰肆拾萬貳仟捌佰貳拾參垓肆仟陸佰陸拾參萬捌仟伍佰貳拾捌京捌仟伍佰玖拾捌萬壹仟壹佰柒拾兆肆仟壹佰捌拾參萬肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾"); 208 | test_float!(1e96f64 - 1e81, "玖仟玖佰玖拾玖萬玖仟玖佰玖拾玖極玖仟玖佰玖拾玖萬玖仟玖佰玖拾壹載零壹佰貳拾玖萬貳仟捌佰伍拾捌正玖仟參佰玖拾捌萬壹仟肆佰陸拾貳澗零壹佰零柒萬壹仟壹佰陸拾柒溝伍仟玖佰貳拾玖萬肆仟貳佰陸拾柒穰壹仟貳佰壹拾萬壹仟柒佰伍拾捌秭柒仟壹佰柒拾捌萬伍仟肆佰玖拾陸垓捌仟肆佰肆拾捌萬柒仟柒佰捌拾柒京捌仟陸佰貳拾柒萬柒仟柒佰陸拾貳兆貳仟伍佰陸拾萬壹仟零壹拾億零伍佰萬零柒佰零肆"); 209 | test_float!(-1e96f64 + 1e81, "負玖仟玖佰玖拾玖萬玖仟玖佰玖拾玖極玖仟玖佰玖拾玖萬玖仟玖佰玖拾壹載零壹佰貳拾玖萬貳仟捌佰伍拾捌正玖仟參佰玖拾捌萬壹仟肆佰陸拾貳澗零壹佰零柒萬壹仟壹佰陸拾柒溝伍仟玖佰貳拾玖萬肆仟貳佰陸拾柒穰壹仟貳佰壹拾萬壹仟柒佰伍拾捌秭柒仟壹佰柒拾捌萬伍仟肆佰玖拾陸垓捌仟肆佰肆拾捌萬柒仟柒佰捌拾柒京捌仟陸佰貳拾柒萬柒仟柒佰陸拾貳兆貳仟伍佰陸拾萬壹仟零壹拾億零伍佰萬零柒佰零肆"); 210 | 211 | test_err!(ChineseToNumberError::ChineseNumberEmpty, ""); 212 | 213 | test_err!( 214 | ChineseToNumberError::ChineseNumberIncorrect { 215 | char_index: 0 216 | }, 217 | "a" 218 | ); 219 | test_err!( 220 | ChineseToNumberError::ChineseNumberIncorrect { 221 | char_index: 1 222 | }, 223 | "壹佰貳拾佰" 224 | ); 225 | 226 | test_err!(i8, ChineseToNumberError::Overflow, "壹佰貳拾捌"); 227 | test_err!(i8, ChineseToNumberError::Underflow, "負壹佰貳拾玖"); 228 | } 229 | 230 | #[test] 231 | fn to_number_high() { 232 | test_group!(ChineseCountMethod::High); 233 | 234 | test!(i8::MAX, "壹佰貳拾柒"); 235 | test!(i8::MIN, "負壹佰貳拾捌"); 236 | test!(u8::MAX, "貳佰伍拾伍"); 237 | test!(i16::MAX, "參萬貳仟柒佰陸拾柒"); 238 | test!(i16::MIN, "負參萬貳仟柒佰陸拾捌"); 239 | test!(u16::MAX, "陸萬伍仟伍佰參拾伍"); 240 | test!(i32::MAX, "貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾柒"); 241 | test!(i32::MIN, "負貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾捌"); 242 | test!(u32::MAX, "肆拾貳億玖仟肆佰玖拾陸萬柒仟貳佰玖拾伍"); 243 | test!(i64::MAX, "玖佰貳拾貳兆參仟參佰柒拾貳萬零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零柒"); 244 | test!(i64::MIN, "負玖佰貳拾貳兆參仟參佰柒拾貳萬零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零捌"); 245 | test!(u64::MAX, "壹仟捌佰肆拾肆兆陸仟柒佰肆拾肆萬零柒佰參拾柒億零玖佰伍拾伍萬壹仟陸佰壹拾伍"); 246 | test!(i128::MAX, "壹佰柒拾萬壹仟肆佰壹拾壹京捌仟參佰肆拾陸萬零肆佰陸拾玖億貳仟參佰壹拾柒萬參仟壹佰陸拾捌兆柒仟參佰零參萬柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾柒"); 247 | test!(i128::MIN, "負壹佰柒拾萬壹仟肆佰壹拾壹京捌仟參佰肆拾陸萬零肆佰陸拾玖億貳仟參佰壹拾柒萬參仟壹佰陸拾捌兆柒仟參佰零參萬柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾捌"); 248 | test!(u128::MAX, "參佰肆拾萬貳仟捌佰貳拾參京陸仟陸佰玖拾貳萬零玖佰參拾捌億肆仟陸佰參拾肆萬陸仟參佰參拾柒兆肆仟陸佰零柒萬肆仟參佰壹拾柒億陸仟捌佰貳拾壹萬壹仟肆佰伍拾伍"); 249 | 250 | test!(123.46f32, "壹佰貳拾參肆角陸分"); 251 | test!(-123.46f32, "負壹佰貳拾參肆角陸分"); 252 | test!(123.46f64, "壹佰貳拾參肆角陸分"); 253 | test!(-123.46f64, "負壹佰貳拾參肆角陸分"); 254 | 255 | test_float!(f32::MAX, "參佰肆拾萬貳仟捌佰貳拾參京肆仟陸佰陸拾參萬捌仟伍佰貳拾捌億捌仟伍佰玖拾捌萬壹仟壹佰柒拾兆肆仟壹佰捌拾參萬肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾"); 256 | test_float!(f32::MIN, "負參佰肆拾萬貳仟捌佰貳拾參京肆仟陸佰陸拾參萬捌仟伍佰貳拾捌億捌仟伍佰玖拾捌萬壹仟壹佰柒拾兆肆仟壹佰捌拾參萬肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾"); 257 | 258 | // the Chinese needs to avoid being converted to Infinite 259 | test_float!( 260 | f64::MAX, 261 | "壹萬柒仟玖佰柒拾陸兆玖仟參佰壹拾參萬肆仟捌佰陸拾貳億參仟壹佰萬京穰", 262 | 4.4e293 263 | ); 264 | test_float!( 265 | f64::MIN, 266 | "負壹萬柒仟玖佰柒拾陸兆玖仟參佰壹拾參萬肆仟捌佰陸拾貳億參仟壹佰萬京穰", 267 | 4.4e293 268 | ); 269 | 270 | test_err!(ChineseToNumberError::ChineseNumberEmpty, ""); 271 | 272 | test_err!( 273 | ChineseToNumberError::ChineseNumberIncorrect { 274 | char_index: 0 275 | }, 276 | "a" 277 | ); 278 | test_err!( 279 | ChineseToNumberError::ChineseNumberIncorrect { 280 | char_index: 1 281 | }, 282 | "壹佰貳拾佰" 283 | ); 284 | 285 | test_err!(i8, ChineseToNumberError::Overflow, "壹佰貳拾捌"); 286 | test_err!(i8, ChineseToNumberError::Underflow, "負壹佰貳拾玖"); 287 | } 288 | 289 | #[test] 290 | fn to_number_naive() { 291 | test_group_naive!(); 292 | 293 | test!(i8::MAX, "壹貳柒"); 294 | test!(i8::MIN, "負壹貳捌"); 295 | test!(u8::MAX, "貳伍伍"); 296 | test!(i16::MAX, "參貳柒陸柒"); 297 | test!(i16::MIN, "負參貳柒陸捌"); 298 | test!(u16::MAX, "陸伍伍參伍"); 299 | test!(i32::MAX, "貳壹肆柒肆捌參陸肆柒"); 300 | test!(i32::MIN, "負貳壹肆柒肆捌參陸肆捌"); 301 | test!(u32::MAX, "肆貳玖肆玖陸柒貳玖伍"); 302 | test!(i64::MAX, "玖貳貳參參柒貳零參陸捌伍肆柒柒伍捌零柒"); 303 | test!(i64::MIN, "負玖貳貳參參柒貳零參陸捌伍肆柒柒伍捌零捌"); 304 | test!(u64::MAX, "壹捌肆肆陸柒肆肆零柒參柒零玖伍伍壹陸壹伍"); 305 | test!( 306 | i128::MAX, 307 | "壹柒零壹肆壹壹捌參肆陸零肆陸玖貳參壹柒參壹陸捌柒參零參柒壹伍捌捌肆壹零伍柒貳柒" 308 | ); 309 | test!( 310 | i128::MIN, 311 | "負壹柒零壹肆壹壹捌參肆陸零肆陸玖貳參壹柒參壹陸捌柒參零參柒壹伍捌捌肆壹零伍柒貳捌" 312 | ); 313 | test!( 314 | u128::MAX, 315 | "參肆零貳捌貳參陸陸玖貳零玖參捌肆陸參肆陸參參柒肆陸零柒肆參壹柒陸捌貳壹壹肆伍伍" 316 | ); 317 | 318 | test_float!(123.46f32, "壹貳參點肆陸"); 319 | test_float!(-123.46f32, "負壹貳參點肆陸"); 320 | test_float!(123.46f64, "壹貳參點肆陸"); 321 | test_float!(-123.46f64, "負壹貳參點肆陸"); 322 | 323 | test_err!(ChineseToNumberError::ChineseNumberEmpty, ""); 324 | 325 | test_err!( 326 | ChineseToNumberError::ChineseNumberIncorrect { 327 | char_index: 0 328 | }, 329 | "a" 330 | ); 331 | test_err!( 332 | ChineseToNumberError::ChineseNumberIncorrect { 333 | char_index: 1 334 | }, 335 | "壹佰貳拾佰" 336 | ); 337 | 338 | test_err!(i8, ChineseToNumberError::Overflow, "壹貳捌"); 339 | test_err!(i8, ChineseToNumberError::Underflow, "負壹貳玖"); 340 | } 341 | -------------------------------------------------------------------------------- /tests/number_to_chinese.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "number-to-chinese")] 2 | 3 | use chinese_number::{ 4 | ChineseCase, ChineseCountMethod, ChineseVariant, NumberToChinese, NumberToChineseError, 5 | }; 6 | 7 | macro_rules! test_group { 8 | ($case:expr, $method:expr) => { 9 | macro_rules! test { 10 | ($expect: expr,$value: expr) => { 11 | assert_eq!( 12 | $expect, 13 | $value.to_chinese(ChineseVariant::Traditional, $case, $method).unwrap() 14 | ); 15 | }; 16 | } 17 | 18 | #[allow(unused)] 19 | macro_rules! test_err { 20 | ($expect: expr,$value: expr) => { 21 | assert_eq!( 22 | Err($expect), 23 | $value.to_chinese(ChineseVariant::Traditional, $case, $method) 24 | ); 25 | }; 26 | } 27 | }; 28 | } 29 | 30 | macro_rules! test_group_naive { 31 | ($case:expr) => { 32 | macro_rules! test { 33 | ($expect: expr,$value: expr) => { 34 | assert_eq!($expect, $value.to_chinese_naive(ChineseVariant::Traditional, $case)); 35 | }; 36 | } 37 | }; 38 | } 39 | 40 | #[test] 41 | fn to_uppercase_low() { 42 | test_group!(ChineseCase::Upper, ChineseCountMethod::Low); 43 | 44 | test!("壹佰貳拾柒", i8::MAX); 45 | test!("負壹佰貳拾捌", i8::MIN); 46 | test!("貳佰伍拾伍", u8::MAX); 47 | test!("參萬貳仟柒佰陸拾柒", i16::MAX); 48 | test!("負參萬貳仟柒佰陸拾捌", i16::MIN); 49 | test!("陸萬伍仟伍佰參拾伍", u16::MAX); 50 | test!("貳秭壹垓肆京柒兆肆億捌萬參仟陸佰肆拾柒", i32::MAX); 51 | test!("負貳秭壹垓肆京柒兆肆億捌萬參仟陸佰肆拾捌", i32::MIN); 52 | test!("肆秭貳垓玖京肆兆玖億陸萬柒仟貳佰玖拾伍", u32::MAX); 53 | test!("玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖", 9999999999999999i64); 54 | test!("負玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖", -9999999999999999i64); 55 | test!("玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖", 9999999999999999u64); 56 | test!("玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖", 9999999999999999i128); 57 | test!( 58 | "負玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖", 59 | -9999999999999999i128 60 | ); 61 | test!("玖極玖載玖正玖澗玖溝玖穰玖秭玖垓玖京玖兆玖億玖萬玖仟玖佰玖拾玖", 9999999999999999u128); 62 | 63 | test!("壹佰貳拾參肆角陸分", 123.456f32); 64 | test!("負壹佰貳拾參肆角陸分", -123.456f32); 65 | test!("壹佰貳拾參肆角陸分", 123.456f64); 66 | test!("負壹佰貳拾參肆角陸分", -123.456f64); 67 | 68 | test_err!(NumberToChineseError::Overflow, i128::MAX); 69 | test_err!(NumberToChineseError::Underflow, i128::MIN); 70 | test_err!(NumberToChineseError::Overflow, u128::MAX); 71 | test_err!(NumberToChineseError::Overflow, f32::MAX); 72 | test_err!(NumberToChineseError::Underflow, f32::MIN); 73 | test_err!(NumberToChineseError::Overflow, f64::MAX); 74 | test_err!(NumberToChineseError::Underflow, f64::MIN); 75 | } 76 | 77 | #[test] 78 | fn to_uppercase_ten_thousand() { 79 | test_group!(ChineseCase::Upper, ChineseCountMethod::TenThousand); 80 | 81 | test!("壹佰貳拾柒", i8::MAX); 82 | test!("負壹佰貳拾捌", i8::MIN); 83 | test!("貳佰伍拾伍", u8::MAX); 84 | test!("參萬貳仟柒佰陸拾柒", i16::MAX); 85 | test!("負參萬貳仟柒佰陸拾捌", i16::MIN); 86 | test!("陸萬伍仟伍佰參拾伍", u16::MAX); 87 | test!("貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾柒", i32::MAX); 88 | test!("負貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾捌", i32::MIN); 89 | test!("肆拾貳億玖仟肆佰玖拾陸萬柒仟貳佰玖拾伍", u32::MAX); 90 | test!("玖佰貳拾貳京參仟參佰柒拾貳兆零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零柒", i64::MAX); 91 | test!("負玖佰貳拾貳京參仟參佰柒拾貳兆零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零捌", i64::MIN); 92 | test!("壹仟捌佰肆拾肆京陸仟柒佰肆拾肆兆零柒佰參拾柒億零玖佰伍拾伍萬壹仟陸佰壹拾伍", u64::MAX); 93 | test!("壹佰柒拾澗壹仟肆佰壹拾壹溝捌仟參佰肆拾陸穰零肆佰陸拾玖秭貳仟參佰壹拾柒垓參仟壹佰陸拾捌京柒仟參佰零參兆柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾柒",i128::MAX); 94 | test!("負壹佰柒拾澗壹仟肆佰壹拾壹溝捌仟參佰肆拾陸穰零肆佰陸拾玖秭貳仟參佰壹拾柒垓參仟壹佰陸拾捌京柒仟參佰零參兆柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾捌",i128::MIN); 95 | test!("參佰肆拾澗貳仟捌佰貳拾參溝陸仟陸佰玖拾貳穰零玖佰參拾捌秭肆仟陸佰參拾肆垓陸仟參佰參拾柒京肆仟陸佰零柒兆肆仟參佰壹拾柒億陸仟捌佰貳拾壹萬壹仟肆佰伍拾伍",u128::MAX); 96 | 97 | test!("壹佰貳拾參肆角陸分", 123.456f32); 98 | test!("負壹佰貳拾參肆角陸分", -123.456f32); 99 | test!("壹佰貳拾參肆角陸分", 123.456f64); 100 | test!("負壹佰貳拾參肆角陸分", -123.456f64); 101 | 102 | test!("參佰肆拾澗貳仟捌佰貳拾參溝肆仟陸佰陸拾參穰捌仟伍佰貳拾捌秭捌仟伍佰玖拾捌垓壹仟壹佰柒拾京肆仟壹佰捌拾參兆肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾",f32::MAX); 103 | test!("負參佰肆拾澗貳仟捌佰貳拾參溝肆仟陸佰陸拾參穰捌仟伍佰貳拾捌秭捌仟伍佰玖拾捌垓壹仟壹佰柒拾京肆仟壹佰捌拾參兆肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾",f32::MIN); 104 | test!("玖仟玖佰玖拾玖極玖仟玖佰玖拾玖載玖仟玖佰玖拾玖正玖仟玖佰捌拾玖澗貳仟玖佰捌拾參溝捌仟伍佰伍拾貳穰零肆佰陸拾肆秭貳仟捌佰玖拾貳垓玖仟陸佰伍拾參京肆仟壹佰陸拾兆陸仟零貳拾壹億柒仟陸佰陸拾捌萬肆仟零參拾貳",1e52f64 - 1e37); 105 | test!("負玖仟玖佰玖拾玖極玖仟玖佰玖拾玖載玖仟玖佰玖拾玖正玖仟玖佰捌拾玖澗貳仟玖佰捌拾參溝捌仟伍佰伍拾貳穰零肆佰陸拾肆秭貳仟捌佰玖拾貳垓玖仟陸佰伍拾參京肆仟壹佰陸拾兆陸仟零貳拾壹億柒仟陸佰陸拾捌萬肆仟零參拾貳",-1e52f64 + 1e37); 106 | 107 | test_err!(NumberToChineseError::Overflow, f64::MAX); 108 | test_err!(NumberToChineseError::Underflow, f64::MIN); 109 | } 110 | 111 | #[test] 112 | fn to_uppercase_middle() { 113 | test_group!(ChineseCase::Upper, ChineseCountMethod::Middle); 114 | 115 | test!("壹佰貳拾柒", i8::MAX); 116 | test!("負壹佰貳拾捌", i8::MIN); 117 | test!("貳佰伍拾伍", u8::MAX); 118 | test!("參萬貳仟柒佰陸拾柒", i16::MAX); 119 | test!("負參萬貳仟柒佰陸拾捌", i16::MIN); 120 | test!("陸萬伍仟伍佰參拾伍", u16::MAX); 121 | test!("貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾柒", i32::MAX); 122 | test!("負貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾捌", i32::MIN); 123 | test!("肆拾貳億玖仟肆佰玖拾陸萬柒仟貳佰玖拾伍", u32::MAX); 124 | test!("玖佰貳拾貳兆參仟參佰柒拾貳萬零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零柒", i64::MAX); 125 | test!("負玖佰貳拾貳兆參仟參佰柒拾貳萬零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零捌", i64::MIN); 126 | test!("壹仟捌佰肆拾肆兆陸仟柒佰肆拾肆萬零柒佰參拾柒億零玖佰伍拾伍萬壹仟陸佰壹拾伍", u64::MAX); 127 | test!("壹佰柒拾萬壹仟肆佰壹拾壹垓捌仟參佰肆拾陸萬零肆佰陸拾玖京貳仟參佰壹拾柒萬參仟壹佰陸拾捌兆柒仟參佰零參萬柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾柒",i128::MAX); 128 | test!("負壹佰柒拾萬壹仟肆佰壹拾壹垓捌仟參佰肆拾陸萬零肆佰陸拾玖京貳仟參佰壹拾柒萬參仟壹佰陸拾捌兆柒仟參佰零參萬柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾捌",i128::MIN); 129 | test!("參佰肆拾萬貳仟捌佰貳拾參垓陸仟陸佰玖拾貳萬零玖佰參拾捌京肆仟陸佰參拾肆萬陸仟參佰參拾柒兆肆仟陸佰零柒萬肆仟參佰壹拾柒億陸仟捌佰貳拾壹萬壹仟肆佰伍拾伍",u128::MAX); 130 | 131 | test!("壹佰貳拾參肆角陸分", 123.456f32); 132 | test!("負壹佰貳拾參肆角陸分", -123.456f32); 133 | test!("壹佰貳拾參肆角陸分", 123.456f64); 134 | test!("負壹佰貳拾參肆角陸分", -123.456f64); 135 | 136 | test!("參佰肆拾萬貳仟捌佰貳拾參垓肆仟陸佰陸拾參萬捌仟伍佰貳拾捌京捌仟伍佰玖拾捌萬壹仟壹佰柒拾兆肆仟壹佰捌拾參萬肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾",f32::MAX); 137 | test!("負參佰肆拾萬貳仟捌佰貳拾參垓肆仟陸佰陸拾參萬捌仟伍佰貳拾捌京捌仟伍佰玖拾捌萬壹仟壹佰柒拾兆肆仟壹佰捌拾參萬肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾",f32::MIN); 138 | test!("玖仟玖佰玖拾玖萬玖仟玖佰玖拾玖極玖仟玖佰玖拾玖萬玖仟玖佰玖拾壹載零壹佰貳拾玖萬貳仟捌佰伍拾捌正玖仟參佰玖拾捌萬壹仟肆佰陸拾貳澗零壹佰零柒萬壹仟壹佰陸拾柒溝伍仟玖佰貳拾玖萬肆仟貳佰陸拾柒穰壹仟貳佰壹拾萬壹仟柒佰伍拾捌秭柒仟壹佰柒拾捌萬伍仟肆佰玖拾陸垓捌仟肆佰肆拾捌萬柒仟柒佰捌拾柒京捌仟陸佰貳拾柒萬柒仟柒佰陸拾貳兆貳仟伍佰陸拾萬壹仟零壹拾億零伍佰萬零柒佰零肆",1e96f64 - 1e81); 139 | test!("負玖仟玖佰玖拾玖萬玖仟玖佰玖拾玖極玖仟玖佰玖拾玖萬玖仟玖佰玖拾壹載零壹佰貳拾玖萬貳仟捌佰伍拾捌正玖仟參佰玖拾捌萬壹仟肆佰陸拾貳澗零壹佰零柒萬壹仟壹佰陸拾柒溝伍仟玖佰貳拾玖萬肆仟貳佰陸拾柒穰壹仟貳佰壹拾萬壹仟柒佰伍拾捌秭柒仟壹佰柒拾捌萬伍仟肆佰玖拾陸垓捌仟肆佰肆拾捌萬柒仟柒佰捌拾柒京捌仟陸佰貳拾柒萬柒仟柒佰陸拾貳兆貳仟伍佰陸拾萬壹仟零壹拾億零伍佰萬零柒佰零肆",-1e96f64 + 1e81); 140 | 141 | test_err!(NumberToChineseError::Overflow, f64::MAX); 142 | test_err!(NumberToChineseError::Underflow, f64::MIN); 143 | } 144 | 145 | #[test] 146 | fn to_uppercase_high() { 147 | test_group!(ChineseCase::Upper, ChineseCountMethod::High); 148 | 149 | test!("壹佰貳拾柒", i8::MAX); 150 | test!("負壹佰貳拾捌", i8::MIN); 151 | test!("貳佰伍拾伍", u8::MAX); 152 | test!("參萬貳仟柒佰陸拾柒", i16::MAX); 153 | test!("負參萬貳仟柒佰陸拾捌", i16::MIN); 154 | test!("陸萬伍仟伍佰參拾伍", u16::MAX); 155 | test!("貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾柒", i32::MAX); 156 | test!("負貳拾壹億肆仟柒佰肆拾捌萬參仟陸佰肆拾捌", i32::MIN); 157 | test!("肆拾貳億玖仟肆佰玖拾陸萬柒仟貳佰玖拾伍", u32::MAX); 158 | test!("玖佰貳拾貳兆參仟參佰柒拾貳萬零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零柒", i64::MAX); 159 | test!("負玖佰貳拾貳兆參仟參佰柒拾貳萬零參佰陸拾捌億伍仟肆佰柒拾柒萬伍仟捌佰零捌", i64::MIN); 160 | test!("壹仟捌佰肆拾肆兆陸仟柒佰肆拾肆萬零柒佰參拾柒億零玖佰伍拾伍萬壹仟陸佰壹拾伍", u64::MAX); 161 | test!("壹佰柒拾萬壹仟肆佰壹拾壹京捌仟參佰肆拾陸萬零肆佰陸拾玖億貳仟參佰壹拾柒萬參仟壹佰陸拾捌兆柒仟參佰零參萬柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾柒",i128::MAX); 162 | test!("負壹佰柒拾萬壹仟肆佰壹拾壹京捌仟參佰肆拾陸萬零肆佰陸拾玖億貳仟參佰壹拾柒萬參仟壹佰陸拾捌兆柒仟參佰零參萬柒仟壹佰伍拾捌億捌仟肆佰壹拾萬伍仟柒佰貳拾捌",i128::MIN); 163 | test!("參佰肆拾萬貳仟捌佰貳拾參京陸仟陸佰玖拾貳萬零玖佰參拾捌億肆仟陸佰參拾肆萬陸仟參佰參拾柒兆肆仟陸佰零柒萬肆仟參佰壹拾柒億陸仟捌佰貳拾壹萬壹仟肆佰伍拾伍",u128::MAX); 164 | 165 | test!("壹佰貳拾參肆角陸分", 123.456f32); 166 | test!("負壹佰貳拾參肆角陸分", -123.456f32); 167 | test!("壹佰貳拾參肆角陸分", 123.456f64); 168 | test!("負壹佰貳拾參肆角陸分", -123.456f64); 169 | 170 | test!("參佰肆拾萬貳仟捌佰貳拾參京肆仟陸佰陸拾參萬捌仟伍佰貳拾捌億捌仟伍佰玖拾捌萬壹仟壹佰柒拾兆肆仟壹佰捌拾參萬肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾",f32::MAX); 171 | test!("負參佰肆拾萬貳仟捌佰貳拾參京肆仟陸佰陸拾參萬捌仟伍佰貳拾捌億捌仟伍佰玖拾捌萬壹仟壹佰柒拾兆肆仟壹佰捌拾參萬肆仟捌佰肆拾伍億壹仟陸佰玖拾貳萬伍仟肆佰肆拾",f32::MIN); 172 | test!("壹萬柒仟玖佰柒拾陸兆玖仟參佰壹拾參萬肆仟捌佰陸拾貳億參仟壹佰伍拾柒萬零捌佰壹拾肆京伍仟貳佰柒拾肆萬貳仟參佰柒拾參億壹仟柒佰零肆萬參仟伍佰陸拾柒兆玖仟捌佰零柒萬零伍佰陸拾柒億伍仟貳佰伍拾捌萬肆仟肆佰玖拾玖穰陸仟伍佰玖拾捌萬玖仟壹佰柒拾肆億柒仟陸佰捌拾萬參仟壹佰伍拾柒兆貳仟陸佰零柒萬捌仟零貳億捌仟伍佰參拾捌萬柒仟陸佰零伍京捌仟玖佰伍拾伍萬捌仟陸佰參拾貳億柒仟陸佰陸拾捌萬柒仟捌佰壹拾柒兆壹仟伍佰肆拾萬肆仟伍佰捌拾玖億伍仟參佰伍拾壹萬肆仟參佰捌拾貳垓肆仟陸佰肆拾貳萬參仟肆佰參拾貳億壹仟參佰貳拾陸萬捌仟捌佰玖拾肆兆陸仟肆佰壹拾捌萬貳仟柒佰陸拾捌億肆仟陸佰柒拾伍萬肆仟陸佰柒拾京參仟伍佰參拾柒萬伍仟壹佰陸拾玖億捌仟陸佰零肆萬玖仟玖佰壹拾兆伍仟柒佰陸拾伍萬伍仟壹佰貳拾捌億貳仟零柒拾陸萬貳仟肆佰伍拾肆秭玖仟零玖萬零參佰捌拾玖億參仟貳佰捌拾玖萬肆仟肆佰零柒兆伍仟捌佰陸拾捌萬伍仟零捌拾肆億伍仟伍佰壹拾參萬參仟玖佰肆拾貳京參仟零肆拾伍萬捌仟參佰貳拾參億陸仟玖佰零參萬貳仟貳佰貳拾玖兆肆仟捌佰壹拾陸萬伍仟捌佰零捌億伍仟伍佰玖拾參萬參仟貳佰壹拾貳垓參仟參佰肆拾捌萬貳仟柒佰肆拾柒億玖仟柒佰捌拾貳萬陸仟貳佰零肆兆壹仟肆佰肆拾柒萬貳仟參佰壹拾陸億捌仟柒佰參拾捌萬壹仟柒佰柒拾壹京捌仟零玖拾壹萬玖仟貳佰玖拾玖億捌仟捌佰壹拾貳萬伍仟零肆拾兆肆仟零貳拾陸萬壹仟捌佰肆拾壹億貳仟肆佰捌拾伍萬捌仟參佰陸拾捌",f64::MAX); 173 | test!("負壹萬柒仟玖佰柒拾陸兆玖仟參佰壹拾參萬肆仟捌佰陸拾貳億參仟壹佰伍拾柒萬零捌佰壹拾肆京伍仟貳佰柒拾肆萬貳仟參佰柒拾參億壹仟柒佰零肆萬參仟伍佰陸拾柒兆玖仟捌佰零柒萬零伍佰陸拾柒億伍仟貳佰伍拾捌萬肆仟肆佰玖拾玖穰陸仟伍佰玖拾捌萬玖仟壹佰柒拾肆億柒仟陸佰捌拾萬參仟壹佰伍拾柒兆貳仟陸佰零柒萬捌仟零貳億捌仟伍佰參拾捌萬柒仟陸佰零伍京捌仟玖佰伍拾伍萬捌仟陸佰參拾貳億柒仟陸佰陸拾捌萬柒仟捌佰壹拾柒兆壹仟伍佰肆拾萬肆仟伍佰捌拾玖億伍仟參佰伍拾壹萬肆仟參佰捌拾貳垓肆仟陸佰肆拾貳萬參仟肆佰參拾貳億壹仟參佰貳拾陸萬捌仟捌佰玖拾肆兆陸仟肆佰壹拾捌萬貳仟柒佰陸拾捌億肆仟陸佰柒拾伍萬肆仟陸佰柒拾京參仟伍佰參拾柒萬伍仟壹佰陸拾玖億捌仟陸佰零肆萬玖仟玖佰壹拾兆伍仟柒佰陸拾伍萬伍仟壹佰貳拾捌億貳仟零柒拾陸萬貳仟肆佰伍拾肆秭玖仟零玖萬零參佰捌拾玖億參仟貳佰捌拾玖萬肆仟肆佰零柒兆伍仟捌佰陸拾捌萬伍仟零捌拾肆億伍仟伍佰壹拾參萬參仟玖佰肆拾貳京參仟零肆拾伍萬捌仟參佰貳拾參億陸仟玖佰零參萬貳仟貳佰貳拾玖兆肆仟捌佰壹拾陸萬伍仟捌佰零捌億伍仟伍佰玖拾參萬參仟貳佰壹拾貳垓參仟參佰肆拾捌萬貳仟柒佰肆拾柒億玖仟柒佰捌拾貳萬陸仟貳佰零肆兆壹仟肆佰肆拾柒萬貳仟參佰壹拾陸億捌仟柒佰參拾捌萬壹仟柒佰柒拾壹京捌仟零玖拾壹萬玖仟貳佰玖拾玖億捌仟捌佰壹拾貳萬伍仟零肆拾兆肆仟零貳拾陸萬壹仟捌佰肆拾壹億貳仟肆佰捌拾伍萬捌仟參佰陸拾捌",f64::MIN); 174 | } 175 | 176 | #[test] 177 | fn to_lowercase_low() { 178 | test_group!(ChineseCase::Lower, ChineseCountMethod::Low); 179 | 180 | test!("一百二十七", i8::MAX); 181 | test!("負一百二十八", i8::MIN); 182 | test!("二百五十五", u8::MAX); 183 | test!("三萬二千七百六十七", i16::MAX); 184 | test!("負三萬二千七百六十八", i16::MIN); 185 | test!("六萬五千五百三十五", u16::MAX); 186 | test!("二秭一垓四京七兆四億八萬三千六百四十七", i32::MAX); 187 | test!("負二秭一垓四京七兆四億八萬三千六百四十八", i32::MIN); 188 | test!("四秭二垓九京四兆九億六萬七千二百九十五", u32::MAX); 189 | test!("九極九載九正九澗九溝九穰九秭九垓九京九兆九億九萬九千九百九十九", 9999999999999999i64); 190 | test!("負九極九載九正九澗九溝九穰九秭九垓九京九兆九億九萬九千九百九十九", -9999999999999999i64); 191 | test!("九極九載九正九澗九溝九穰九秭九垓九京九兆九億九萬九千九百九十九", 9999999999999999u64); 192 | test!("九極九載九正九澗九溝九穰九秭九垓九京九兆九億九萬九千九百九十九", 9999999999999999i128); 193 | test!( 194 | "負九極九載九正九澗九溝九穰九秭九垓九京九兆九億九萬九千九百九十九", 195 | -9999999999999999i128 196 | ); 197 | test!("九極九載九正九澗九溝九穰九秭九垓九京九兆九億九萬九千九百九十九", 9999999999999999u128); 198 | 199 | test!("一百二十三四角六分", 123.456f32); 200 | test!("負一百二十三四角六分", -123.456f32); 201 | test!("一百二十三四角六分", 123.456f64); 202 | test!("負一百二十三四角六分", -123.456f64); 203 | 204 | test_err!(NumberToChineseError::Overflow, i128::MAX); 205 | test_err!(NumberToChineseError::Underflow, i128::MIN); 206 | test_err!(NumberToChineseError::Overflow, u128::MAX); 207 | test_err!(NumberToChineseError::Overflow, f32::MAX); 208 | test_err!(NumberToChineseError::Underflow, f32::MIN); 209 | test_err!(NumberToChineseError::Overflow, f64::MAX); 210 | test_err!(NumberToChineseError::Underflow, f64::MIN); 211 | } 212 | 213 | #[test] 214 | fn to_lowercase_ten_thousand() { 215 | test_group!(ChineseCase::Lower, ChineseCountMethod::TenThousand); 216 | 217 | test!("一百二十七", i8::MAX); 218 | test!("負一百二十八", i8::MIN); 219 | test!("二百五十五", u8::MAX); 220 | test!("三萬二千七百六十七", i16::MAX); 221 | test!("負三萬二千七百六十八", i16::MIN); 222 | test!("六萬五千五百三十五", u16::MAX); 223 | test!("二十一億四千七百四十八萬三千六百四十七", i32::MAX); 224 | test!("負二十一億四千七百四十八萬三千六百四十八", i32::MIN); 225 | test!("四十二億九千四百九十六萬七千二百九十五", u32::MAX); 226 | test!("九百二十二京三千三百七十二兆零三百六十八億五千四百七十七萬五千八百零七", i64::MAX); 227 | test!("負九百二十二京三千三百七十二兆零三百六十八億五千四百七十七萬五千八百零八", i64::MIN); 228 | test!("一千八百四十四京六千七百四十四兆零七百三十七億零九百五十五萬一千六百一十五", u64::MAX); 229 | test!("一百七十澗一千四百一十一溝八千三百四十六穰零四百六十九秭二千三百一十七垓三千一百六十八京七千三百零三兆七千一百五十八億八千四百一十萬五千七百二十七",i128::MAX); 230 | test!("負一百七十澗一千四百一十一溝八千三百四十六穰零四百六十九秭二千三百一十七垓三千一百六十八京七千三百零三兆七千一百五十八億八千四百一十萬五千七百二十八",i128::MIN); 231 | test!("三百四十澗二千八百二十三溝六千六百九十二穰零九百三十八秭四千六百三十四垓六千三百三十七京四千六百零七兆四千三百一十七億六千八百二十一萬一千四百五十五",u128::MAX); 232 | 233 | test!("一百二十三四角六分", 123.456f32); 234 | test!("負一百二十三四角六分", -123.456f32); 235 | test!("一百二十三四角六分", 123.456f64); 236 | test!("負一百二十三四角六分", -123.456f64); 237 | 238 | test!("三百四十澗二千八百二十三溝四千六百六十三穰八千五百二十八秭八千五百九十八垓一千一百七十京四千一百八十三兆四千八百四十五億一千六百九十二萬五千四百四十",f32::MAX); 239 | test!("負三百四十澗二千八百二十三溝四千六百六十三穰八千五百二十八秭八千五百九十八垓一千一百七十京四千一百八十三兆四千八百四十五億一千六百九十二萬五千四百四十",f32::MIN); 240 | test!("九千九百九十九極九千九百九十九載九千九百九十九正九千九百八十九澗二千九百八十三溝八千五百五十二穰零四百六十四秭二千八百九十二垓九千六百五十三京四千一百六十兆六千零二十一億七千六百六十八萬四千零三十二",1e52f64 - 1e37); 241 | test!("負九千九百九十九極九千九百九十九載九千九百九十九正九千九百八十九澗二千九百八十三溝八千五百五十二穰零四百六十四秭二千八百九十二垓九千六百五十三京四千一百六十兆六千零二十一億七千六百六十八萬四千零三十二",-1e52f64 + 1e37); 242 | 243 | test_err!(NumberToChineseError::Overflow, f64::MAX); 244 | test_err!(NumberToChineseError::Underflow, f64::MIN); 245 | } 246 | 247 | #[test] 248 | fn to_lowercase_middle() { 249 | test_group!(ChineseCase::Lower, ChineseCountMethod::Middle); 250 | 251 | test!("一百二十七", i8::MAX); 252 | test!("負一百二十八", i8::MIN); 253 | test!("二百五十五", u8::MAX); 254 | test!("三萬二千七百六十七", i16::MAX); 255 | test!("負三萬二千七百六十八", i16::MIN); 256 | test!("六萬五千五百三十五", u16::MAX); 257 | test!("二十一億四千七百四十八萬三千六百四十七", i32::MAX); 258 | test!("負二十一億四千七百四十八萬三千六百四十八", i32::MIN); 259 | test!("四十二億九千四百九十六萬七千二百九十五", u32::MAX); 260 | test!("九百二十二兆三千三百七十二萬零三百六十八億五千四百七十七萬五千八百零七", i64::MAX); 261 | test!("負九百二十二兆三千三百七十二萬零三百六十八億五千四百七十七萬五千八百零八", i64::MIN); 262 | test!("一千八百四十四兆六千七百四十四萬零七百三十七億零九百五十五萬一千六百一十五", u64::MAX); 263 | test!("一百七十萬一千四百一十一垓八千三百四十六萬零四百六十九京二千三百一十七萬三千一百六十八兆七千三百零三萬七千一百五十八億八千四百一十萬五千七百二十七",i128::MAX); 264 | test!("負一百七十萬一千四百一十一垓八千三百四十六萬零四百六十九京二千三百一十七萬三千一百六十八兆七千三百零三萬七千一百五十八億八千四百一十萬五千七百二十八",i128::MIN); 265 | test!("三百四十萬二千八百二十三垓六千六百九十二萬零九百三十八京四千六百三十四萬六千三百三十七兆四千六百零七萬四千三百一十七億六千八百二十一萬一千四百五十五",u128::MAX); 266 | 267 | test!("一百二十三四角六分", 123.456f32); 268 | test!("負一百二十三四角六分", -123.456f32); 269 | test!("一百二十三四角六分", 123.456f64); 270 | test!("負一百二十三四角六分", -123.456f64); 271 | 272 | test!("三百四十萬二千八百二十三垓四千六百六十三萬八千五百二十八京八千五百九十八萬一千一百七十兆四千一百八十三萬四千八百四十五億一千六百九十二萬五千四百四十",f32::MAX); 273 | test!("負三百四十萬二千八百二十三垓四千六百六十三萬八千五百二十八京八千五百九十八萬一千一百七十兆四千一百八十三萬四千八百四十五億一千六百九十二萬五千四百四十",f32::MIN); 274 | test!("九千九百九十九萬九千九百九十九極九千九百九十九萬九千九百九十一載零一百二十九萬二千八百五十八正九千三百九十八萬一千四百六十二澗零一百零七萬一千一百六十七溝五千九百二十九萬四千二百六十七穰一千二百一十萬一千七百五十八秭七千一百七十八萬五千四百九十六垓八千四百四十八萬七千七百八十七京八千六百二十七萬七千七百六十二兆二千五百六十萬一千零一十億零五百萬零七百零四",1e96f64 - 1e81); 275 | test!("負九千九百九十九萬九千九百九十九極九千九百九十九萬九千九百九十一載零一百二十九萬二千八百五十八正九千三百九十八萬一千四百六十二澗零一百零七萬一千一百六十七溝五千九百二十九萬四千二百六十七穰一千二百一十萬一千七百五十八秭七千一百七十八萬五千四百九十六垓八千四百四十八萬七千七百八十七京八千六百二十七萬七千七百六十二兆二千五百六十萬一千零一十億零五百萬零七百零四",-1e96f64 + 1e81); 276 | 277 | test_err!(NumberToChineseError::Overflow, f64::MAX); 278 | test_err!(NumberToChineseError::Underflow, f64::MIN); 279 | } 280 | 281 | #[test] 282 | fn to_lowercase_high() { 283 | test_group!(ChineseCase::Lower, ChineseCountMethod::High); 284 | 285 | test!("一百二十七", i8::MAX); 286 | test!("負一百二十八", i8::MIN); 287 | test!("二百五十五", u8::MAX); 288 | test!("三萬二千七百六十七", i16::MAX); 289 | test!("負三萬二千七百六十八", i16::MIN); 290 | test!("六萬五千五百三十五", u16::MAX); 291 | test!("二十一億四千七百四十八萬三千六百四十七", i32::MAX); 292 | test!("負二十一億四千七百四十八萬三千六百四十八", i32::MIN); 293 | test!("四十二億九千四百九十六萬七千二百九十五", u32::MAX); 294 | test!("九百二十二兆三千三百七十二萬零三百六十八億五千四百七十七萬五千八百零七", i64::MAX); 295 | test!("負九百二十二兆三千三百七十二萬零三百六十八億五千四百七十七萬五千八百零八", i64::MIN); 296 | test!("一千八百四十四兆六千七百四十四萬零七百三十七億零九百五十五萬一千六百一十五", u64::MAX); 297 | test!("一百七十萬一千四百一十一京八千三百四十六萬零四百六十九億二千三百一十七萬三千一百六十八兆七千三百零三萬七千一百五十八億八千四百一十萬五千七百二十七",i128::MAX); 298 | test!("負一百七十萬一千四百一十一京八千三百四十六萬零四百六十九億二千三百一十七萬三千一百六十八兆七千三百零三萬七千一百五十八億八千四百一十萬五千七百二十八",i128::MIN); 299 | test!("三百四十萬二千八百二十三京六千六百九十二萬零九百三十八億四千六百三十四萬六千三百三十七兆四千六百零七萬四千三百一十七億六千八百二十一萬一千四百五十五",u128::MAX); 300 | 301 | test!("一百二十三四角六分", 123.456f32); 302 | test!("負一百二十三四角六分", -123.456f32); 303 | test!("一百二十三四角六分", 123.456f64); 304 | test!("負一百二十三四角六分", -123.456f64); 305 | } 306 | 307 | #[test] 308 | fn to_uppercase_naive() { 309 | test_group_naive!(ChineseCase::Upper); 310 | 311 | test!("壹貳柒", i8::MAX); 312 | test!("負壹貳捌", i8::MIN); 313 | test!("貳伍伍", u8::MAX); 314 | test!("參貳柒陸柒", i16::MAX); 315 | test!("負參貳柒陸捌", i16::MIN); 316 | test!("陸伍伍參伍", u16::MAX); 317 | test!("貳壹肆柒肆捌參陸肆柒", i32::MAX); 318 | test!("負貳壹肆柒肆捌參陸肆捌", i32::MIN); 319 | test!("肆貳玖肆玖陸柒貳玖伍", u32::MAX); 320 | test!("玖貳貳參參柒貳零參陸捌伍肆柒柒伍捌零柒", i64::MAX); 321 | test!("負玖貳貳參參柒貳零參陸捌伍肆柒柒伍捌零捌", i64::MIN); 322 | test!("壹捌肆肆陸柒肆肆零柒參柒零玖伍伍壹陸壹伍", u64::MAX); 323 | test!( 324 | "壹柒零壹肆壹壹捌參肆陸零肆陸玖貳參壹柒參壹陸捌柒參零參柒壹伍捌捌肆壹零伍柒貳柒", 325 | i128::MAX 326 | ); 327 | test!( 328 | "負壹柒零壹肆壹壹捌參肆陸零肆陸玖貳參壹柒參壹陸捌柒參零參柒壹伍捌捌肆壹零伍柒貳捌", 329 | i128::MIN 330 | ); 331 | test!( 332 | "參肆零貳捌貳參陸陸玖貳零玖參捌肆陸參肆陸參參柒肆陸零柒肆參壹柒陸捌貳壹壹肆伍伍", 333 | u128::MAX 334 | ); 335 | 336 | test!("壹貳參點肆陸", 123.456f32); 337 | test!("負壹貳參點肆陸", -123.456f32); 338 | test!("壹貳參點肆陸", 123.456f64); 339 | test!("負壹貳參點肆陸", -123.456f64); 340 | 341 | test!( 342 | "參肆零貳捌貳參肆陸陸參捌伍貳捌捌伍玖捌壹壹柒零肆壹捌參肆捌肆伍壹陸玖貳伍肆肆零", 343 | f32::MAX 344 | ); 345 | test!( 346 | "負參肆零貳捌貳參肆陸陸參捌伍貳捌捌伍玖捌壹壹柒零肆壹捌參肆捌肆伍壹陸玖貳伍肆肆零", 347 | f32::MIN 348 | ); 349 | test!("壹柒玖柒陸玖參壹參肆捌陸貳參壹伍柒零捌壹肆伍貳柒肆貳參柒參壹柒零肆參伍陸柒玖捌零柒零伍陸柒伍貳伍捌肆肆玖玖陸伍玖捌玖壹柒肆柒陸捌零參壹伍柒貳陸零柒捌零零貳捌伍參捌柒陸零伍捌玖伍伍捌陸參貳柒陸陸捌柒捌壹柒壹伍肆零肆伍捌玖伍參伍壹肆參捌貳肆陸肆貳參肆參貳壹參貳陸捌捌玖肆陸肆壹捌貳柒陸捌肆陸柒伍肆陸柒零參伍參柒伍壹陸玖捌陸零肆玖玖壹零伍柒陸伍伍壹貳捌貳零柒陸貳肆伍肆玖零零玖零參捌玖參貳捌玖肆肆零柒伍捌陸捌伍零捌肆伍伍壹參參玖肆貳參零肆伍捌參貳參陸玖零參貳貳貳玖肆捌壹陸伍捌零捌伍伍玖參參貳壹貳參參肆捌貳柒肆柒玖柒捌貳陸貳零肆壹肆肆柒貳參壹陸捌柒參捌壹柒柒壹捌零玖壹玖貳玖玖捌捌壹貳伍零肆零肆零貳陸壹捌肆壹貳肆捌伍捌參陸捌",f64::MAX); 350 | test!("負壹柒玖柒陸玖參壹參肆捌陸貳參壹伍柒零捌壹肆伍貳柒肆貳參柒參壹柒零肆參伍陸柒玖捌零柒零伍陸柒伍貳伍捌肆肆玖玖陸伍玖捌玖壹柒肆柒陸捌零參壹伍柒貳陸零柒捌零零貳捌伍參捌柒陸零伍捌玖伍伍捌陸參貳柒陸陸捌柒捌壹柒壹伍肆零肆伍捌玖伍參伍壹肆參捌貳肆陸肆貳參肆參貳壹參貳陸捌捌玖肆陸肆壹捌貳柒陸捌肆陸柒伍肆陸柒零參伍參柒伍壹陸玖捌陸零肆玖玖壹零伍柒陸伍伍壹貳捌貳零柒陸貳肆伍肆玖零零玖零參捌玖參貳捌玖肆肆零柒伍捌陸捌伍零捌肆伍伍壹參參玖肆貳參零肆伍捌參貳參陸玖零參貳貳貳玖肆捌壹陸伍捌零捌伍伍玖參參貳壹貳參參肆捌貳柒肆柒玖柒捌貳陸貳零肆壹肆肆柒貳參壹陸捌柒參捌壹柒柒壹捌零玖壹玖貳玖玖捌捌壹貳伍零肆零肆零貳陸壹捌肆壹貳肆捌伍捌參陸捌",f64::MIN); 351 | } 352 | -------------------------------------------------------------------------------- /tests/self.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "chinese-to-number", feature = "number-to-chinese"))] 2 | 3 | use core::{ 4 | fmt::Display, 5 | ops::{AddAssign, RangeInclusive, SubAssign}, 6 | }; 7 | 8 | use chinese_number::{ 9 | ChineseCase, ChineseCountMethod, ChineseToNumber, ChineseVariant, NumberToChinese, 10 | }; 11 | use num_traits::{CheckedAdd, CheckedMul}; 12 | 13 | fn ranger< 14 | T: PartialOrd + Copy + AddAssign + SubAssign + CheckedAdd + CheckedMul + TryFrom + Display, 15 | >( 16 | range: RangeInclusive, 17 | f: impl Fn(T), 18 | ) { 19 | let e = *range.end(); 20 | 21 | let mut s = *range.start(); 22 | 23 | let one = match T::try_from(1) { 24 | Ok(n) => n, 25 | Err(_) => unimplemented!(), 26 | }; 27 | let mut c = one; 28 | let mut cc = one; 29 | 30 | while s <= e { 31 | f(s); 32 | 33 | s = match s.checked_add(&cc) { 34 | Some(n) => n, 35 | None => break, 36 | }; 37 | 38 | c += one; 39 | 40 | cc = match cc.checked_mul(&c) { 41 | Some(n) => n, 42 | None => break, 43 | }; 44 | 45 | cc -= one; 46 | } 47 | } 48 | 49 | #[test] 50 | fn test_u8() { 51 | for method in ChineseCountMethod::variants() { 52 | ranger(u8::MIN..=u8::MAX, |i| { 53 | assert_eq!( 54 | i, 55 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 56 | .unwrap() 57 | .to_number(method) 58 | .unwrap() 59 | ); 60 | }); 61 | } 62 | 63 | ranger(u8::MIN..=u8::MAX, |i| { 64 | assert_eq!( 65 | i, 66 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 67 | .to_number_naive() 68 | .unwrap() 69 | ); 70 | }); 71 | } 72 | 73 | #[test] 74 | fn test_i8() { 75 | for method in ChineseCountMethod::variants() { 76 | ranger(i8::MIN..=i8::MAX, |i| { 77 | assert_eq!( 78 | i, 79 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 80 | .unwrap() 81 | .to_number(method) 82 | .unwrap() 83 | ); 84 | }); 85 | } 86 | 87 | ranger(i8::MIN..=i8::MAX, |i| { 88 | assert_eq!( 89 | i, 90 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 91 | .to_number_naive() 92 | .unwrap() 93 | ); 94 | }); 95 | } 96 | 97 | #[test] 98 | fn test_u16() { 99 | for method in ChineseCountMethod::variants() { 100 | ranger(u16::MIN..=u16::MAX, |i| { 101 | assert_eq!( 102 | i, 103 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 104 | .unwrap() 105 | .to_number(method) 106 | .unwrap() 107 | ); 108 | }); 109 | } 110 | 111 | ranger(u16::MIN..=u16::MAX, |i| { 112 | assert_eq!( 113 | i, 114 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 115 | .to_number_naive() 116 | .unwrap() 117 | ); 118 | }); 119 | } 120 | 121 | #[test] 122 | fn test_i16() { 123 | for method in ChineseCountMethod::variants() { 124 | ranger(i16::MIN..=i16::MAX, |i| { 125 | assert_eq!( 126 | i, 127 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 128 | .unwrap() 129 | .to_number(method) 130 | .unwrap() 131 | ); 132 | }); 133 | } 134 | 135 | ranger(i16::MIN..=i16::MAX, |i| { 136 | assert_eq!( 137 | i, 138 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 139 | .to_number_naive() 140 | .unwrap() 141 | ); 142 | }); 143 | } 144 | 145 | #[test] 146 | fn test_u32() { 147 | for method in ChineseCountMethod::variants() { 148 | ranger(u32::MIN..=u32::MAX, |i| { 149 | assert_eq!( 150 | i, 151 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 152 | .unwrap() 153 | .to_number(method) 154 | .unwrap() 155 | ); 156 | }); 157 | } 158 | 159 | ranger(u32::MIN..=u32::MAX, |i| { 160 | assert_eq!( 161 | i, 162 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 163 | .to_number_naive() 164 | .unwrap() 165 | ); 166 | }); 167 | } 168 | 169 | #[test] 170 | fn test_i32() { 171 | for method in ChineseCountMethod::variants() { 172 | ranger(i32::MIN..=i32::MAX, |i| { 173 | assert_eq!( 174 | i, 175 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 176 | .unwrap() 177 | .to_number(method) 178 | .unwrap() 179 | ); 180 | }); 181 | } 182 | 183 | ranger(i32::MIN..=i32::MAX, |i| { 184 | assert_eq!( 185 | i, 186 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 187 | .to_number_naive() 188 | .unwrap() 189 | ); 190 | }); 191 | } 192 | 193 | #[test] 194 | fn test_u64() { 195 | ranger(u64::MIN..=9999_9999_9999_9999, |i| { 196 | assert_eq!( 197 | i, 198 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::Low) 199 | .unwrap() 200 | .to_number(ChineseCountMethod::Low) 201 | .unwrap() 202 | ); 203 | }); 204 | 205 | for method in ChineseCountMethod::variants().iter().copied().skip(1) { 206 | ranger(u64::MIN..=u64::MAX, |i| { 207 | assert_eq!( 208 | i, 209 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 210 | .unwrap() 211 | .to_number(method) 212 | .unwrap() 213 | ); 214 | }); 215 | } 216 | 217 | ranger(u64::MIN..=u64::MAX, |i| { 218 | assert_eq!( 219 | i, 220 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 221 | .to_number_naive() 222 | .unwrap() 223 | ); 224 | }); 225 | } 226 | 227 | #[test] 228 | fn test_i64() { 229 | ranger(-9999_9999_9999_9999i64..=9999_9999_9999_9999, |i| { 230 | assert_eq!( 231 | i, 232 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::Low) 233 | .unwrap() 234 | .to_number(ChineseCountMethod::Low) 235 | .unwrap() 236 | ); 237 | }); 238 | 239 | for method in ChineseCountMethod::variants().iter().copied().skip(1) { 240 | ranger(i64::MIN..=i64::MAX, |i| { 241 | assert_eq!( 242 | i, 243 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 244 | .unwrap() 245 | .to_number(method) 246 | .unwrap() 247 | ); 248 | }); 249 | } 250 | 251 | ranger(i64::MIN..=i64::MAX, |i| { 252 | assert_eq!( 253 | i, 254 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 255 | .to_number_naive() 256 | .unwrap() 257 | ); 258 | }); 259 | } 260 | 261 | #[test] 262 | fn test_u128() { 263 | ranger(u128::MIN..=9999_9999_9999_9999, |i| { 264 | assert_eq!( 265 | i, 266 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::Low) 267 | .unwrap() 268 | .to_number(ChineseCountMethod::Low) 269 | .unwrap() 270 | ); 271 | }); 272 | 273 | for method in ChineseCountMethod::variants().iter().copied().skip(1) { 274 | ranger(u128::MIN..=u128::MAX, |i| { 275 | assert_eq!( 276 | i, 277 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 278 | .unwrap() 279 | .to_number(method) 280 | .unwrap() 281 | ); 282 | }); 283 | } 284 | 285 | ranger(u128::MIN..=u128::MAX, |i| { 286 | assert_eq!( 287 | i, 288 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 289 | .to_number_naive() 290 | .unwrap() 291 | ); 292 | }); 293 | } 294 | 295 | #[test] 296 | fn test_i128() { 297 | ranger(-9999_9999_9999_9999i128..=9999_9999_9999_9999, |i| { 298 | assert_eq!( 299 | i, 300 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, ChineseCountMethod::Low) 301 | .unwrap() 302 | .to_number(ChineseCountMethod::Low) 303 | .unwrap() 304 | ); 305 | }); 306 | 307 | for method in ChineseCountMethod::variants().iter().copied().skip(1) { 308 | ranger(i128::MIN..=i128::MAX, |i| { 309 | assert_eq!( 310 | i, 311 | i.to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, method) 312 | .unwrap() 313 | .to_number(method) 314 | .unwrap() 315 | ); 316 | }); 317 | } 318 | 319 | ranger(i128::MIN..=i128::MAX, |i| { 320 | assert_eq!( 321 | i, 322 | i.to_chinese_naive(ChineseVariant::Traditional, ChineseCase::Lower) 323 | .to_number_naive() 324 | .unwrap() 325 | ); 326 | }); 327 | } 328 | --------------------------------------------------------------------------------