Files
rappaurio-sae501_502/app/node_modules/cejs/data/numeral.js
2023-09-25 09:41:55 +02:00

1254 lines
37 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @name CeL function for numeral systems
* @fileoverview 本檔案包含了記數系統用的 functions。
*
* @since
*
* @see <a href="https://en.wikipedia.org/wiki/List_of_numeral_systems"
* accessdate="2015/4/30 21:50">List of numeral systems</a>
*/
'use strict';
if (false) {
CeL.run('data.numeral', function() {
CeL.to_Chinese_numeral(1000);
});
}
// --------------------------------------------------------------------------------------------
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
typeof CeL === 'function' && CeL.run({
// module name
name : 'data.numeral',
// data.native: .chars()
require : 'data.code.compatibility.|data.native.',
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
code : module_code
});
function module_code(library_namespace) {
var
/** {Number}未發現之index。 const: 基本上與程式碼設計合一,僅表示名義,不可更改。(=== -1) */
NOT_FOUND = ''.indexOf('_');
// nothing required
/**
* null module constructor
*
* @class 處理記數系統的 functions
*/
var _// JSDT:_module_
= function() {
// null module constructor
};
/**
* for JSDT: 有 prototype 才會將之當作 Class
*/
_// JSDT:_module_
.prototype = {};
// -----------------------------------------------------------------------------------------------------------------
// 中文數字 (Chinese numerals)
function to_search_pattern(keys) {
var key, chars = [], long_keys = [];
function add(key) {
if (key)
if (key.length === 1)
chars.push(key);
else
long_keys.push(key);
}
if (Array.isArray(keys))
keys.forEach(add);
else
for (key in keys)
add(key);
chars = chars.length > 0 ? '[' + chars.join('') + ']' : '';
if (long_keys.length > 0 && chars)
long_keys.push(chars);
// /(?:long_keys|long_keys|[chars])/g
// /[chars]/g
return new RegExp(long_keys.length > 0 ? '(?:' + long_keys.join('|')
+ ')' : chars, 'g');
}
var
// 小寫數字
Chinese_numerals_Normal_digits = '〇一二三四五六七八九',
//
Chinese_numerals_Normal_digits_Array
//
= Chinese_numerals_Normal_digits.split(''),
//
Chinese_numerals_Normal_digits_pattern
//
= to_search_pattern(Chinese_numerals_Normal_digits_Array),
//
numerals_Normal_pattern = new RegExp('('
//
+ Chinese_numerals_Normal_digits_pattern.source + '|\\d+)', 'g'),
// 籌算: 步十百千萬
amount_pattern = new RegExp(numerals_Normal_pattern.source + '?([十百千])',
'g'),
// 正式大寫數字
Chinese_numerals_Formal_digits = '零壹貳參肆伍陸柒捌玖',
//
Chinese_numerals_Formal_digits_Array
//
= Chinese_numerals_Formal_digits.split(''),
//
Chinese_numerals_Formal_digits_pattern
//
= to_search_pattern(Chinese_numerals_Formal_digits_Array),
// http://thdl.ntu.edu.tw/suzhou/
// 蘇州碼子又稱花碼、番仔碼、草碼、菁仔碼
Suzhou_numerals_digits = '〇〡〢〣〤〥〦〧〨〩',
// Counting Rod Numerals As of Unicode version 8.0
Counting_rod_numerals_digits
// https://en.wikipedia.org/wiki/Counting_Rod_Numerals
= '𝍠𝍡𝍢𝍣𝍤𝍥𝍦𝍧𝍨𝍩𝍪𝍫𝍬𝍭𝍮𝍯𝍰𝍱',
// 全形阿拉伯數字 U+FF10~U+FF19 FULLWIDTH DIGIT
FULLWIDTH_DIGITS = '',
//
positional_Chinese_numerals_digits
//
= Chinese_numerals_Normal_digits
//
+ Chinese_numerals_Formal_digits
//
+ Suzhou_numerals_digits.slice(1) + FULLWIDTH_DIGITS,
//
positional_Chinese_numerals_digits_pattern
//
= new RegExp('[' + positional_Chinese_numerals_digits + ']', 'g'),
//
only_positional_Chinese_numerals_digits_pattern
//
= new RegExp('^[' + positional_Chinese_numerals_digits + ']+$'),
// 舊時/非正式/通用數字 正規化
numeral_convert_pair = {
// o : '',
: '',
'○' : '',
: '壹',
: '貳',
: '二',
: '參',
: '參',
: '參',
: '四',
// Firefox/3.0.19 無法 parse '䦉': 錯誤: invalid property id
'䦉' : '肆',
// [[ja:大字 (数字)]]
: '壹',
: '貳',
: '貳',
: '參',
: '陸',
// 去除常用字以防 false positive
// 漆 : '柒',
// 俗亦以「什」代拾,然易竄為「仟」。
// 什 : '拾',
// 念圓 : '貳拾圓',
// 念 : '貳拾',
廿 : '二十',
: '二十',
: '三十',
// http://www.bsm.org.cn/show_article.php?id=1888
// "丗五年" = "卅五年"
: '三十',
// e.g., 卌又三年
: '四十',
// 罕作「圩」
// 圩 : '五十',
: '二百',
// 古亦作「陌」。
: '佰',
// 古亦作「阡」。
: '仟',
: '萬',
萬萬 : '億',
// 太常使用。
// 經 : '京',
: '秭',
: '穰',
: '釐'
// 太常使用。
// 毛 : '毫'
},
//
numeral_convert_pattern,
// denomination, 萬進系統單位
// http://zh.wikipedia.org/wiki/%E4%B8%AD%E6%96%87%E6%95%B0%E5%AD%97
// http://zh.wikipedia.org/wiki/%E5%8D%81%E8%BF%9B%E5%88%B6
// http://zh.wikipedia.org/wiki/%E4%B8%AD%E6%96%87%E6%95%B0%E5%AD%97
// http://lists.w3.org/Archives/Public/www-style/2003Apr/0063.html
// http://forum.moztw.org/viewtopic.php?t=3043
// http://www.moroo.com/uzokusou/misc/suumei/suumei.html
// http://espero.51.net/qishng/zhao.htm
// http://www.nchu.edu.tw/~material/nano/newsbook1.htm
// http://www.moroo.com/uzokusou/misc/suumei/suumei1.html
// 十億(吉),兆(萬億),千兆(拍),百京(艾),十垓(澤),秭(堯),秭:禾予;溝(土旁);,無量大數→,無量,大數;[載]之後的[極]有的用[報]
// 異體:阿僧[禾氏],For Korean:阿僧祗;秭:禾予,抒,杼,For Korean:枾 For
// Korean:不可思議(不:U+4E0D→U+F967)
// Espana應該是梵文所譯
// 因為根據「大方廣佛華嚴經卷第四十五卷」中在「無量」這個數位以後還有無邊、無等、不可數、不可稱、不可思、不可量、不可說、不可說不可說Espana應該是指上面其中一個..因為如果你有心查查Espana其實應該是解作西班牙文的「西班牙」
Chinese_numerals_Denominations
// ',萬,億,兆,京,垓,秭,穰,溝,澗,正,載,極,恒河沙,阿僧祇,那由他,不可思議,無量大數'
= ',萬,億,兆,京,垓,秭,穰,溝,澗,正,載,極',
//
Chinese_numerals_Denominations_Array
//
= Chinese_numerals_Denominations.split(','),
//
Chinese_numerals_Denominations_pattern
//
= to_search_pattern(Chinese_numerals_Denominations_Array),
//
Chinese_numerals_token_pattern
//
= new RegExp('(.*?)('
//
+ Chinese_numerals_Denominations_pattern.source + ')', 'g'),
// TODO:
// http://zh.wikipedia.org/wiki/%E5%8D%81%E9%80%80%E4%BD%8D
// 比漠微細的,是自天竺的佛經上的數字。而這些「佛經數字」已成為「古代用法」了。
// 小數單位(十退位):分,釐(厘),毫(毛),絲(秒),忽,微,纖,沙,塵(納),埃,渺,漠(皮),模糊,逡巡,須臾(飛),瞬息,彈指,剎那(阿),六德(德),虛,空,清,淨
// or:,虛,空,清,淨→,空虛,清淨(仄),阿賴耶,阿摩羅,涅槃寂靜(攸)
// 六釐英金庚款公債條例: 年息定為?釐, 年利率?厘
Chinese_numerals_Decimal_denominations = '分釐毫絲忽微纖沙塵埃渺漠',
//
numerals_Decimal_token_pattern
//
= new RegExp(numerals_Normal_pattern.source
//
+ '([' + Chinese_numerals_Decimal_denominations + '])', 'g'),
// 下數系統單位
Chinese_numerals_Normal_base_denomination
// 籌算: 步十百千萬
= (',十,百,千' + Chinese_numerals_Denominations).split(','),
//
Chinese_numerals_Formal_base_denomination
//
= (',拾,佰,仟' + Chinese_numerals_Denominations).split(','),
//
Chinese_numerals_Normal_pattern = new RegExp('(?:負?(?:['
+ Chinese_numerals_Normal_digits + '\\d ]['
+ Chinese_numerals_Normal_base_denomination.join('') + ']*|['
+ Chinese_numerals_Normal_base_denomination.join('')
+ ']+)+(又|分之)?)+', 'g'),
//
Chinese_numerals_Normal_Full_matched = new RegExp('^(?:負?['
+ Chinese_numerals_Normal_digits + '\\d '
+ Chinese_numerals_Normal_base_denomination.join('') + '又]+|分之)+$'),
//
numeral_value = Object.create(null);
_.Chinese_numerals_Normal_digits = Chinese_numerals_Normal_digits;
_.Chinese_numerals_Formal_digits = Chinese_numerals_Formal_digits;
_.Chinese_numerals_Denominations
//
= Chinese_numerals_Denominations_Array.join('');
(function() {
var base, scale = 0;
Chinese_numerals_Normal_digits_Array
//
.forEach(function(digits) {
numeral_value[digits] = scale;
scale++;
});
base = scale;
'十,百,千'.split(',')
// 籌算: 步十百千萬
.forEach(function(denomination) {
numeral_value[denomination] = scale;
scale *= base;
});
base = scale;
Chinese_numerals_Denominations_Array
//
.forEach(function(denomination) {
if (denomination) {
numeral_value[denomination] = scale;
scale *= base;
}
});
scale = .1;
Chinese_numerals_Decimal_denominations.split('')
//
.forEach(function(denomination) {
if (denomination) {
numeral_value[denomination] = scale;
scale /= 10;
}
});
for (scale = 1;
//
scale < Suzhou_numerals_digits.length; scale++) {
base = Suzhou_numerals_digits.charAt(scale);
numeral_value[base] = scale;
numeral_convert_pair[base]
//
= Chinese_numerals_Normal_digits[scale];
}
for (scale = 0;
//
scale < FULLWIDTH_DIGITS.length; scale++) {
base = FULLWIDTH_DIGITS.charAt(scale);
numeral_value[base] = scale;
numeral_convert_pair[base]
//
= Chinese_numerals_Normal_digits[scale];
}
numeral_convert_pattern
//
= to_search_pattern(numeral_convert_pair);
})();
// 對所有非正規之數字。
// TODO (bug): 十廿, 二廿
function normalize_Chinese_numeral(number_String) {
return number_String
// .replace(/\s+/g, '')
//
.replace(numeral_convert_pattern, function($0) {
return numeral_convert_pair[$0];
});
}
_.normalize_Chinese_numeral = normalize_Chinese_numeral;
function Chinese_numerals_Formal_to_Normal(number_String) {
return number_String.replace(Chinese_numerals_Formal_digits_pattern,
function($0) {
return Chinese_numerals_Normal_digits
//
.charAt(Chinese_numerals_Formal_digits.indexOf($0));
})
//
.replace(/[拾佰仟]/g, function(denomination) {
return '十百千'.charAt('拾佰仟'.indexOf(denomination));
});
}
_.Chinese_numerals_Formal_to_Normal
//
= Chinese_numerals_Formal_to_Normal;
function Chinese_numerals_Normal_to_Formal(number_String) {
return number_String.replace(Chinese_numerals_Normal_digits_pattern,
function($0) {
return Chinese_numerals_Formal_digits
//
.charAt(Chinese_numerals_Normal_digits.indexOf($0));
})
//
.replace(/[十百千]/g, function($0) {
return '拾佰仟'.charAt('十百千'.indexOf($0));
});
}
_.Chinese_numerals_Normal_to_Formal
//
= Chinese_numerals_Normal_to_Formal;
/**
* 將漢字中文數字轉換為半形阿拉伯數字表示法(小數系統 0-99999)
*
* @deprecated use from_Chinese_numeral.
*/
function deprecated_from_Chinese_numeral(number_String) {
if (!number_String || !isNaN(number_String))
return number_String;
number_String = Chinese_numerals_Formal_to_Normal(
//
normalize_Chinese_numeral('' + number_String));
var i = 0, l, m,
//
n = Chinese_numerals_Normal_digits_Array,
// 籌算: 萬千百十步
d = '萬千百十'.split(''), r = 0,
/**
* @see <a
* href="http://zh.wikipedia.org/wiki/%E6%97%A5%E8%AA%9E%E6%95%B8%E5%AD%97"
* accessdate="2012/9/10 21:0">日語數字</a>
*/
p = ('' + number_String).replace(/\s/g, '')
//
.replace(/[O○]/g, '');
for (; i < n.length; i++)
n[n[i]] = i;
for (i = 0; i < d.length; i++) {
if (p && NOT_FOUND !==
//
(m = d[i] ? p.indexOf(d[i]) : p.length))
if (!m && d[i] === '十')
r += 1, p = p.slice(1);
else if (isNaN(l = n[
//
p.slice(0, m).replace(/^+/, '')]))
return number_String;
else
r += l, p = p.slice(m + 1);
if (d[i])
r *= 10;
}
return r;
}
// More examples: see /_test suite/test.js
function from_positional_Chinese_numeral(number_String) {
return isNaN(number_String = number_String.replace(
positional_Chinese_numerals_digits_pattern, function(digit) {
return numeral_value[digit];
})) ? number_String : +number_String;
}
function to_positional_Chinese_numeral(number_String, formal) {
formal = formal ? Chinese_numerals_Formal_digits_Array
//
: Chinese_numerals_Normal_digits_Array;
return ('' + number_String)
//
.replace(/\d/g, function(digit) {
return formal[digit];
});
}
_.positional_Chinese_numerals_digits
//
= positional_Chinese_numerals_digits;
_.from_positional_Chinese_numeral
//
= from_positional_Chinese_numeral;
_.to_positional_Chinese_numeral
//
= to_positional_Chinese_numeral;
// 將漢字中文數字轉換為半形阿拉伯數字表示法。(正常情況下:小數系統 0-9999)
function from_Chinese_numeral_token(amount) {
if (!isNaN(amount))
return +amount;
// reset
amount_pattern.lastIndex = 0;
var token_sum = 0, matched, lastIndex = 0;
while (matched = amount_pattern.exec(amount)) {
lastIndex = amount_pattern.lastIndex;
// [ , digit, denomination ]
// for "一千零十一" 等。
token_sum += (matched[1]
//
&& matched[1] !== '' ? numeral_value[matched[1]] : 1)
//
* numeral_value[matched[2]];
}
// lastIndex 後面的全部放棄。
amount = amount.slice(lastIndex).replace(/^+/, '');
numerals_Normal_pattern.lastIndex = 0;
matched = numerals_Normal_pattern.exec(amount);
if (matched)
token_sum += isNaN(matched = matched[0])
//
? numeral_value[matched] : +matched;
return token_sum || 0;
}
/**
* 將漢字中文數字轉換為阿拉伯數字表示法。<br />
* 注意:本函數不會檢查 number_String 之正規與否!
*/
function from_Chinese_numeral(number_String) {
if (!number_String || !isNaN(number_String))
return number_String;
number_String = Chinese_numerals_Formal_to_Normal(
//
normalize_Chinese_numeral('' + number_String));
// console.log(Chinese_numerals_Normal_pattern);
// console.log(JSON.stringify(number_String));
if (!Chinese_numerals_Normal_Full_matched.test(number_String)) {
// 部分符合,僅針對符合部分處理。
Chinese_numerals_Normal_pattern.lastIndex = 0;
return number_String.replace(
//
Chinese_numerals_Normal_pattern, function($0) {
// console.log('-- ' + JSON.stringify($0));
// 避免前後空格被吃掉。
var token = $0.match(/^(\s*)(\S.*?)(\s*)$/);
if (!token) {
// 可能會是" "
return $0;
}
var digit = token[2].charAt(0);
token[2] = ('負十'.includes(digit)
|| positional_Chinese_numerals_digits.includes(digit)
|| (digit = token[2].charAt(1)) && ('十'.includes(digit)
//
|| positional_Chinese_numerals_digits.includes(digit))
// 不處理過大的位值,例如 "正"。
? from_Chinese_numeral(token[2]) : token[2]);
return token[1] + token[2] + token[3];
});
}
var sum = 0, lastIndex = 0,
//
negative = number_String.charAt(0) === '負',
//
matched = number_String
//
.match(/^(負)?(?:(.+)又)?(.+)分之(.+)$/);
if (matched) {
sum = (matched[2]
//
&& from_Chinese_numeral(matched[2]) || 0)
+ from_Chinese_numeral(matched[4])
/ from_Chinese_numeral(matched[3]);
return negative ? -sum : sum;
}
// reset
Chinese_numerals_token_pattern.lastIndex = 0;
// console.log([ number_String, Chinese_numerals_token_pattern ]);
while (matched = Chinese_numerals_token_pattern
//
.exec(number_String)) {
// [ , amount, denomination ]
// console.log(matched);
sum += from_Chinese_numeral_token(matched[1] || 1)
* numeral_value[matched[2]];
lastIndex = Chinese_numerals_token_pattern.lastIndex;
}
number_String = number_String.slice(lastIndex);
// reset
numerals_Decimal_token_pattern.lastIndex = 0;
// console.log([ sum, number_String, numerals_Decimal_token_pattern ]);
if (lastIndex = numerals_Decimal_token_pattern
//
.exec(number_String)) {
// 輸入 '捌佰3分' 之類。
// console.log(lastIndex);
lastIndex = lastIndex.index;
matched = [ , number_String.slice(0, lastIndex),
number_String.slice(lastIndex) ];
} else {
// 輸入 '捌佰3又3分' 之類。
matched = number_String.match(/(.*)[點又.](.*)/)
|| [ , number_String ];
}
if (false) {
console
.trace([ sum, matched, Chinese_numerals_Normal_Full_matched ]);
console.trace([ only_positional_Chinese_numerals_digits_pattern
.test(matched[1]) ]);
}
sum += only_positional_Chinese_numerals_digits_pattern.test(matched[1])
// e.g., CeL.from_Chinese_numeral('第一二三四章')
? from_positional_Chinese_numeral(matched[1])
: from_Chinese_numeral_token(matched[1]);
// console.trace(sum);
if (number_String = matched[2]) {
// 處理小數。
for (var base = .1, lastIndex = 0;; base /= 10) {
numerals_Decimal_token_pattern.lastIndex = lastIndex;
if (matched = numerals_Decimal_token_pattern
//
.exec(number_String)) {
lastIndex
//
= numerals_Decimal_token_pattern.lastIndex;
// 單位
base = numeral_value[matched[2]];
matched = matched[1];
} else {
numerals_Normal_pattern.lastIndex = lastIndex;
if (matched = numerals_Normal_pattern
//
.exec(number_String)) {
lastIndex
//
= numerals_Normal_pattern.lastIndex;
matched = matched[0];
} else
break;
}
if (isNaN(matched))
matched = numeral_value[matched];
else if (matched > 9)
matched = matched.replace(/^(\d)/, '$1.');
else
matched = +matched;
sum += matched * base;
}
}
return negative ? -sum : sum;
}
/**
* 將阿拉伯數字轉為中文數字<b>下數系統</b>大寫(Long scale)、小寫(Short scale)兩種表示法/中文數字讀法<br />
* 處理1-99999的數,尚有bug。
*/
function to_Chinese_numeral_Low_scale(number_String, formal) {
// 用r=[]約多花一倍時間!
var i = 0, r = '', l = number_String.length - 1, d,
//
tnum = formal ? Chinese_numerals_Formal_digits_Array
: Chinese_numerals_Normal_digits_Array,
//
zero = tnum[0],
//
tbd = formal ? Chinese_numerals_Formal_base_denomination
: Chinese_numerals_Normal_base_denomination;
for (; i <= l; i++)
// if(d=parseInt(number_String.charAt(i)))比較慢
if ((d = number_String.charAt(i)) !== '0')
// '〇一二三四五六七八'.charAt(d) 比較慢
r += tnum[d] + tbd[l - i];
else if (r.slice(-1) != zero)
if (Math.floor(number_String.slice(i + 1)))
r += zero;
else
break;
return r;
}
if (false)
(function() {
// 2.016,2.297,2.016
var d = new Date, v = '12345236', i = 0, a;
for (; i < 10000; i++)
a = to_Chinese_numeral(v);
alert(v + '\n→' + a + '\ntime:' + gDate(new Date - d));
});
/**
* 將阿拉伯數字轉為萬進中文數字表示法。 num>1京時僅會取概數此時得轉成string再輸入 TODO: 統整:尚有bug。 廿卅 小數
*
* @param {Number}number
* native number
* @param {Boolean}[formal]
* kind
*
* @returns {String} 中文數字
*
*/
function to_Chinese_numeral(number, formal) {
// number = parseFloat(number);
number = (typeof number === 'number'
//
? number.toString(10)
//
: '' + number)
// 避免前後空格被吃掉。
// .replace(/[,\s]/g, '')
;
if (!/^[+\-]?(?:\d+(?:\.\d*)?|(?:\d*\.)?\d+)$/.test(number)) {
// 非數值
return number.replace(
//
/[+\-]?(?:\d+(?:\.\d*)?|(?:\d*\.)?\d+)/g, function($0) {
// 避免前後空格被吃掉。
var token = $0.match(/^(\s*)(\S.*?)(\s*)$/);
if (!token) {
// 可能會是" "
return $0;
}
// console.log(token);
return token[1] + to_Chinese_numeral(token[2], formal)
+ token[3];
});
}
var j,
// i:integer,整數;
i,
// d:decimal,小數
d = number.indexOf('.'), k, l, m, addZero = false,
//
tnum = formal ? Chinese_numerals_Formal_digits_Array
//
: Chinese_numerals_Normal_digits_Array,
//
zero = tnum[0];
if (d === NOT_FOUND)
d = 0;
else
for (number = number.replace(/0+$/, ''),
//
i = number.slice(d + 1),
//
number = number.slice(0, d),
//
d = '', j = 0; j < i.length; j++)
// 小數
d += tnum[i.charAt(j)];
// 至此 number 為整數。
if (number.charAt(0) === '-')
i = '負', number = number.slice(1);
else
i = '';
number = number.replace(/^0+/, '');
m = number.length % 4, j = m - 4, l = (number.length - (m || 4)) / 4;
// addZero=false, l=Math.floor((number.length-1)/4)
for (; j < number.length; m = 0, l--)
// 這邊得用 parseInt( ,10):
// parseInt('0~')會用八進位,其他也有奇怪的效果。
if (Math.floor(m = m ? number.slice(0, m) : number
.substr(j += 4, 4))) {
m = to_Chinese_numeral_Low_scale(m, formal);
if (addZero = addZero && m.charAt(0) != zero) {
i += zero + m
//
+ Chinese_numerals_Denominations_Array[l];
addZero = false;
} else
i += m
//
+ Chinese_numerals_Denominations_Array[l];
} else
addZero = true;
// 習慣用法: 一十 → 十
return (i ? i.replace(/^(負)?[一壹]([十拾])/, '$1$2') : zero)
+ (d ? '點' + d : '');
}
_.from_Chinese_numeral = from_Chinese_numeral;
_.to_Chinese_numeral = to_Chinese_numeral;
/**
* 各區文化特色 - 貨幣轉換:<br />
* 轉換成新臺幣中文大寫金額表示法。<br />
* Converted into money notation.
*
* @example <code>
// More examples: see /_test suite/test.js
* </code>
*
* @param {Number|String}amount
* 貨幣數量。
* @returns {String} 新臺幣金額中文大寫表示法。
*
* @requires to_Chinese_numeral()
*/
function to_TWD(amount) {
if (typeof amount === 'string')
amount = amount.replace(/[\s,$]+/g, '');
amount = to_Chinese_numeral(amount, true)
// 銀行習慣用法,零可以不用寫。
.replace(/([佰仟萬億兆京垓秭穰溝澗正載極])零/g, '$1')
// 100000 → 壹拾萬圓整
.replace(/^拾/, '壹拾');
// 大寫金額數字應緊接“人民幣/港幣/台幣”字樣填寫,不得留有空位。
return '新臺幣' + (amount.includes('點') ? amount.replace(
//
/點(.)(.)?(.)?/, function($0, $1, $2, $3) {
return '圓' + $1 + '角'
// 日本明治時代臺灣 1圓=100錢=1000厘, 不使用"零"這個數字
// e.g., "五百三圓二十三錢五厘"
+ ($2 ? $2 + '分' + ($3 ? $3 + '文' : '') : '');
}) :
// 在“元”(或“圓”)之後、應寫“整”(或“正”)字
// 在“角”之後,可以不寫“整”(或“正”)字
// 大寫金額數字有“分”的,“分”後面不寫“整”(或“正”)字。
amount + '圓整');
}
_// JSDT:_module_
.to_TWD = to_TWD;
/**
* Japanese numerals
*
* @param {Number}number
* native number
*
* @returns {String} Japanese numerals
*/
function to_Japanese_numeral(number) {
return to_Chinese_numeral(number).replace(//g, '').replace(/萬/, '万');
}
_.to_Japanese_numeral = to_Japanese_numeral;
// https://en.wikipedia.org/wiki/Long_and_short_scales
// http://blog.functionalfun.net/2008/08/project-euler-problem-17-converting.html
var English_numerals = {
0 : "zero",
1 : "one",
2 : "two",
3 : "three",
4 : "four",
5 : "five",
6 : "six",
7 : "seven",
8 : "eight",
9 : "nine",
10 : "ten",
11 : "eleven",
12 : "twelve",
13 : "thirteen",
14 : "fourteen",
15 : "fifteen",
16 : "sixteen",
17 : "seventeen",
18 : "eighteen",
19 : "nineteen",
20 : "twenty",
30 : "thirty",
40 : "forty",
50 : "fifty",
60 : "sixty",
70 : "seventy",
80 : "eighty",
90 : "ninety",
100 : "hundred",
1000 : "thousand",
1000000 : "million",
1000000000 : "billion",
1000000000000 : "trillion",
1000000000000000 : "quadrillion",
// Number.isSafeInteger(1000000000000000000) === false
'1000000000000000000' : "quintillion"
};
// @inner
function to_English_numeral_small(number) {
// assert: number = 1 ~ 999
// hundreds
var conversion = number / 100 | 0;
if (number %= 100)
if (number in English_numerals)
number = English_numerals[number];
else {
// units
var _1 = number % 10;
_1 = _1 ? English_numerals[_1] : '';
// tens
number = number / 10 | 0;
if (number) {
number = English_numerals[number * 10];
if (_1)
number += '-' + _1;
} else
number = _1;
}
if (conversion) {
conversion = English_numerals[conversion] + ' '
+ English_numerals[100];
if (number)
conversion += ' and ' + number;
} else
conversion = number;
return conversion;
}
// written out numbers in words. Get number name.
// British usage
// @see http://www.grammarbook.com/numbers/numbers.asp
function to_English_numeral(number) {
if (number != Math.floor(number)) {
library_namespace.error('Cannot conver [' + number + ']!');
}
number = Math.floor(number);
if (number < 0)
return "negative " + to_English_numeral(-number);
if (number < 91 && (number in English_numerals))
// for zero.
return English_numerals[number];
var base = 1000, unit = 1, conversion = [], remainder,
// remainder, 0 ~ 999 (1000-1)
small = number % base;
while (number = Math.floor(number / base)) {
unit *= base;
if (remainder = number % base)
conversion.unshift(to_English_numeral_small(remainder) + ' '
+ English_numerals[unit]);
}
if (conversion = conversion.join(', ')) {
if (small)
conversion += ' and '
//
+ to_English_numeral_small(small);
} else
conversion = small ? to_English_numeral_small(small) : '';
return conversion;
}
_.to_English_numeral = to_English_numeral;
// -----------------------------------------------------------------------------------------------------------------
// (十進位)位值直接轉換用
// https://en.wikipedia.org/wiki/Positional_notation
function convert_positional(digit_set, name) {
var digits;
if (typeof digit_set !== 'string' || 10 !==
//
(digits = digit_set.chars()).length) {
library_namespace.error('Invalid digits of [' + name + ']: ('
+ digits.length + ') [' + digit_set + ']');
return;
}
var PATTERN_numeral = new RegExp(
digit_set.length === digits.length ? '[' + digit_set + ']'
: digits.join('|'), 'g');
digits.forEach(function(digit, index) {
numeral_convert_pair[digit] = index;
});
/**
* native number → positional numeral system
*
* @param {Number}number
* native number
*
* @returns {String} specified numerals
*/
function to_numeral(number) {
return String(number).replace(/\d/g, function(digit) {
return digits[digit];
});
}
/**
* positional numeral system → native number
*
* @param {String}number
* specified numerals
*
* @returns {Number} native number
*/
to_numeral.from = function from_numeral(number) {
number = String(number).replace(PATTERN_numeral, function(digit) {
return numeral_convert_pair[digit];
});
if (!isNaN(number))
number = Number(number);
return number;
}
return to_numeral;
}
// http://wikimediafoundation.org/wiki/Template:ConvertDigit
// https://github.com/esetera/Objavi/blob/master/digits.txt
// https://de.wikipedia.org/wiki/Zahlzeichen_in_Unicode
// TODO: https://en.wiktionary.org/wiki/8
(function() {
var positional_digits = {
// Eastern Arabic numerals
// https://en.wikipedia.org/wiki/Eastern_Arabic_numerals
// 中東阿拉伯文數字, 標準阿拉伯文數字
// Western Arabic / HinduArabic numeral system: 0123456789
// 在埃及,「二」通常用另一種寫法。
Arabic : '٠١٢٣٤٥٦٧٨٩',
// Perso-Arabic variant, Persian, Urdu, 東阿拉伯文數字
Perso : '۰۱۲۳۴۵۶۷۸۹',
Balinese : '᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙',
// Bengali numerals (সংখ্যা shôngkhæ), 孟加拉文數字,
// Bengali-Assamese numerals
// https://en.wikipedia.org/wiki/Bengali_numerals
// ৴৵৶৷৸৹
Bangla : '০১২৩৪৫৬৭৮৯',
Brahmi : '𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯',
Chakma : '𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿',
Cham : '꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙',
// 天城文(देवनागरी / devanāgarī
// https://hi.wikipedia.org/wiki/%E0%A4%AE%E0%A5%80%E0%A4%A1%E0%A4%BF%E0%A4%AF%E0%A4%BE%E0%A4%B5%E0%A4%BF%E0%A4%95%E0%A4%BF:Gadget-Numeral_converter.js
// https://hi.wikipedia.org/wiki/%E0%A4%B5%E0%A4%BF%E0%A4%95%E0%A4%BF%E0%A4%AA%E0%A5%80%E0%A4%A1%E0%A4%BF%E0%A4%AF%E0%A4%BE:%E0%A4%85%E0%A4%82%E0%A4%95_%E0%A4%AA%E0%A4%B0%E0%A4%BF%E0%A4%B5%E0%A4%B0%E0%A5%8D%E0%A4%A4%E0%A4%95
Devanagari : '०१२३४५६७८९',
Gujarati : '૦૧૨૩૪૫૬૭૮૯',
// Gurmukhī numerals
// https://en.wikipedia.org/wiki/Gurmukh%C4%AB_alphabet#Numerals
Gurmukhi : '੦੧੨੩੪੫੬੭੮੯',
Javanese : '꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙',
Kannada : '೦೧೨೩೪೫೬೭೮೯',
// Kayah Li
Kayah_Li : '꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉',
// Khmer, Cambodian, 高棉文數字.
// https://km.wikipedia.org/wiki/%E1%9E%91%E1%9F%86%E1%9E%96%E1%9F%90%E1%9E%9A%E1%9E%82%E1%9F%86%E1%9E%9A%E1%9E%BC:Number_table_sorting
Khmer : '០១២៣៤៥៦៧៨៩',
// Tai Tham Hora 十進位數字系統。
Lanna : '᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉',
// Tai Tham Tham 十進位數字系統。老傣文,又稱老傣仂文、蘭納文. Lanna script
Tai_Tham : '᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙',
// 寮國/寮文數字
Lao : '໐໑໒໓໔໕໖໗໘໙',
Lepcha : '᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉',
Limbu : '᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏',
Malayalam : '൦൧൨൩൪൫൬൭൮൯',
// Meitei-Mayek
Meitei_Mayek : '꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹',
Mongolian : '᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙',
// or Burmese. 緬甸文數字.
// 警告:其中非空!
Myanmar : '၀၁၂၃၄၅၆၇၈၉',
// 緬甸撣邦文十進位數字系統。
// 警告:其中非空!
Myanmar_Shan : '႐႑႒႓႔႕႖႗႘႙',
// Neu-Tai-Lue.
Neu_Tai_Lue : '᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙',
// N'Ko, r to l
NKo : '߀߁߂߃߄߅߆߇߈߉',
Oriya : '୦୧୨୩୪୫୬୭୮୯',
// Ol Chiki decimal numeral system. 桑塔爾文十進位數字系統。
Ol_Chiki : '᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙',
Osmanya : '𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩',
Saurashtra : '꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙',
Sharada : '𑇐𑇑𑇒𑇓𑇔𑇕𑇖𑇗𑇘𑇙',
// Sorang-Sompeng
Sorang_Sompeng : '𑃰𑃱𑃲𑃳𑃴𑃵𑃶𑃷𑃸𑃹',
Sundanese : '᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹',
Takri : '𑛀𑛁𑛂𑛃𑛄𑛅𑛆𑛇𑛈𑛉',
// Tamil (Grantha), 泰米爾文數字
// https://www.adobe.com/type/browser/pdfs/1965.pdf
Tamil : '௦௧௨௩௪௫௬௭௮௯',
Telugu : '౦౧౨౩౪౫౬౭౮౯',
// 藏文數字
Tibetan : '༠༡༢༣༤༥༦༧༨༩',
// 泰文數字 th:ตัวเลขไทย
// https://th.wikipedia.org/wiki/%E0%B8%95%E0%B8%B1%E0%B8%A7%E0%B9%80%E0%B8%A5%E0%B8%82%E0%B9%84%E0%B8%97%E0%B8%A2
Thai : '๐๑๒๓๔๕๖๗๘๙',
Vai : '꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩'
};
for ( var name in positional_digits) {
var to_numeral = convert_positional(positional_digits[name], name);
if (to_numeral) {
_['to_' + name + '_numeral'] = to_numeral;
_['from_' + name + '_numeral'] = to_numeral.from;
}
}
})();
// -----------------------------------------------------------------------------------------------------------------
// Roman numerals
// https://en.wikipedia.org/wiki/Roman_numerals
// https://en.wiktionary.org/wiki/Appendix:Roman_numerals
// TODO: to Alternative forms
var Roman_numeral_alternative = {
'ↅ' : 'VI',
'ↆ' : 'L',
// Safari 11: Invalid character
'' : 'L',
'' : 'C',
'' : 'D',
'' : 'M',
'' : 'L',
'' : 'C',
'' : 'D',
'ⅿ' : 'M',
'ↀ' : 'M'
}, PATTERN_Roman_numeral_alternative,
//
Roman_numeral_pair = {},
//
PATTERN_Roman = [],
// assert: 2個一組為十進位。
Roman_numeral_value = 'IVXLCDMↁↂↇↈ'.split(''),
// Roman_numeral_value[apostrophus_starts] 開始為 apostrophus 表示法。
apostrophus_starts = Roman_numeral_value.indexOf('ↁ');
Roman_numeral_value.forEach(function(digit, index) {
var is_unit = index % 2 === 0, next;
Roman_numeral_pair[digit] = (is_unit ? 1 : 5)
* Math.pow(10, index / 2 | 0);
if (is_unit) {
var next = Roman_numeral_value[index + 1];
PATTERN_Roman.unshift('('
+ (next ? digit + '[' + next
+ Roman_numeral_value[index + 2] + ']|' + next
+ '?' : '') + digit + '*)');
}
});
// 千百十個: /(M*)(C[DM]|D?C*)(X[LC]|L?X*)(I[VX]|V?I*)/i
PATTERN_Roman = new RegExp(PATTERN_Roman.join(''), 'i');
// console.log(PATTERN_Roman);
// /(ↈ*)(ↂ[ↇↈ]|ↇ?ↂ*)(M[ↁↂ]|ↁ?M*)(C[DM]|D?C*)(X[LC]|L?X*)(I[VX]|V?I*)/i
// apostrophus: expressed in "apostrophus" notation.
function to_Roman_numeral(number, apostrophus) {
if (!(number > 0) || number != (number | 0)) {
/**
* the word nulla (the Latin word meaning "none") was used by
* medieval computists in lieu of 0.<br />
* About 725, Bede or one of his colleagues used the letter N, the
* initial of nulla, in a table of epacts, all written in Roman
* numerals.
*/
// return number === 0 ? 'N' : number;
return number;
}
/** {Natural}已處理的 Roman 數字。 */
var value = [],
/** {Natural}剩下尚未處理的數值。 */
left = number | 0;
// 將 apostrophus 轉成可接受的最大 index。
apostrophus = apostrophus ? Roman_numeral_value.length
: apostrophus_starts;
// index += 2: assert: 2個一組為十進位。
for (var index = 0; left > 0; index += 2) {
if (index >= apostrophus) {
library_namespace.error(
// OUT OF RANGE: number ≥ 1000000
'The number is too large to be expressed in Roman numerals: '
+ number);
return;
}
var digits,
/** {Integer}位值。 */
position = left % 10;
left = left / 10 | 0;
if ((position + 1) % 5 === 0 && apostrophus >
// position = 4 or 9 時之特殊處置。必須有此數字表示法,才允許通過。
(digits = index + (position === 4 ? 1 : 2))) {
digits = Roman_numeral_value[index]
+ Roman_numeral_value[digits];
} else {
if (position > 4
// [index + 1] 可能已經越界。
&& (digits = Roman_numeral_value[index + 1])) {
position -= 5;
} else {
digits = '';
}
digits += Roman_numeral_value[index].repeat(position);
}
value.push(digits);
}
return value.reverse().join('');
}
function Roman_position(previous, position) {
if (!position)
return previous;
if (position.length === 1)
return previous + Roman_numeral_pair[position];
var _1 = Roman_numeral_pair[position[0]],
//
_2 = Roman_numeral_pair[position[1]];
if (_2 > _1)
// assert: position.length === 2
return previous + _2 - _1;
return previous + _1 + _2 * (position.length - 1);
}
// TODO: 'Ↄ', 'ↄ'
function from_Roman_numeral(number) {
var matched = normalize_Roman_numeral(number).match(PATTERN_Roman);
return matched ? matched.slice(1).reduce(Roman_position, 0) : number;
}
function normalize_Roman_numeral(number) {
return String(number)
// 正規化。
.replace(PATTERN_Roman_numeral_alternative, function(digit) {
return Roman_numeral_alternative[digit];
});
}
_.to_Roman_numeral = to_Roman_numeral;
_.from_Roman_numeral = from_Roman_numeral;
_.normalize_Roman_numeral = normalize_Roman_numeral;
'ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ'.split('').forEach(function(digit, index) {
Roman_numeral_alternative[digit] = to_Roman_numeral(index + 1);
});
'ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻ'.split('').forEach(function(digit, index) {
Roman_numeral_alternative[digit] = to_Roman_numeral(index + 1);
});
PATTERN_Roman_numeral_alternative = new RegExp('['
+ Object.keys(Roman_numeral_alternative) + ']', 'g');
if (false)
(function() {
for (var i = 1; i < 50000; i++)
if (i !== CeL.from_Roman_numeral(CeL.to_Roman_numeral(i)))
throw 'Error: ' + i + ' → ' + CeL.to_Roman_numeral(i)
+ ' → '
+ CeL.from_Roman_numeral(CeL.to_Roman_numeral(i));
});
// -----------------------------------------------------------------------------------------------------------------
return (_// JSDT:_module_
);
}