### Set up development environment Source: https://github.com/zcold/pycnnum/blob/master/README.md Create a virtual environment and install development dependencies for contributing. Example for Ubuntu 22.4. ```bash # example for working under Ubuntu 22.4 # git and python3.8-venv are required git clone https://github.com/zcold/pycnnum.git pycnnum_dev cd pycnnum_dev python3.8 -m venv .venv source .venv/bin/activate python -m pip install .[dev] -U ``` -------------------------------- ### Install pycnnum from source Source: https://github.com/zcold/pycnnum/blob/master/README.md Clone the repository and install the package from source. Requires git. ```bash # git is required git clone https://github.com/zcold/pycnnum.git cd pycnnum python -m pip install . ``` -------------------------------- ### Install pycnnum from PyPI Source: https://github.com/zcold/pycnnum/blob/master/README.md Install the pycnnum package from PyPI using pip. ```bash pip install pycnnum ``` -------------------------------- ### MathSymbols example: positive, negative, point Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Example from the MathSymbols class docstring demonstrating creation of positive, negative, and point CNMath instances, combining them into a MathSymbols object, and iterating over its elements. ```python >>> positive = CNMath(*"正正正正", symbol="+", expression=lambda x: +x) >>> negative = CNMath(*"负負负負", symbol="-", expression=lambda x: -x) >>> point = CNMath(*"点點点點", symbol=".", expression=lambda integer, decimal: float(str(integer) + "." + str(decimal))) >>> math = MathSymbols(positive, negative, point) >>> math.positive + >>> list(math) [+, -, .] >>> for i in math: ... print(i) + - . ``` -------------------------------- ### NumberingSystem example: MID type Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Example from the NumberingSystem class docstring showing how to instantiate a NumberingSystem with NumberingType.MID and access its numbering_type, digits, units, and math symbols. ```python >>> system = NumberingSystem(NumberingType.MID) >>> system.numbering_type >>> system.digits[0] 0 >>> system.units[0] 10^1 >>> system.units[7].simplified '垓' >>> system.math.positive + ``` -------------------------------- ### int2symbols example Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Example usage of the int2symbols method, converting integers to a list of symbols. The output shows the symbol representation for each input, including handling of leading zeros and string inputs. ```python >>> s = NumberingSystem(NumberingType.MID) >>> s.int2symbols(18) [1, 10^1, 8] >>> s.int2symbols(20000180) [2, 10^3, 10^4, 0, 1, 10^2, 8, 10^1] >>> s.int2symbols(26) [2, 10^1, 6] >>> s.int2symbols(320) [3, 10^2, 2, 10^1] >>> s.int2symbols(220) [2, 10^2, 2, 10^1] >>> s.int2symbols("220") [2, 10^2, 2, 10^1] ``` -------------------------------- ### Example of _refine_integer_symbols Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Shows the output of _refine_integer_symbols for various Chinese number strings, demonstrating how it converts symbols to refined integer symbol lists. ```python >>> s = NumberingSystem(NumberingType.MID) >>> s._refine_integer_symbols(s.cn2symbols("十八")[0]) [1, 10^1, 8, 10^0] >>> s._refine_integer_symbols(s.cn2symbols("两千万一百八十")[0]) [2, 10^7, 1, 10^2, 8, 10^1] >>> s._refine_integer_symbols(s.cn2symbols("两千万零一百八十")[0]) [2, 10^7, 1, 10^2, 8, 10^1] >>> s._refine_integer_symbols(s.cn2symbols("两亿六")[0]) [2, 10^8, 6, 10^7] ``` -------------------------------- ### CNMath example: positive symbol Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Example from the CNMath class docstring showing how to create a CNMath instance with a positive symbol and expression, and access its symbol attribute. ```python >>> positive = CNMath(*"正正正正", symbol="+", expression=lambda x: +x) >>> positive.symbol '+' ``` -------------------------------- ### Example of get_int_value Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Shows the output of get_int_value for various Chinese number strings, demonstrating how it computes the integer value from symbols. ```python >>> s = NumberingSystem(NumberingType.MID) >>> s.get_int_value(s.cn2symbols("十八")[0]) 18 >>> s.get_int_value(s.cn2symbols("两千万一百八十")[0]) 20000180 >>> s.get_int_value(s.cn2symbols("两亿六")[0]) 260000000 ``` -------------------------------- ### num2cn() conversion examples Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Example usage of num2cn() converting integers, floats, and strings to Chinese numerals. Shows default behavior and effects of options like alt_2, numbering_type, upper, and traditional. ```python >>> num2cn(16) '十六' >>> num2cn(1) '一' >>> num2cn(116) '一百一十六' >>> num2cn(2401, alt_2=True) '两千四百零一' >>> num2cn(101) '一百零一' >>> num2cn(float("3.4"), numbering_type=NumberingType.HIGH, alt_2=True, upper=False, traditional=False) '三点四' >>> num2cn("3.4", numbering_type=NumberingType.HIGH, alt_2=True, upper=False, traditional=False) '三点四' >>> num2cn(23232.005184132423423423300, numbering_type=NumberingType.HIGH, alt_2=True, upper=False, traditional=True) '兩萬叁仟兩佰叁拾贰點零零伍壹捌肆壹叁贰肆贰肆' >>> num2cn("23232.005184132423423423300", numbering_type=NumberingType.HIGH, alt_2=True, upper=False, traditional=True) '兩萬叁仟兩佰叁拾贰點零零伍壹捌肆壹叁贰肆贰叁肆贰叁肆贰叁叁零零' >>> num2cn('023232.005184132423423423300', numbering_type=NumberingType.HIGH, alt_2=False, upper=False, traditional=False) '二万三千二百三十二点零零五一八四一三二四二三四二三四二三三零零' >>> num2cn(111180000) '一亿一千一百一十八万' >>> num2cn(1821010) '一百八十二万一千零一十' >>> num2cn(182.1) '一百八十二点一' >>> num2cn('3.4') '三点四' >>> num2cn(16) '十六' >>> num2cn(10600) '一万零六百' >>> num2cn(110) '一百一' >>> num2cn(1600) '一千六' ``` -------------------------------- ### CNChar usage example Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Shows how to create a CNChar instance and access its simplified, traditional, and upper-case forms. The output demonstrates that upper_simplified defaults to the simplified form and upper_traditional defaults to the traditional form. ```python >>> negative = CNChar(simplified="负", traditional="負") >>> negative.simplified '负' >>> negative.traditional '負' >>> negative.upper_simplified '负' >>> negative.upper_traditional '負' ``` -------------------------------- ### pycnnum package __init__.py source Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum.html Source code of the pycnnum package's __init__.py file. It contains the module docstring with the example and imports the version and the conversion functions. ```python 1"""Chinese number <=> int/float conversion for Python3.8+ 2 3Example: 4 5```python 6 7>>> from pycnnum import cn2num, num2cn 8>>> from pycnnum import cn2num, num2cn 9>>> cn2num("一百二十三") 10123 11>>> num2cn(123) 12'一百二十三' 13>>> cn2num("一兆零四十五", numbering_type="mid") 141000000000045 15>>> num2cn(2400, alt_2=True) 16'两千四' 17>>> num2cn(3.4) 18'三点四' 19 20``` 21 22- `.pycnnum.cn2num` 23- `.pycnnum.num2cn` 24""" 25 26from .__version__ import __version__ 27from .pycnnum import cn2num, num2cn ``` -------------------------------- ### num2cn Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Documentation for the num2cn function, including its parameters and usage examples. ```APIDOC ## num2cn(num, numbering_type=NumberingType.MID, upper=False, traditional=False, alt_0=False, alt_2=False) ### Description Converts a number (int, float, or string) into its Chinese numeral representation. Supports various numbering types, uppercase/traditional forms, and alternative characters for zero and two. ### Parameters - **num** (Tuple[int, float, str]) - Required - The number to convert. Accepts int, float, or string. - **numbering_type** (Union[str, NumberingType], optional) - Numbering type. Defaults to `NumberingType.MID`. - **upper** (bool, optional) - Use capitalized numbers. Defaults to `False`. - **traditional** (bool, optional) - Use traditional Chinese characters. Defaults to `False`. - **alt_0** (bool, optional) - Use alternative form of zero. Defaults to `False`. - **alt_2** (bool, optional) - Use alternative form of two. Defaults to `False`. ### Returns - **str** - The Chinese numeral representation of the input number. ### Examples ```python >>> num2cn(16) '十六' >>> num2cn(1) '一' >>> num2cn(116) '一百一十六' >>> num2cn(2401, alt_2=True) '两千四百零一' >>> num2cn(101) '一百零一' >>> num2cn(float("3.4"), numbering_type=NumberingType.HIGH, alt_2=True, upper=False, traditional=False) '三点四' >>> num2cn("3.4", numbering_type=NumberingType.HIGH, alt_2=True, upper=False, traditional=False) '三点四' >>> num2cn(23232.005184132423423423300, numbering_type=NumberingType.HIGH, alt_2=True, upper=False, traditional=True) '兩萬叁仟兩佰叁拾贰點零零伍壹捌肆壹叁贰肆贰肆' >>> num2cn("23232.005184132423423423300", numbering_type=NumberingType.HIGH, alt_2=True, upper=False, traditional=True) '兩萬叁仟兩佰叁拾贰點零零伍壹捌肆壹叁贰肆贰叁肆贰叁肆贰叁叁零零' >>> num2cn('023232.005184132423423423300', numbering_type=NumberingType.HIGH, alt_2=False, upper=False, traditional=False) '二万三千二百三十二点零零五一八四一三二四二三四二三四二三三零零' >>> num2cn(111180000) '一亿一千一百一十八万' >>> num2cn(1821010) '一百八十二万一千零一十' >>> num2cn(182.1) '一百八十二点一' >>> num2cn('3.4') '三点四' >>> num2cn(16) '十六' >>> num2cn(10600) '一万零六百' >>> num2cn(110) '一百一' >>> num2cn(1600) '一千六' ``` ``` -------------------------------- ### Convert Chinese numbers to symbols with cn2symbols Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Demonstrates the cn2symbols method, which converts Chinese number strings into integer and decimal symbol lists. Includes examples with positive/negative signs, decimal points, and error cases for invalid math symbols or multiple points. ```python >>> system = NumberingSystem(NumberingType.MID) >>> system.cn2symbols("一百八") ([1, 10^2, 8], []) >>> system.cn2symbols("一百八十") ([1, 10^2, 8, 10^1], []) >>> system.cn2symbols("一百八点五六七") ([1, 10^2, 8], [5, 6, 7]) >>> system.cn2symbols("两千万一百八十") ([2, 10^7, 1, 10^2, 8, 10^1], []) >>> system.cn2symbols("正两千万一百八十") ([+, 2, 10^7, 1, 10^2, 8, 10^1], []) >>> system.cn2symbols("负两千万一百八十") ([-, 2, 10^7, 1, 10^2, 8, 10^1], []) >>> system.cn2symbols("点负两千万一百八十") Traceback (most recent call last): ... ValueError: First symbol in decimal part should not be a math symbol, - is provided. >>> system.cn2symbols("两千万点一百点八十") Traceback (most recent call last): ... ValueError: Multiple points in the number 两千万点一百点八十. >>> system.cn2symbols("两千万点一百點八十") Traceback (most recent call last): ... ValueError: Multiple points in the number 两千万点一百點八十. ``` -------------------------------- ### Search initialization and event handling Source: https://github.com/zcold/pycnnum/blob/master/doc/index.html This JavaScript code sets up the search functionality for the documentation page. It initializes the search index, handles search input events, and manages the display of search results. It also handles keyboard navigation for the results. ```javascript function escapeHTML(html) { return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML; } const originalContent = document.querySelector("main.pdoc"); let currentContent = originalContent; function setContent(innerHTML) { let elem; if (innerHTML) { elem = document.createElement("main"); elem.classList.add("pdoc"); elem.innerHTML = innerHTML; } else { elem = originalContent; } if (currentContent !== elem) { currentContent.replaceWith(elem); currentContent = elem; } } function getSearchTerm() { return (new URL(window.location)).searchParams.get("search"); } const searchBox = document.querySelector(".pdoc input[type=search]"); searchBox.addEventListener("input", function () { let url = new URL(window.location); if (searchBox.value.trim()) { url.hash = ""; url.searchParams.set("search", searchBox.value); } else { url.searchParams.delete("search"); } history.replaceState("", "", url.toString()); onInput(); }); window.addEventListener("popstate", onInput); let search, searchErr; async function initialize() { try { search = await new Promise((resolve, reject) => { const script = document.createElement("script"); script.type = "text/javascript"; script.async = true; script.onload = () => resolve(window.pdocSearch); script.onerror = (e) => reject(e); script.src = "search.js"; document.getElementsByTagName("head")[0].appendChild(script); }); } catch (e) { console.error("Cannot fetch pdoc search index"); searchErr = "Cannot fetch search index."; } onInput(); document.querySelector("nav.pdoc").addEventListener("click", e => { if (e.target.hash) { searchBox.value = ""; searchBox.dispatchEvent(new Event("input")); } }); } function onInput() { setContent((() => { const term = getSearchTerm(); if (!term) { return null } if (searchErr) { return `

