こうこく
作 ▸

JavaScriptで数値を漢数字表記に変換する

例えば 1,234,567,890 → 十二億三千四百五十六万七千八百九十 とかです。

関数を作ってみました。が、コード内には無量大数とか書いてありますが、実際には safe integer の範囲内にしか対応してません。これは今のChrome (ver.71) だと -9007199254740991 ~ 9007199254740991 です。

safe integerの範囲を無視しても、1垓 (10^20) を超えたあたりからは数値を文字列にキャストした時に指数表記 (1e+20みたいな) になってしまうので、うまく変換できませんでした。

なので、以下のコードでは9,007兆くらいが限界です。

/**
 * 数値を漢数字表記に変換
 * @param  {String|Number} num - 半角数字
 * @return {String} 漢数字表記
 * @throws {TypeError} 半角数字以外の文字が含まれている場合
 * @throws {RangeError} 数値が Number.MIN_SAFE_INTEGER ~ Number.MAX_SAFE_INTEGER の範囲外の場合
 */
const numbersToKanji = (num) => {
	if (num === undefined || num === null || num === '') {
		return '';
	}
	if (!(/^-?[0-9]+$/g.test(num))) {
		throw new TypeError('半角数字以外の文字が含まれています。漢数字に変換できませんでした。-> '+ num);
	}
	num = Number(num);
	if (!Number.isSafeInteger(num)) {
		throw new RangeError('数値が '+ Number.MIN_SAFE_INTEGER +' ~ '+ Number.MAX_SAFE_INTEGER +' の範囲外です。漢数字に変換できませんでした。-> '+ num);
	}
	if (num === 0) {
		return '零';
	}
	let ret = '';
	if (num < 0) {
		ret += 'マイナス';
		num *= -1;
	}
	const numStr = num + '';
	const kanjiNums = ['','一','二','三','四','五','六','七','八','九'];
	const kanjiNames = ['十','百','千','万','億','兆','京','垓','𥝱','穣','溝','澗','正','載','極','恒河沙','阿僧祇','那由他','不可思議','無量大数'];
	const exponents = [1,2,3,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68];
	const exponentsLen = exponents.length;
	for (let i = exponentsLen; i >= 0; --i) {
		const bias = Math.pow(10, exponents[i]);
		if (num >= bias) {
			const top = Math.floor(num / bias);
			if (top >= 10) {
				ret += numbersToKanji(top);
			} else {
				if (top == 1 && exponents[i] <= 3) {
					// ※先頭の数字が1、かつ指数が3 (千の位) 以下の場合のみ『一』をつけない
				} else {
					ret += kanjiNums[top];
				}
			}
			ret += kanjiNames[i];
			num -= top * bias;
		}
	}
	ret += kanjiNums[num];
	return ret;
};

以下テストケースです。

console.log(numbersToKanji(0));  // -> '零'
console.log(numbersToKanji(1));  // -> '一'
console.log(numbersToKanji(2));  // -> '二'
console.log(numbersToKanji(3));  // -> '三'
console.log(numbersToKanji(4));  // -> '四'
console.log(numbersToKanji(5));  // -> '五'
console.log(numbersToKanji(6));  // -> '六'
console.log(numbersToKanji(7));  // -> '七'
console.log(numbersToKanji(8));  // -> '八'
console.log(numbersToKanji(9));  // -> '九'
console.log(numbersToKanji(10));  // -> '十'
console.log(numbersToKanji(11));  // -> '十一'
console.log(numbersToKanji(100));  // -> '百'
console.log(numbersToKanji(111));  // -> '百十一'
console.log(numbersToKanji(1000));  // -> '千'
console.log(numbersToKanji(1111));  // -> '千百十一'
console.log(numbersToKanji(10000));  // -> '一万'
console.log(numbersToKanji(11111));  // -> '一万千百十一'
console.log(numbersToKanji(100000));  // -> '十万'
console.log(numbersToKanji(111111));  // -> '十一万千百十一'
console.log(numbersToKanji(1000000));  // -> '百万'
console.log(numbersToKanji(1111111));  // -> '百十一万千百十一'
console.log(numbersToKanji(10000000));  // -> '千万'
console.log(numbersToKanji(11111111));  // -> '千百十一万千百十一'
console.log(numbersToKanji(100000000));  // -> '一億'
console.log(numbersToKanji(111111111));  // -> '一億千百十一万千百十一'
console.log(numbersToKanji(1234567890));  // -> '十二億三千四百五十六万七千八百九十'
console.log(numbersToKanji(1000000000000));  // -> '一兆'
console.log(numbersToKanji(9007199254740991));  // -> '九千七兆千九百九十二億五千四百七十四万九百九十一'
console.log(numbersToKanji(-1));           // -> 'マイナス一'
console.log(numbersToKanji(-1234567890));  // -> 'マイナス十二億三千四百五十六万七千八百九十'

console.log(numbersToKanji());      // -> ''
console.log(numbersToKanji(null));  // -> ''
console.log(numbersToKanji(''));    // -> ''
console.log(numbersToKanji('9'));   // -> '九'

// エラーケース
try {
	numbersToKanji('1a');
} catch (e) {
	console.log(e.toString());  // -> TypeError: 半角数字以外の文字が含まれています。漢数字に変換できませんでした。-> 1a
}
try {
	numbersToKanji(9007199254740991 + 1);
} catch (e) {
	console.log(e.toString());  // -> RangeError: 数値が -9007199254740991 ~ 9007199254740991 の範囲外です。漢数字に変換できませんでした。-> 9007199254740992
}
この記事に何かあればこちらまで (非公開)