npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cjk-number

v1.0.0

Published

Convert between numbers and CJK number systems

Readme

cjk-number

Static Badge CI GitHub LicenseCodeQL Advanced

Convert numbers between Arabic values and CJK numeral systems.

Supported domains include:

  • Traditional and simplified Chinese numerals
  • Formal and informal variants
  • Heavenly stems and earthly branches
  • Korean and Japanese numeric kanji/hanja styles
  • Kana sequence systems (gojuon and iroha)
  • Negative numbers, decimals, and very large BigInt values

繁體中文 | 简体中文 | 日本語 | 한국어

Install

npm install cjk-number

Runtime

  • Node.js 18+
  • ESM package

Quick Start

import {
  number,
  cjkIdeographic,
  tradChineseInformal,
  tradChineseFormal,
  simpChineseInformal,
  simpChineseFormal,
  cjkHeavenlyStem,
  cjkEarthlyBranch,
  koreanHangulFormal,
  japaneseFormal,
  hiragana
} from "cjk-number";

// parse string -> number / bigint / string
number.parse("一千零二十三"); // 1023
number.parse("壹仟零貳拾參"); // 1023
number.parse("負一百零二"); // -102
number.parse("一點二三"); // 1.23
number.parse("一無量大數", { mode: "preferBigInt" }); // 10n ** 68n
number.parse("一京點一", { mode: "exactDecimal" }); // "10000000000000000.1" (lossless)

// format number/bigint/string -> CJK
cjkIdeographic.parse(1023); // "一千零二十三"
tradChineseFormal.parse(1023); // "壹仟零貳拾參"
simpChineseFormal.parse(1023); // "壹仟零贰拾叁"
koreanHangulFormal.parse(10n ** 68n); // "일무량대수"
japaneseFormal.parse(10n ** 68n); // "壱無量大数"

// arithmetic on CJK strings (exact BigFloat engine)
tradChineseInformal.add(["一兆", "一點五"]); // "一兆零一點五"
tradChineseInformal.subtract(["一京", "一兆"]); // "九千九百九十九兆"
tradChineseInformal.multiply(["一億", "一億"]); // "一京"
tradChineseInformal.divide(["五", "二"]); // "二點五"
tradChineseInformal.modulo("五", "二"); // "一"
tradChineseInformal.pow("二", "十"); // "一千零二十四"
tradChineseInformal.abs("負一兆"); // "一兆"
["三十", "二", "十一"].sort(tradChineseInformal.compare); // ["二", "十一", "三十"]

// stem/branch
cjkHeavenlyStem.parse(10); // "癸"
cjkEarthlyBranch.parse(12); // "亥"

// sequence systems
hiragana.parse(1); // "あ"
hiragana.parse(46); // "ん"

API

number.parse(input, options?)

Parses CJK text into a number, bigint, or exact decimal string.

Options:

| Option | Type | Default | Description | |---|---|---|---| | mode | "number" \| "preferBigInt" \| "exactDecimal" | "number" | Controls the output numeric type | | strict | boolean | false | Rejects unsupported characters early | | explicitTyping | ExplicitTyping | undefined | Forces a specific CJK system for parsing |

mode values:

  • "number" (default) — returns number; auto-promotes to bigint if the integer exceeds Number.MAX_SAFE_INTEGER.
  • "preferBigInt" — always returns bigint for integer parse paths.
  • "exactDecimal" — returns a lossless decimal string (e.g. "10000000000000000.1"), bypassing the MAX_SAFE_INTEGER restriction for mixed large+decimal values.

explicitTyping values:

  • Choose from any of the available system names (e.g., "hiraganaIroha", "tradChineseFormal", "koreanHangulFormal") to force the parser to use that system's mapping specifically. This is useful for resolving conflicts between systems that share the same symbols (like Hiragana Gojuon vs Iroha).

Examples:

number.parse("九千零七兆一", { mode: "preferBigInt" }); // 9007000000000001n
number.parse("癸"); // 10
number.parse("亥"); // 12
number.parse("壱京", { mode: "preferBigInt" }); // 10n ** 16n
number.parse("ぬ", { explicitTyping: "hiraganaIroha" }); // 10
number.parse("ぬ"); // 23 (default gojuon sequence)
number.parse("一京點一", { mode: "exactDecimal" }); // "10000000000000000.1"

Formatters

All formatters expose the following methods:

parse(value)

Formats a number, bigint, or exact decimal string into a CJK numeral string.

Arithmetic methods

All numeric formatters (not cyclic/sequence ones) also expose arithmetic methods that accept CJK strings and return a CJK string in the same numeral system:

tradChineseInformal.add(["一千", "二十三"]); // "一千零二十三"
tradChineseInformal.subtract(["一京", "一兆"]); // "九千九百九十九兆"
tradChineseInformal.multiply(["一億", "一億"]); // "一京"
tradChineseInformal.divide(["五", "二"]); // "二點五"
tradChineseInformal.modulo("五", "二"); // "一"
tradChineseInformal.pow("二", "三"); // "八"
tradChineseInformal.pow("二", 3); // "八" (exponent can be a number)
tradChineseInformal.abs("負五十"); // "五十"
tradChineseInformal.compare("三十", "二"); // 1
["三十", "二", "十一"].sort(tradChineseInformal.compare); // ["二", "十一", "三十"]

