mirror of
				https://scm.univ-tours.fr/22107988t/rappaurio-sae501_502.git
				synced 2025-11-04 15:05:23 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1254 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1254 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						||
 * @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 = '0123456789',
 | 
						||
	//
 | 
						||
	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 : '〇',
 | 
						||
		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 / Hindu–Arabic 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_
 | 
						||
	);
 | 
						||
}
 |