Error: ${searchErr}

` } if (!search) { return "

Searching...

" } window.scrollTo({top: 0, left: 0, behavior: 'auto'}); const results = search(term); let html; if (results.length === 0) { html = `No search results for '${escapeHTML(term)}'.` } else { html = `

${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.

`; } for (let result of results.slice(0, 10)) { let doc = result.doc; let url = `${doc.modulename.replaceAll(".", "/")}.html`; if (doc.qualname) { url += `#${doc.qualname}`; } let heading; switch (result.doc.kind) { case "function": if (doc.fullname.endsWith(".__init__")) { heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; } else { heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; } break; case "class": heading = `class ${doc.fullname}`; if (doc.bases) heading += `(${doc.bases})`; heading += `:`; break; case "variable": heading = `${doc.fullname}`; if (doc.annotation) heading += `${doc.annotation}`; if (doc.default_value) heading += ` = ${doc.default_value}`; break; default: heading = `${doc.fullname}`; break; } html += `
${heading}
${doc.doc}
`; } return html; })()); } if (getSearchTerm()) { initialize(); searchBox.value = getSearchTerm(); onInput(); } else { searchBox.addEventListener("focus", initialize, {once: true}); } searchBox.addEventListener("keydown", e => { if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) { let focused = currentContent.querySelector(".search-result.focused"); if (!focused) { currentContent.querySelector(".search-result").classList.add("focused"); } else if ( e.key === "ArrowDown" && focused.nextElementSibling && focused.nextElementSibling.classList.contains("search-result") ) { focused.classList.remove("focused"); focused.nextElementSibling.classList.add("focused"); focused.nextElementSibling.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" }); } else if ( e.key === "ArrowUp" && focused.previousElementSibling && focused.previousElementSibling.classList.contains("search-result") ) { focused.classList.remove("focused"); focused.previousElementSibling.classList.add("focused"); focused.previousElementSibling.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" }); } else if ( e.key === "Enter" ) { focused.querySelector("a").click(); } } }); ``` -------------------------------- ### Create MathSymbols with CNMath objects Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Creates CNMath objects for positive, negative, and point, combines them into a MathSymbols instance, and demonstrates iteration and printing. ```python >>> positive = CNMath(*"正正正正", symbol="+", expression=lambda x: +x) >>> negative = CNMath(*"负負负負", symbol="-", expression=lambda x: -x) >>> point = CNMath(*"点點点點", symbol=".", expression=lambda integer, decimal: float(str(integer) + "." + str(decimal))) >>> math = MathSymbols(positive, negative, point) >>> math.positive + >>> list(math) [+, -, .] >>> for i in math: ... print(i) + - . ``` -------------------------------- ### Create CNUnit with power 4 Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Creates a CNUnit with power 4 and displays its string representation as 10^4. ```python >>> wan = CNUnit(*"万萬萬萬", power=4) >>> wan 10^4 ``` -------------------------------- ### cn2num example Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Example usage of the cn2num function, converting Chinese number strings to integer or float values. The output shows the numeric result for each input, including handling of negative, positive, and decimal numbers. ```python >>> cn2num("负零点五") -0.5 >>> cn2num("一百八") 180 >>> cn2num("一百八十") 180 >>> cn2num("一百八点五六七") 180.567 >>> cn2num("两千万一百八十") 20000180 >>> cn2num("正两千万一百八十") 20000180 ``` -------------------------------- ### Create NumberingSystem and access properties Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Shows how to create a NumberingSystem with the MID numbering type and access its properties: numbering_type, digits, units, and math symbols. The output demonstrates the expected values for the default MID system. ```python >>> system = NumberingSystem(NumberingType.MID) >>> system.numbering_type >>> system.digits[0] 0 >>> system.units[0] 10^1 >>> system.units[7].simplified '垓' >>> system.math.positive + ``` -------------------------------- ### CNChar.all_forms property Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Property that concatenates all string attributes of the character into a single string. Useful for getting all forms at once. ```python @property def all_forms(self) -> str: """All forms of the character""" return "".join(v for v in self.__dict__.values() if isinstance(v, str)) ``` -------------------------------- ### Search initialization and result rendering Source: https://github.com/zcold/pycnnum/blob/master/doc/test/test_pycnnum.html Initializes the search index from ../search.js, handles search input, renders results with proper headings based on doc kind, and supports keyboard navigation (ArrowDown, ArrowUp, Enter) for result selection. ```javascript function escapeHTML(html) { return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML; } const originalContent = document.querySelector("main.pdoc"); let currentContent = originalContent; function setContent(innerHTML) { let elem; if (innerHTML) { elem = document.createElement("main"); elem.classList.add("pdoc"); elem.innerHTML = innerHTML; } else { elem = originalContent; } if (currentContent !== elem) { currentContent.replaceWith(elem); currentContent = elem; } } function getSearchTerm() { return (new URL(window.location)).searchParams.get("search"); } const searchBox = document.querySelector(".pdoc input[type=search]"); searchBox.addEventListener("input", function () { let url = new URL(window.location); if (searchBox.value.trim()) { url.hash = ""; url.searchParams.set("search", searchBox.value); } else { url.searchParams.delete("search"); } history.replaceState("", "", url.toString()); onInput(); }); window.addEventListener("popstate", onInput); let search, searchErr; async function initialize() { try { search = await new Promise((resolve, reject) => { const script = document.createElement("script"); script.type = "text/javascript"; script.async = true; script.onload = () => resolve(window.pdocSearch); script.onerror = (e) => reject(e); script.src = "../search.js"; document.getElementsByTagName("head")[0].appendChild(script); }); } catch (e) { console.error("Cannot fetch pdoc search index"); searchErr = "Cannot fetch search index."; } onInput(); document.querySelector("nav.pdoc").addEventListener("click", e => { if (e.target.hash) { searchBox.value = ""; searchBox.dispatchEvent(new Event("input")); } }); } function onInput() { setContent((() => { const term = getSearchTerm(); if (!term) { return null } if (searchErr) { return `

Error: ${searchErr}

` } if (!search) { return "

Searching...

" } window.scrollTo({top: 0, left: 0, behavior: 'auto'}); const results = search(term); let html; if (results.length === 0) { html = `No search results for '${escapeHTML(term)}'.` } else { html = `

${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.

`; } for (let result of results.slice(0, 10)) { let doc = result.doc; let url = `../${doc.modulename.replaceAll(".", "/")}.html`; if (doc.qualname) { url += `#${doc.qualname}`; } let heading; switch (doc.kind) { case "function": if (doc.fullname.endsWith(".__init__")) { heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; } else { heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; } break; case "class": heading = `class ${doc.fullname}`; if (doc.bases) heading += `(${doc.bases})`; heading += `:`; break; case "variable": heading = `${doc.fullname}`; if (doc.annotation) heading += `${doc.annotation}`; if (doc.default_value) heading += ` = ${doc.default_value}`; break; default: heading = `${doc.fullname}`; break; } html += `
${heading}
${doc.doc}
`; } return html; })()); } if (getSearchTerm()) { initialize(); searchBox.value = getSearchTerm(); onInput(); } else { searchBox.addEventListener("focus", initialize, {once: true}); } searchBox.addEventListener("keydown", e => { if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) { let focused = currentContent.querySelector(".search-result.focused"); if (!focused) { currentContent.querySelector(".search-result").classList.add("focused"); } else if ( e.key === "ArrowDown" && focused.nextElementSibling && focused.nextElementSibling.classList.contains("search-result") ) { focused.classList.remove("focused"); focused.nextElementSibling.classList.add("focused"); focused.nextElementSibling.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" }); } else if ( e.key === "ArrowUp" && focused.previousElementSibling && focused.previousElementSibling.classList.contains("search-result") ) { focused.classList.remove("focused"); focused.previousElementSibling.classList.add("focused"); focused.previousElementSibling.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" }); } else if ( e.key === "Enter" ) { focused.querySelector("a").click(); } } }); ``` -------------------------------- ### Create CNUnit with create() and handle ValueError Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Shows creating CNUnit objects with different numbering types and powers, including a ValueError when the power is invalid for the given numbering type. ```python >>> CNUnit.create(power=8, numbering_type=NumberingType.LOW).simplified '亿' >>> CNUnit.create(power=12, numbering_type=NumberingType.LOW).simplified '秭' >>> CNUnit.create(power=12, numbering_type=NumberingType.HIGH).simplified Traceback (most recent call last): ... ValueError: power = 12 is invalid for numbering_type = ``` -------------------------------- ### Convert Chinese string to symbols with cn2symbols Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Converts a Chinese number string into integer and decimal symbol lists. Raises ValueError for multiple decimal points or a math symbol at the start of the decimal part. ```python 395 def cn2symbols(self, cn_str: str) -> Tuple[List[SymbolType], List[SymbolType]]: 396 """Chinese string to symbols 397 398 Example: 399 ```python 400 401 >>> system = NumberingSystem(NumberingType.MID) 402 >>> system.cn2symbols("一百八") 403 ([1, 10^2, 8], []) 404 >>> system.cn2symbols("一百八十") 405 ([1, 10^2, 8, 10^1], []) 406 >>> system.cn2symbols("一百八点五六七") 407 ([1, 10^2, 8], [5, 6, 7]) 408 >>> system.cn2symbols("两千万一百八十") 409 ([2, 10^7, 1, 10^2, 8, 10^1], []) 410 >>> system.cn2symbols("正两千万一百八十") 411 ([+, 2, 10^7, 1, 10^2, 8, 10^1], []) 412 >>> system.cn2symbols("负两千万一百八十") 413 ([-, 2, 10^7, 1, 10^2, 8, 10^1], []) 414 >>> system.cn2symbols("点负两千万一百八十") 415 Traceback (most recent call last): 416 ... 417 ValueError: First symbol in decimal part should not be a math symbol, - is provided. 418 >>> system.cn2symbols("两千万点一百点八十") 419 Traceback (most recent call last): 420 ... 421 ValueError: Multiple points in the number 两千万点一百点八十. 422 >>> system.cn2symbols("两千万点一百點八十") 423 Traceback (most recent call last): 424 ... 425 ValueError: Multiple points in the number 两千万点一百點八十. 426 427 ``` 428 Args: cn_str (str): Chinese number 429 Returns: Tuple[List[SymbolType], List[SymbolType]]: Integer symbols, decimal symbols 430 """ 431 if cn_str == "": 432 return [], [] 433 434 int_part, dec_part = cn_str, "" 435 int_dec = re.split(r"\.|点|點", cn_str) 436 if len(int_dec) > 2: 437 raise ValueError(f"Multiple points in the number {cn_str}.") 438 int_part, dec_part = int_dec if len(int_dec) == 2 else (int_dec[0], "") 439 440 integer_value = [copy.deepcopy(self[c]) for c in int_part] 441 442 for i, v in enumerate(integer_value): 443 if not isinstance(v, CNUnit): 444 continue 445 if i + 1 < len(integer_value) and isinstance(integer_value[i + 1], CNUnit): 446 v.power += integer_value[i + 1].power # type: ignore[union-attr] 447 integer_value[i + 1] = None # type: ignore[union-attr] 448 449 integer_value = [v for v in integer_value if v is not None] 450 451 for i, v in enumerate(integer_value): 452 if not isinstance(v, CNUnit): 453 continue 454 for u in integer_value[i + 1 :]: 455 if isinstance(u, CNUnit) and u.power > v.power: 456 v.power += u.power 457 break 458 459 decimal_value = [copy.deepcopy(self[c]) for c in dec_part] 460 461 # if first symbol is a math symbol, e.g. '正两千万一百八十' 462 if int_part and (first_symbol := [c for c in self.math if int_part[0] in c.all_forms]): 463 integer_value[0] = first_symbol[0] 464 465 # if first symbol is a math symbol, e.g. '点负两千万一百八十' 466 if decimal_value and (decimal_value[0] in self.math): 467 raise ValueError( 468 f"First symbol in decimal part should not be a math symbol, {decimal_value[0]} is provided." 469 ) 470 471 return integer_value, decimal_value ``` -------------------------------- ### NumberingSystem.__init__ Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Constructor for NumberingSystem. Initializes the numbering type and builds the units list using UNITS and the numbering type's powers. ```python 379 def __init__(self, numbering_type: NumberingType = NumberingType.MID) -> None: 380 """Construction""" 381 self._numbering_type = numbering_type 382 self._units = [CNUnit(*UNITS[i], power=i + 1) for i in range(4)] # type: ignore[misc] 383 self._units[4:] = [CNUnit.create(i, self._numbering_type) for i in self._numbering_type.powers] ``` -------------------------------- ### get_int_value: Compute integer value from symbols Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Computes the integer value from a list of integer symbols. The example shows usage with NumberingSystem(NumberingType.MID) and cn2symbols, returning 18, 20000180, and 260000000 for the Chinese numbers 十八, 两千万一百八十, and 两亿六 respectively. ```python def get_int_value(self, integer_symbols: List[SymbolType]) -> int: """Compute the value from symbol Example: ```python >>> s = NumberingSystem(NumberingType.MID) >>> s.get_int_value(s.cn2symbols("十八")[0]) 18 >>> s.get_int_value(s.cn2symbols("两千万一百八十")[0]) 20000180 >>> s.get_int_value(s.cn2symbols("两亿六")[0]) 260000000 ``` Args: integer_symbols (List[SymbolType]): Symbols, without point Returns: int: value """ integer_symbols = self._refine_integer_symbols(integer_symbols) value = [0] last_power = 0 for s in integer_symbols: if isinstance(s, CNDigit): value[-1] = s.int_value elif isinstance(s, CNUnit): value[-1] *= pow(10, s.power) if s.power > last_power: value[:-1] = [v * pow(10, s.power) for v in value[:-1]] # pylint: disable=no-member last_power = s.power value.append(0) return sum(value) ``` ```python >>> s = NumberingSystem(NumberingType.MID) >>> s.get_int_value(s.cn2symbols("十八")[0]) 18 >>> s.get_int_value(s.cn2symbols("两千万一百八十")[0]) 20000180 >>> s.get_int_value(s.cn2symbols("两亿六")[0]) 260000000 ``` -------------------------------- ### pycnnum module source: NumberingType enum and CNChar dataclass Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html The source page shows the beginning of the pycnnum module source code, including the NumberingType enum and the CNChar dataclass. The code is displayed with line numbers in the documentation. The example includes the module docstring, imports, and the class definitions up to the CNUnit class declaration. ```python # pylint: disable=line-too-long """Chinese number <=> int/float conversion """ from __future__ import annotations import copy import re from dataclasses import dataclass from enum import Enum from functools import cached_property from math import log2 from typing import Callable, List, Optional, Tuple, Union from .constants import DIGITS, UNITS class NumberingType(Enum): r"""Numbering system types: LOW, MID, HIGH Chinese numbering types: For $i \in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]$: - `LOW` : $10^{8 + i}$ - `MID` : $10^{8 + i*4}$ - `HIGH` : $10^{2^{i+3}}$ --- | type | 亿 | 兆 | 京 | 垓 | 秭 | 穰 | 沟 | 涧 | 正 | 载 | |-------| --------|---------|---------|---------|----------|----------|----------|-----------|-----------|-----------| |`low` | $10^{8}$|$10^{9}$ |$10^{10}$|$10^{11}$|$10^{12}$ |$10^{13}$ |$10^{14}$ |$10^{15}$ |$10^{16}$ |$10^{17}$ | |`mid` | $10^{8}$|$10^{12}$|$10^{16}$|$10^{20}$|$10^{24}$ |$10^{28}$ |$10^{32}$ |$10^{36}$ |$10^{40}$ |$10^{44}$ | |`high` | $10^{8}$|$10^{16}$|$10^{32}$|$10^{64}$|$10^{128}$|$10^{256}$|$10^{512}$|$10^{1024}$|$10^{2048}$|$10^{4096}$| """ LOW = "low" """ | type | 亿 | 兆 | 京 | 垓 | 秭 | 穰 | 沟 | 涧 | 正 | 载 | |-------| --------|---------|---------|---------|----------|----------|----------|-----------|-----------|-----------| |`low` | $10^{8}$|$10^{9}$ |$10^{10}$|$10^{11}$|$10^{12}$ |$10^{13}$ |$10^{14}$ |$10^{15}$ |$10^{16}$ |$10^{17}$ | """ MID = "mid" """ | type | 亿 | 兆 | 京 | 垓 | 秭 | 穰 | 沟 | 涧 | 正 | 载 | |-------| --------|---------|---------|---------|----------|----------|----------|-----------|-----------|-----------| |`mid` | $10^{8}$|$10^{12}$|$10^{16}$|$10^{20}$|$10^{24}$ |$10^{28}$ |$10^{32}$ |$10^{36}$ |$10^{40}$ |$10^{44}$ | """ HIGH = "high" """ | type | 亿 | 兆 | 京 | 垓 | 秭 | 穰 | 沟 | 涧 | 正 | 载 | |-------| --------|---------|---------|---------|----------|----------|----------|-----------|-----------|-----------| |`high` | $10^{8}$|$10^{16}$|$10^{32}$|$10^{64}$|$10^{128}$|$10^{256}$|$10^{512}$|$10^{1024}$|$10^{2048}$|$10^{4096}$| """ @property def powers(self) -> List[int]: """Powers of units for each numbering type""" return { NumberingType.LOW: [8 + i for i in range(10)], NumberingType.MID: [8 + 4 * i for i in range(10)], NumberingType.HIGH: [2 ** (i + 3) for i in range(10)], }[self] # region char classes @dataclass class CNChar: """Base Chinese char class. Each object has simplified and traditional strings. When converted to string, it will shows the simplified string or traditional string or space `' '`. Example: ```python >>> negative = CNChar(simplified="负", traditional="負") >>> negative.simplified '负' >>> negative.traditional '負' >>> negative.upper_simplified '负' >>> negative.upper_traditional '負' ``` """ simplified: Optional[str] = None """Simplified Chinese character""" traditional: Optional[str] = None """Traditional Chinese character""" upper_simplified: Optional[str] = None """Capitalized character in simplified Chinese. Defaults to `None` means same as `self.simplified`.""" upper_traditional: Optional[str] = None """Capitalized character in traditional Chinese. Defaults to `None` means same as `self.traditional`.""" @property def all_forms(self) -> str: """All forms of the character""" return "".join(v for v in self.__dict__.values() if isinstance(v, str)) def __post_init__(self): """Post initialization""" self.simplified = self.simplified or "" self.traditional = self.traditional or self.simplified self.upper_simplified = self.upper_simplified or self.simplified self.upper_traditional = self.upper_traditional or self.traditional def __str__(self) -> str: return self.simplified if self.simplified else f"Empty {self.__class__.__name__}" def __repr__(self) -> str: return str(self) @dataclass class CNUnit(CNChar): """Chinese number unit class ``` -------------------------------- ### CNUnit.create Source: https://github.com/zcold/pycnnum/blob/master/doc/pycnnum/pycnnum.html Class method to create a CNUnit instance based on power and numbering type. ```APIDOC ## CNUnit.create ### Description Creates a CNUnit object based on a power value and numbering type. It selects the appropriate Chinese number unit character from predefined constants. ### Method classmethod ### Signature `create(cls, power: int, numbering_type: NumberingType = NumberingType.MID) -> CNUnit` ### Parameters - **power** (int) - Required - Unit power, starting from 1. - **numbering_type** (NumberingType, optional) - Defaults to `NumberingType.MID`. Numbering type. ### Returns - **CNUnit** - Created unit object. ### Raises - **ValueError** - Raised when invalid `numbering_type` is provided. ### Example ```python >>> CNUnit.create(power=8, numbering_type=NumberingType.LOW).simplified '亿' >>> CNUnit.create(power=12, numbering_type=NumberingType.LOW).simplified '秭' >>> CNUnit.create(power=12, numbering_type=NumberingType.HIGH).simplified Traceback (most recent call last): ... ValueError: power = 12 is invalid for numbering_type = ``` ```