All arithmetic uses a zero-dependency BigFloat engine: decimal points are scaled out to BigInt before any operation, so results like "一兆" + "一點五" are exact with no floating-point drift.

Available formatters:

  • cjkIdeographic
  • tradChineseInformal
  • tradChineseFormal
  • simpChineseInformal
  • simpChineseFormal
  • cjkHeavenlyStem
  • cjkEarthlyBranch
  • koreanHangulFormal
  • koreanHanjaFormal
  • koreanHanjaInformal
  • japaneseFormal
  • japaneseInformal
  • hiragana
  • hiraganaIroha
  • katakana
  • katakanaIroha

Sequence system methods

All sequence systems (stems, branches, and kana) also expose methods for traversing and decoding the sequence:

  • decode(symbol): Returns the 1-indexed numeric value of a symbol in the specific sequence.
  • next(symbol, count?): Returns the next symbol in the sequence (cyclic).
  • prev(symbol, count?): Returns the previous symbol in the sequence (cyclic).
  • range(start, end): Returns an array of symbols from start to end (inclusive).

Example:

hiraganaIroha.decode("ぬ"); // 10
hiragana.decode("ぬ"); // 23 (gojuon)

cjkHeavenlyStem.next("癸"); // "甲"
cjkEarthlyBranch.prev("子", 2); // "戌"
hiraganaIroha.range("ゑ", "す"); // ["ゑ", "ひ", "も", "せ", "す"]

Examples:

tradChineseInformal.parse(-320); // "負三百二十"
simpChineseInformal.parse(12.34); // "十二点三四"
tradChineseFormal.parse(10n ** 68n); // "壹無量大數"
simpChineseFormal.parse(10n ** 64n); // "壹不可思议"

cjkHeavenlyStem.parse(11, { mode: "cyclic" }); // "甲"
cjkEarthlyBranch.parse(13, { mode: "cyclic" }); // "子"

System Coverage

Full numeric systems (large-unit aware)

These support complete number formatting/parsing and large units up to 無量大數 / 无量大数:

  • tradChineseInformal
  • tradChineseFormal
  • simpChineseInformal
  • simpChineseFormal
  • koreanHangulFormal
  • koreanHanjaFormal
  • koreanHanjaInformal
  • japaneseFormal
  • japaneseInformal

Sequence systems

These are order-based symbol sequences, not positional decimal numerals:

  • cjkHeavenlyStem: 10 symbols
  • cjkEarthlyBranch: 12 symbols
  • hiragana: modern gojuon sequence (46 symbols)
  • katakana: modern gojuon sequence (46 symbols)
  • hiraganaIroha: traditional iroha sequence (47 symbols, includes ゐ and ゑ)
  • katakanaIroha: traditional iroha sequence (47 symbols, includes ヰ and ヱ)

For sequence formatters:

  • fixed mode: only accepts 1..length
  • cyclic mode: wraps by sequence length

Supported Large Units

Traditional:

萬, 億, 兆, 京, 垓, 秭, 穰, 溝, 澗, 正, 載, 極, 恆河沙, 阿僧祇, 那由他, 不可思議, 無量大數

Simplified:

万, 亿, 兆, 京, 垓, 秭, 穰, 沟, 涧, 正, 载, 极, 恒河沙, 阿僧祇, 那由他, 不可思议, 无量大数

Korean naming set:

만, 억, 조, 경, 해, 자, 양, 구, 간, 정, 재, 극, 항하사, 아승기, 나유타, 불가사의, 무량대수

Japanese naming set:

万, 億, 兆, 京, 垓, 秭, 穣, 溝, 澗, 正, 載, 極, 恒河沙, 阿僧祇, 那由他, 不可思議, 無量大数

Note:

  • Historical texts may assign different powers for some high-order names.
  • This package uses a fixed modern 10^4-step progression across supported large-unit systems.

Strict Mode

strict: true validates input characters against an allowed set.

Use it when you want to reject unexpected symbols early.

number.parse("一億", { strict: true }); // ok
number.parse("abc", { strict: true }); // throws SyntaxError

Error Cases

Common thrown errors:

  • SyntaxError: unsupported or invalid text shape
  • RangeError: invalid formatter range in fixed sequence mode
  • RangeError: non-integer passed to integer-only paths
  • RangeError: decimal parse integer part exceeds Number.MAX_SAFE_INTEGER — use { mode: "exactDecimal" } to bypass
  • RangeError: division by zero in divide or modulo

Development

Install and verify:

npm install
npm run typecheck
npm test
npm run build

Release preflight:

npm run release:check

Dry-run package content:

npm run pack:check

Property-style test environment variables:

  • CJK_TEST_SEED (default: 20260327)
  • CJK_TEST_SAMPLES (default: 100)
  • CJK_TEST_MAX_DIGITS (default: 69)

Example:

CJK_TEST_SEED=42 CJK_TEST_SAMPLES=1000 CJK_TEST_MAX_DIGITS=69 npm test

License

MIT