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

1766 lines
51 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 data function
* @fileoverview 本檔案包含了 data 處理的 functions。
* @since
*/
'use strict';
// 'use asm';
// --------------------------------------------------------------------------------------------
typeof CeL === 'function' && CeL.run({
// module name
name : 'data',
require : 'data.code.compatibility.|data.native.to_fixed',
// 設定不匯出的子函式。
// no_extend : '*',
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
code : module_code
});
function module_code(library_namespace) {
// requiring
var to_fixed = this.r('to_fixed'),
/** {Number}未發現之index。 const: 基本上與程式碼設計合一,僅表示名義,不可更改。(=== -1) */
NOT_FOUND = ''.indexOf('_');
/**
* null module constructor
*
* @class data 處理的 functions
*/
var _// JSDT:_module_
= function() {
// null module constructor
};
/**
* for JSDT: 有 prototype 才會將之當作 Class
*/
_// JSDT:_module_
.prototype = {};
/**
* <code>
eval(uneval(o)): IE 沒有 uneval
http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
way1:
return YAHOO.lang.JSON.parse( YAHOO.lang.JSON.stringify( obj ) );
TODO:
1.
防止交叉參照版: try
var a=function(){this.a=1,this.b={a:this.a},this.a={b:this.b};},b=cloneObject(a);
.or.
var a={},b;
a.a={a:1};
a.b={a:a.a};
a.a={b:a.b};
b=cloneObject(a);
恐須改成
=new cloneObject();
2.
equal()
</code>
*/
/**
* clone object
*
* @param object
* @param {Boolean}deep
* deep / with trivial
* @return
*
* @see Object.clone() @ data.native
* @since 2008/7/19 11:13:10, 2012/10/16 22:01:12, 2014/5/30 19:35:59.
*/
function clone(object, deep) {
if (!object || typeof object !== 'object')
// assert: is 純量 / function
return object;
if (Array.isArray(object))
if (deep) {
var target = [];
object.forEach(function(o, index) {
target[index] = clone(o, deep);
});
return target;
} else
// Array.clone: data.native.clone_Array()
return Array.clone(object);
var key = ('clone' in object)
// test 物件自帶的 clone().
&& typeof object.clone === 'function';
if (key)
// object.clone(deep);
return object.clone();
key = library_namespace.is_type(object);
if (key === 'Date')
return new Date(object.getTime());
if (key === 'RegExp')
// new object.constructor(object)
return new RegExp(object);
var value, target = {};
for (key in object)
// 不加入非本 instance為 prototype 的東西。
if (Object.hasOwn(object, key)) {
value = object[key];
// TODO: 預防 loop, 防止交叉參照/循環參照。
target[key] = deep ? clone(value, deep) : value;
}
return target;
}
_// JSDT:_module_
.clone = clone;
// merge `new_data` to `old_data`, and return merged old_data
// merge 時,各屬性值以 `old_data` 為基礎,`new_data` 後設定者為準。
// Will modify old_data!
function deep_merge_object(old_data, options) {
var new_data;
if (Array.isArray(old_data)) {
// deep_merge_object([old_data, new_data, newer_data, ...,
// latest data ], options);
old_data.forEach(function(data, index) {
if (index === 0) {
old_data = data;
} else if (index === this.length - 1) {
new_data = data;
} else {
old_data = deep_merge_object([ old_data, data ], options);
}
});
} else {
// deep_merge_object(old_data, new_data);
new_data = options;
}
// ----------------------------
if (typeof old_data !== 'object' || old_data === null || !new_data) {
return new_data || old_data;
}
// ----------------------------
function merge_property_of_object(sub_new_data, sub_old_data) {
for ( var property in sub_new_data) {
// 將 property in sub_new_data 設定至
// old_value=sub_old_data[property];
merge_property(property, sub_new_data, sub_old_data);
}
return sub_old_data;
}
// 以 sub_old_data[property] 為基礎,將 sub_new_data[property] merge/overwrite
// 到 sub_old_data[property]
// 最終指定 sub_new_data[property] = old_value;
function merge_property(property, sub_new_data, sub_old_data) {
// assert: property in sub_new_data
var new_value = sub_new_data[property];
// assert: typeof old_value === 'object'
if (typeof new_value !== 'object' || !(property in sub_old_data)) {
// using new_value, overwrite old value
sub_old_data[property] = new_value;
return;
}
// assert: property in sub_old_data
var old_value = sub_old_data[property];
if (Array.isArray(new_value)) {
if (Array.isArray(old_value)) {
// 對於 {Object}old_value 先複製到 `old_value`
Object.keys(new_value).forEach(
// merge 像 new_value.a=1
function(sub_property) {
if (!library_namespace.is_digits(sub_property)) {
merge_property(sub_property, new_value, old_value);
}
});
old_value.append(new_value);
} else if (typeof old_value === 'object') {
// assert: library_namespace.is_Object(old_value)
merge_property_of_object(new_value, old_value);
} else {
// new_value.push(old_value);
sub_old_data[property] = new_value;
}
return;
}
// assert: library_namespace.is_Object(old_value) &&
// library_namespace.is_Object(new_value)
if (typeof old_value !== 'object') {
// 考慮 new_value 與 old_value 型態不同的情況。
sub_old_data[property] = new_value;
} else {
merge_property_of_object(new_value, old_value);
}
}
// assert: library_namespace.is_Object(old_data)
return merge_property_of_object(new_data, old_data);
}
_.deep_merge_object = deep_merge_object;
/**
* get the quote index of specified string.<br />
* 輸入('"','dh"fdgfg')得到2:指向"的位置.
*
* @param {String}string
* @param {String}quote
* ['"/][/]可能不太適用,除非將/[/]/→/[\/]/
* @returns
* @since 2004/5/5
*/
function index_of_quote(string, quote) {
var i, l = 0, m;
if (!quote)
quote = '"';
while ((i = string.indexOf(quote, l)) > 0
&& string.charAt(i - 1) === '\\') {
m = string.slice(l, i - 2).match(/(\\+)$/);
if (m && m[1].length % 2)
break;
else
l = i + 1;
}
return i;
}
/**
* <code>
{var a=[],b,t='',i;a[20]=4,a[12]=8,a[27]=4,a[29]=4,a[5]=6,a.e=60,a.d=17,a.c=1;alert(a);b=sortValue(a);alert(a+'\n'+b);for(i in b)t+='\n'+b[i]+' '+a[b[i]];alert(t);}
</code>
*/
// 依值排出key array…起碼到現在我還看不出此函數有啥大功用。
// array,否則會出現error! mode=1:相同value的以','合併,mode=2:相同value的以array填入
function sortValue(a, mode) {
var s = [], r = [], i, j, b, k = [];
// 使用(i in n)的方法僅有數字的i會自動排序這樣雖不必用sort(),但數字亦會轉成字串。
for (i in a)
if ((b = isNaN(i) ? i : parseFloat(i)),
//
typeof s[j = isNaN(j = a[i]) ? j : parseFloat(j)] === 'undefined')
k.push(j), s[j] = b;
else if (typeof s[j] === 'object')
s[j].push(b);
else
s[j] = [ s[j], b ];
// 注意sort 方法會在原地排序 Array 物件。
for (i = 0, k.sort(library_namespace.ascending); i < k.length; i++)
if (typeof (b = s[k[i]]) === 'object')
if (mode === 1)
// b.join(',')與''+b效能相同
r.push(b.join(','));
else if (mode === 2)
r.push(b);
else
for (j in b)
r.push(b[j]);
else
r.push(b);
return r;
}
/**
* <code>
2005/7/18 21:26
依照所要求的index(sortByIndex_I)對array排序。
sortByIndex_Datatype表某index為數字/字串或function
先設定sortByIndex_I,sortByIndex_Datatype再使用array.sort(sortByIndex);
example:
var array=[
'123 avcf 334',
'131 hj 562',
'657 gfhj 435',
'131 ajy 52',
'345 fds 562',
'52 gh 435',
];
sortByIndex_I=[0,1],sortByIndex_Datatype={0:1,2:1};
for(i in array)array[i]=array[i].split(' ');
array.sort(sortByIndex);
alert(array.join('\n'));
</code>
*/
var sortByIndex_I, sortByIndex_Datatype;
function sortByIndex(a, b) {
// alert(a+'\n'+b);
for (var i = 0, n; i < sortByIndex_I.length; i++)
if (sortByIndex_Datatype[n = sortByIndex_I[i]]) {
if (typeof sortByIndex_Datatype[n] === 'function') {
if (n = sortByIndex_Datatype[n](a[n], b[n]))
return n;
} else if (n = a[n] - b[n])
return n;
} else if (a[n] != b[n])
return a[n] > b[n] ? 1 : -1;
return 0;
}
/**
* <code>
2005/7/18 21:26
依照所要求的 index 對 array 排序,傳回排序後的 index array。
**假如設定了 separatorarray 的元素會先被 separator 分割!
example:
var array=[
'123 avcf 334',
'131 hj 562',
'657 gfhj 435',
'131 ajy 52',
'345 fds 562',
'52 gh 435',
];
alert(getIndexSortByIndex(array,' ',[0,1],[0,2]));
alert(array.join('\n')); // 已被 separator 分割!
</code>
*/
function getIndexSortByIndex(array, separator, indexArray, isNumberIndex) {
// 判定與事前準備(設定sortByIndex_I,sortByIndex_Datatype)
if (typeof indexArray === 'number')
sortByIndex_I = [ indexArray ];
else if (typeof indexArray !== 'object'
|| indexArray.constructor !== Array)
sortByIndex_I = [ 0 ];
else
sortByIndex_I = indexArray;
var i, sortByIndex_A = [];
sortByIndex_Datatype = Object.create(null);
if (typeof isNumberIndex === 'object') {
if (isNumberIndex.constructor === Array) {
sortByIndex_Datatype = Object.create(null);
for (i = 0; i < isNumberIndex.length; i++)
sortByIndex_Datatype[isNumberIndex[i]] = 1;
} else
sortByIndex_Datatype = isNumberIndex;
for (i in sortByIndex_Datatype)
if (isNaN(sortByIndex_Datatype[i])
|| parseInt(sortByIndex_Datatype[i]) !== sortByIndex_Datatype[i])
delete sortByIndex_Datatype[i];
}
if (typeof array !== 'object')
return;
// main work: 可以不用重造 array 資料的話..
for (i in array) {
if (separator)
array[i] = array[i].split(separator);
sortByIndex_A.push(i);
}
sortByIndex_A.sort(function(a, b) {
return sortByIndex(array[a], array[b]);
});
/**
* <code>
for: 重造array資料
var getIndexSortByIndexArray=array;
for(i in getIndexSortByIndexArray){
if(separator)getIndexSortByIndexArray[i]=getIndexSortByIndexArray[i].split(separator);
sortByIndex_A.push(i);
}
sortByIndex_A.sort(function (a,b){return sortByIndex(getIndexSortByIndexArray[a],getIndexSortByIndexArray[b]);});
</code>
*/
return sortByIndex_A;
}
/**
* <code>
simpleWrite('char_frequency report3.txt',char_frequency(simpleRead('function.js')+simpleRead('accounts.js')));
{var t=reduceCode(simpleRead('function.js')+simpleRead('accounts.js'));simpleWrite('char_frequency source.js',t),simpleWrite('char_frequency report.txt',char_frequency(t));} // 所費時間:十數秒(…太扯了吧!)
</code>
*/
_// JSDT:_module_
.
/**
* 測出各字元的出現率。 普通使用字元@0-1279-10,13,32-126reduce後常用9,32-95,97-125
*
* @param {String}
* text 文檔
* @return
* @_memberOf _module_
*/
char_frequency = function char_frequency(text) {
var i, a, c = [], d, t = '' + text, l = t.length, used = '', unused = '', u1 = -1, u2 = u1;
for (i = 0; i < l; i++)
if (c[a = t.charCodeAt(i)])
c[a]++;
else
c[a] = 1;
for (i = u1; i < 256; i++)
if (c[i]) {
if (u2 + 1 === i)
used += ',' + i, unused += (u2 < 0 ? '' : '-' + u2);
u1 = i;
} else {
if (u1 + 1 === i)
unused += ',' + i, used += (u1 < 0 ? '' : '-' + u1);
u2 = i;
}
// 若是reduceCode()的程式通常在120項左右。
for (i = 0, t = 'used:' + used.substr(1) + '\nunused:'
+ unused.substr(1) + '\n', d = sortValue(c, 2).reverse(); i < d.length; i++) {
t += NewLine
+ (a = d[i])
+ '['
+ fromCharCode(a).replace(/\0/g, '\\0').replace(/\r/g,
'\\r').replace(/\n/g, '\\n').replace(/\t/g, '\\t')
+ ']' + ': ' + (a = c[typeof a === 'object' ? a[0] : a])
+ ' ' + (100 * a / l);
// .5%以上者←選購
// if(200*v<l)break;
}
alert(t);
return t;
};
/**
* <code>
flag:
(flag&1)==0 HTML tag, 表情符號等不算一個字
(flag&1)==1 將 HTML tag 全部消掉
(flag&2)==1 連表情符號等也算一個字
可讀性/適讀性
http://en.wikipedia.org/wiki/Flesch-Kincaid_Readability_Test
http://en.wikipedia.org/wiki/Gunning_fog_index
Gunning-Fog Index簡單的來說就是幾年的學校教育才看的懂你的文章數字越低代表越容易閱讀若是高於17那表示你的文章太難囉需要研究生才看的懂我是6.08所以要受過6.08年的學校教育就看的懂囉。
Flesch Reading Ease這個指數的分數越高表示越容易了解一般標準的文件大約介於60~70分之間。
Flesch-Kincaid grade level和Gunning-Fog Index相似分數越低可讀性越高越容易使閱讀者了解至於此指數和Gunning-Fog Index有何不同網站上有列出計算的演算法有興趣的人可以比較比較。
DO.normalize(): 合併所有child成一String, may crash IE6 Win! http://www.quirksmode.org/dom/tests/splittext.html
</code>
*/
_// JSDT:_module_
.
/**
* 計算字數 count words. word_count
*
* @param {String}
* text 文檔
* @param {Number}
* flag 文檔格式/處理方法
*
* @return {Number} 字數
*
* @see https://zh.wikipedia.org/wiki/User:%E5%B0%8F%E8%BA%8D/Wordcount.js
*
* @_memberOf _module_
*/
count_word = function count_word(text, flag) {
var is_HTML = flag & 1;
// is HTML object
if (typeof text === 'object')
if (text.innerText)
text = text.innerText, is_HTML = false;
else if (text.innerHTML)
text = text.innerHTML, is_HTML = true;
if (typeof text !== 'string')
return 0;
// 和perl不同JScript常抓不到(.*?)之後還接特定字串的東西大概因為沒有s。(.*?)得改作([\s\S]*?)
// 或者該加/img
if (is_HTML)
text = text.replace(/<!--([\s\S]*?)-->/g, '').replace(
/<[\s\n]*\/?[\s\n]*[a-z][^<>]*>/gi, '');
if (flag & 2)
text = text.replace(
// 連表情符號或 '~。),' / 破折號 '——' / 刪節號 '……' 等標點符號也算一個字
/[\+\-*\\\/?!,;.<>{}\[\]@#$%^&_|"'~`—…、,;。!?:()()「」『』“”‘’]{2,}/g,
';');
return text
// 去掉注解用的括弧、書名號、專名號、印刷符號等
.replace(/[()()《》〈〉*#]+/g, '')
// 將數字改成單一字母。
.replace(/\d*\.?\d+([^.]|$)/g, '0$1')
/**
* 將整組物理量值加計量單位略縮成單一字母。<br />
* The general rule of the International Bureau of Weights and Measures
* (BIPM) is that the numerical value always precedes the unit, and a
* space is always used to separate the unit from the number, e.g., "23
* °C" (not "23°C" or "23° C").
*
* @see <a href="http://en.wikipedia.org/wiki/ISO_31-0#Expressions"
* accessdate="2012/7/28 0:42">ISO 31-0</a>, <a
* href="http://lamar.colostate.edu/~hillger/faq.html#spacing"
* accessdate="2012/7/28 0:42">FAQ: Frequently Asked Questions
* about the metric system</a>.
*/
.replace(/\d+\s*[a-zA-Z°]+(\s*\/\s*(\d+\s*)?[a-zA-Z°]+)?/g, '0')
// 長度過長時極耗時間。e.g., ...\d{500000}...
// .replace(/\d*\.?\d+\s*[a-zA-Z°]+(\s*\/\s*(\d*\.?\d+\s*)?[a-zA-Z°]+)?/g,'0')
// https://en.wikipedia.org/wiki/Punctuation_of_English
// Do not count punctuations of English.
.replace(/[,;:.?!\-"'()⟨⟩«»\[\]{}<>$%#@~`^&*\\\/+=|]+/g, '')
// 將英文、數字、單位等改成單一字母。[.]: 縮寫。[\/]: m/s 之類。
// a's: 1
// http://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF
// http://zh.wikipedia.org/wiki/Unicode%E5%AD%97%E7%AC%A6%E5%88%97%E8%A1%A8
.replace(/[\wÀ-ÖØ-öø-ȳ]{2,}/g, 'w')
// date/time or number
.replace(/[\d:+\-\.\/,]{2,}/g, '0')
// 再去掉*全部*空白
.replace(/[\s\n]+/g, '')
// return text.length;
.length;
};
_// JSDT:_module_
.
/**
* 運算式值的二進位表示法
* 已最佳化:5.82s/100000次dec_to_bin(20,8)@300(?)MHz,2.63s/100000次dec_to_bin(20)@300(?)MHz
*
* @param {Number}
* number number
* @param places
* places,字元數,使用前置0來填補回覆值
* @return
* @example<code>
{var d=new Date,i,b;for(i=0;i<100000;i++)b=dec_to_bin(20);alert(gDate(new Date-d));}
</code>
* @_memberOf _module_
*/
dec_to_bin = function dec_to_bin(number, places) {
if (places && number + 1 < (1 << places)) {
var h = '', b = number.toString(2), i = b.length;
for (; i < places; i++)
h += '0';
return h + b;
}
// native code 還是最快!
return number.toString(2);
if (false) {
// 上兩代:慢
// 不用'1:0',型別轉換比較慢.不用i多一個變數會慢很多
var b = '', c = 1;
for (p = p && n < (p = 1 << p) ? p : n + 1; c < p; c <<= 1)
b = (c & n ? '1' : '0') + b;
return b;
// 上一代:慢
if (p && n + 1 < (1 << p)) {
var h = '', c = 1, b = n.toString(2);
while (c <= n)
c <<= 1;
while (c < p)
c <<= 1, h += '0';
return h + (n ? n.toString(2) : '');
}
}
};
/**
* <code>
value (Array)=value,(Object)value=
[null]=value 累加=value
value=[null] value=''
type: value type ['=','][int|float|_num_]
: 前段
以[']或["]作分隔重定義指定號[=]與分隔號[,]
: 後段
數字表累加
'int'表整數int累加1
'float'表示浮點數float累加.1 bug:應該用.to_fixed()
不輸入或非數字表示string
mode
_.set_Object_value.F.object
_.set_Object_value.F.array(10進位/當做數字)
number: key部分之base(10進位16進位等)
example:
set_Object_value('UTCDay','Sun,Mon,Tue,Wed,Thu,Fri,Sat','int'); // 自動從0開始設UTCDay.Tue=2
set_Object_value('UTCDay','Sun,Mon,Tue,Wed,Thu,Fri,Sat'); // UTCDay.Sun=UTCDay.Fri=''
set_Object_value('add','a=3,b,c,d',2); // 累加2。add.b=5
set_Object_value('add','a,b,c,d',1,_.set_Object_value.F.array); // add[2]='c'
set_Object_value('add','4=a,b,c,d',2,_.set_Object_value.F.array); // 累加2。add[8]='c'
</code>
*/
_// JSDT:_module_
.
/**
* 設定object之值輸入item=[value][,item=[value]..]。<br />
* value未設定會自動累加。<br />
* 使用前不必需先宣告…起碼在現在的JS版本中
*
* @param obj
* object name that need to operate at
* @param value
* valueto set
* @param type
* 累加 / value type
* @param mode
* mode / value type
* @return
* @_memberOf _module_
*/
set_Object_value = function set_Object_value(obj, value, type, mode) {
if (!value || typeof obj !== 'string')
return;
var a, b, i = 0, p = '=', sp = ',', e = "if(typeof " + obj
+ "!='object')" + obj + "=new " + (mode ?
// "[]":"{}"
// Array之另一種表示法[value1,value2,..],
// Object之另一種表示法{key1:value1,key2:value2,..}
"Array" : "Object") + ";",
// l: item, n: value to 累加
n, Tint = false, cmC = '\\u002c', eqC = '\\u003d';
if (type) {
if (typeof a === 'string') {
a = type.charAt(0);
if (a === '"' || a === "'") {
a = type.split(a);
p = a[1], sp = a[2], type = a[3];
}
}
if (type === 'int')
type = 1, Tint = true;
else if (type === 'float')
type = .1;
else if (isNaN(type))
type = 0;
else if (type === parseInt(type))
type = parseInt(type), Tint = true;
else
// t被設成累加數
type = parseFloat(type);
}
// else t = 1;
if (typeof value === 'string')
value = value.split(sp);
// escape regex characters from jQuery
cmC = new RegExp(cmC.replace(
/([\.\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1"), 'g'),
eqC = new RegExp(eqC.replace(
/([\.\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1"),
'g');
if (type)
// n: 現在count到..
n = -type;
for (; i < value.length; i++) {
if (value[i].indexOf(p) === NOT_FOUND)
// if(v[i].indexOf(p)==NOT_FOUND&&m)v[i]=p+v[i];
value[i] = mode ? p + value[i] : value[i] + p;
if (mode && value[i] === p) {
n += type;
continue;
}
a = value[i].split(p);
if (!mode && !a[0])
// 去掉不合理的(Array可能有NaN index所以不設條件。)
continue;
a[0] = a[0].replace(cmC, ',').replace(eqC, '='), a[1] = a[1]
.replace(cmC, ',').replace(eqC, '=');
if (type)
if (mode) {
if (!a[0])
a[0] = (n += type);
else if (!isNaN(b = mode > 0 ? parseInt(a[0], mode) : a[0]))
n = Tint ? (a[0] = parseInt(b)) : parseFloat(b);
} else if (!a[1])
a[1] = (n += type);
else if (!isNaN(a[1]))
n = Tint ? parseInt(a[1]) : parseFloat(a[1]);
if (!type || Tint && isNaN(b = parseInt(a[1]))
|| isNaN(b = parseFloat(a[1])))
b = a[1];
a = a[0];
e += obj + '['
+ (!type || isNaN(a) ? library_namespace.dQuote(a) : a)
+ ']='
+ (!type || isNaN(b) ? library_namespace.dQuote(b) : b)
+ ';';
}
try {
// if(o=='kk')alert(e.slice(0,500));
// 因為沒想到其他方法可存取Global的object只好使用eval...
// 可以試試obj=set_Object_value(0,..){this=new Aaaray/Object}
return library_namespace.eval_code(e);
} catch (e) {
library_namespace.error('Error @ ' + obj);
library_namespace.error(e);
return;
}
};
_.set_Object_value.F = {
// object is default
'object' : 0,
'array' : -1
};
_// JSDT:_module_
.
/**
* 將字串組分作 Object
*
* @param {String}
* value_set 字串組, e.g., 'a=12,b=34'
* @param assignment_char
* char to assign values, e.g., '='
* @param end_char
* end char of assignment
* @return
* @since 2006/9/6 20:55, 2010/4/12 23:06:04
* @_memberOf _module_
*/
split_String_to_Object = function split_String_to_Object(value_set,
assignment_char, end_char) {
if (typeof value_set !== 'string' || !value_set)
return {};
value_set = value_set.split(end_char || /[,;]/);
if (!assignment_char)
assignment_char = /[=:]/;
var a, o = {}, _e = 0, l = value_set.length;
for (; _e < l; _e++) {
// http://msdn.microsoft.com/library/en-us/jscript7/html/jsmthsplit.asp
a = value_set[_e].split(assignment_char, 2);
if (false)
library_namespace.debug(value_set[_e] + '\n' + a[0] + ' '
+ a[1], 2);
if (a[0] !== '')
o[a[0]] = a[1];
}
return o;
};
/**
* <code>
2003/10/1 15:46
比較string:m,n從起頭開始相同字元數
return null: 格式錯誤,-1: !m||!n
若一開始就不同0
TODO:
test starting with
2009/2/7 7:51:58
看來測試 string 的包含,以 .indexOf() 最快。
即使是比較 s.length 為極小常數的情況亦復如此
下面是快到慢:
// long, short
var contain_substring = [ function(l, s) {
var a = 0 == l.indexOf(s);
return a;
}, function(l, s) {
return 0 == l.indexOf(s);
}, function(l, s) {
return s == l.slice(0, s.length);
}, function(l, s) {
return l.match(s);
}, function(l, s) {
for (var i = 0; i < s.length; i++)
if (s.charAt(i) != l.charAt(i))
return 0;
return 1;
} ];
function test_contain_substring() {
for (var i = 0; i < contain_substring.length; i++) {
var t = new Date;
for (var j = 0; j < 50000; j++) {
contain_substring[i]('sdfgjk;sh*dn\\fj;kgsamnd nwgu!eoh;nfgsj;g',
'sdfgjk;sh*dn\\fj;kgsamnd nwgu!');
contain_substring[i]('sdbf6a89* /23hsauru', 'sdbf6a89* /23');
}
sl(i + ': ' + (new Date - t));
}
}
// 極小常數的情況:
// long,short
var contain_substring = [ function(l, s) {
var a = 0 == l.indexOf(s);
return a;
}, function(l, s) {
return 0 == l.indexOf(s);
}, function(l, s) {
return s == l.slice(0, 1);
}, function(l, s) {
return s.charAt(0) == l.charAt(0);
}, function(l, s) {
return l.match(/^\//);
} ];
function test_contain_substring() {
for (var i = 0; i < contain_substring.length; i++) {
var t = new Date;
for (var j = 0; j < 50000; j++) {
contain_substring[i]('a:\\sdfg.dfg\\dsfg\\dsfg', '/');
contain_substring[i]('/dsfg/adfg/sadfsdf', '/');
}
sl(i + ': ' + (new Date - t));
}
}
</code>
*/
_// JSDT:_module_
.
/**
* test if 2 string is at the same length.<br />
* strcmp: String.prototype.localeCompare
*
* @param s1
* string 1
* @param s2
* string 2
* @return
* @_memberOf _module_
*/
same_length = function same_length(s1, s2) {
if (typeof m !== 'string' || typeof n !== 'string')
return;
if (!s1 || !s2)
return 0;
var i = s1.length, b = 0, s = s2.length;
if (i < s) {
if (
// m === n.slice(0, i = m.length)
0 === s2.indexOf(s1))
return i;
} else if (
// s2==s1.slice(0,i=s2.length)
i = s, 0 === s1.indexOf(s2))
return i;
// sl('*same_length: start length: '+i);
while ((i = (i + 1) >> 1) > 1 && (s = s2.substr(b, i))) {
if (false)
sl('same_length: ' + i + ',' + b + '; [' + m.substr(b) + '], ['
+ s + '] of [' + n + ']');
if (s1.indexOf(s, b) === b)
b += i;
if (false) {
sl('*same_length: ' + i + ',' + b + '; [' + m.charAt(b)
+ '], [' + n.charAt(b) + '] of [' + n + ']');
var s_l = i && m.charAt(b) == n.charAt(b) ? b + 1 : b;
sl('*same_length: ' + s_l + ':' + m.slice(0, s_l) + ',<em>'
+ m.slice(s_l) + '</em>; ' + n.slice(0, s_l) + ',<em>'
+ n.slice(s_l) + '</em>');
}
}
return i && s1.charAt(b) === s2.charAt(b) ? b + 1 : b;
};
/**
* 去除指定字串中重複字元。 remove duplicate characters in a string.
*
* @param {String}string
* 指定字串。
*
* @returns 去除重複字元後之字串。
*/
function remove_duplicate_characters(string) {
string = String(string);
if (!string)
return '';
string = string.split('');
var i = 0, length = string.length, code_array = [], code;
for (; i < length; i++) {
code = string[i].charCodeAt(0);
if (code in code_array) {
string[i] = '';
} else {
code_array[code] = 1;
}
}
return string.join('');
}
_// JSDT:_module_
.remove_duplicate_characters = remove_duplicate_characters;
// -----------------------------------------------------------------------------
/**
* 產生將數字轉為 K, M, G 等數量級(order of magnitude)表示方式的轉換器。<br />
* 原理:先設好各 symbol 使用之下限,比完大小後使用此 symbol。
*
* TODO: full test
*
* @param {Array}symbol
* array of {String}symbol
* @param {Integer}[base]
* define what power
* @param {Integer}[index_of_1]
* 純量的 index。no prefix. 這之前的算做小數。
* @param {String}intervening
* intervening string, 將插入於數字與 symbol 間。e.g., &nbsp;
* @return {Function} 改變表示方式之轉換器。
* @return {undefined} 輸入有問題。
* @requires to_fixed
* @see <a href="http://www.merlyn.demon.co.uk/js-maths.htm#DTS"
* accessdate="2012/8/18 12:17">JRS - JavaScript Maths - J R Stockton</a>
* @_memberOf _module_
*/
function set_order_prefix(symbol, base, index_of_1, intervening) {
if (!Array.isArray(symbol) || !symbol.length)
return;
if (!base)
base = 10;
if (!index_of_1) {
index_of_1 = 0;
if (symbol[0])
symbol.unshift('');
}
var magnitude = 1, length = symbol.length, value = new Array(length), index = index_of_1;
// 先設定好各數量級(order of magnitude)之大小。
while (++index < length) {
magnitude *= base;
value[index] = magnitude;
}
if (index_of_1) {
index = index_of_1;
magnitude = 1;
while (index--) {
magnitude /= base;
value[index] = magnitude;
}
}
value[index_of_1] = 1;
if (intervening) {
for (index = 0; index < length; index++) {
symbol[index] = intervening + symbol[index];
}
}
library_namespace.debug('magnitude array of base ' + base + ': ['
+ value + ']', 1, 'set_order_prefix');
library_namespace.debug('prefixes of base ' + base + ': [' + symbol
+ ']', 1, 'set_order_prefix');
// cache 引入: symbol, value, length.
return (
/**
* 將數字轉為 K, M, G 等數量級(order of magnitude)表示方式。
*
* @param {Number}number
* 數字純量
* @param {Number}digits
* to fixed digit
* @type {String}
* @return {String} 指定數量級(order of magnitude)表示方式
* @requires to_fixed
*/
function(number, digits) {
if (typeof number === 'string')
number = parseFloat(number.replace(/[, ]/g, ''));
if (!number || isNaN(number))
return 0;
var l = 0, r = length, i;
// 直接用比的。 inline binary search.
// while (l < (i = Math.floor((l + r) / 2))) {
while (l < (i = (l + r) >> 1)) {
library_namespace.debug('compare: ' + number + ', [' + i + ']'
+ value[i], 3, 'set_order_prefix');
if (number < value[i]) {
r = i;
} else {
l = i;
}
}
library_namespace.debug('index: [' + i + '] ' + value[i] + ', '
+ symbol[i], 2, 'set_order_prefix');
l = number / value[i];
return to_fixed.call(l, isNaN(digits) || digits < 0 ? (r = Math
.floor(l)) < 10 ? 2 : r < 100 ? 1 : 0 : digits)
+ symbol[i];
});
}
/**
* 將數字轉為 K, M, G 等 metric prefix / SI prefix 表示方式,例如 6458 轉成 6.31 K。
*
* @example <code>
CeL.to_1000_prefix(12343454345);
CeL.to_1000_prefix('12,343,454,345');
</code>
*
* @returns
* @see <a href="http://en.wikipedia.org/wiki/Metric_prefix"
* accessdate="2012/8/18 12:9">Metric prefix</a>, <a
* href="http://en.wikipedia.org/wiki/International_System_of_Units"
* accessdate="2012/8/18 12:11">International System of Units</a>, <a
* href="http://www.bipm.org/en/si/si_brochure/chapter3/prefixes.html"
* accessdate="2012/8/18 12:10">BIPM - SI prefixes</a>, <a
* href="http://bmanolov.free.fr/numbers_names.php"
* accessdate="2012/8/18 12:19">Names of LARGE and small Numbers</a>
*/
function to_1000_prefix() {
var s = 'yzafpnμm kMGTPEZY', i = s.indexOf(' ');
s = s.split('');
s[i] = '';
return set_order_prefix(s, 1000, i, ' ');
}
/**
* 將數字轉為 Ki, Mi, Gi 等 binary prefix 表示方式,例如 1024 轉成 1Ki。
*
* @example <code>
CeL.to_1024_prefix(12343454345);
</code>
*
* @returns
* @see <a
* href="http://en.wikipedia.org/wiki/Binary_prefix#IEC_standard_prefixes"
* accessdate="2012/8/18 11:53">Binary prefix</a>
*/
function to_1024_prefix() {
return set_order_prefix(',Ki,Mi,Gi,Ti,Pi,Ei,Zi,Yi'.split(','), 1024, 0,
' ');
}
// 不可以 `byte` 為變數名: JsDoc 會失會失效。
function to_KiB(bytes, type, use_KB) {
var expression = use_KB ? library_namespace.to_1000_prefix
: library_namespace.to_1024_prefix, b = bytes + ' byte'
+ (bytes > 1 ? 's' : '');
expression = expression(bytes) + 'B';
if (type && type.toLowerCase() === 'html') {
expression = '<span title="' + b + '">' + expression + '</span>';
} else if (library_namespace.is_Object(type)) {
expression = {
span : expression,
title : b
};
} else if (type === '()') {
expression += ' (' + b + ')';
}
return expression;
}
function to_KB(bytes, type) {
return to_KiB(bytes, type, true);
}
// old alias: CeL.show_KiB(), CeL.show_KB()
_.to_KiB = to_KiB;
_.to_KB = to_KB;
// TODO: accept '300K' as 300 KiB
// 設定 lazy evaluation。
library_namespace.set_initializor(to_1000_prefix);
library_namespace.set_initializor(to_1024_prefix);
// -----------------------------------------------------------------------------
/**
* for IE3: mode=1:不取空字串<br />
* .split() appears from Internet Explorer 4.0
*
* @see <a
* href="http://msdn.microsoft.com/en-us/library/s4esdbwz%28v=VS.85%29.aspx"
* accessdate="2010/4/16 20:4">Version Information (Windows Scripting -
* JScript)</a>
*/
function StringToArray(s, mode) {
var a = [], last = 0, i;
while ((i = s.indexOf(sp, last)) !== NOT_FOUND) {
if (mode === 0 || last !== i)
a[a.length] = s.slice(last, i);
last = i + 1;
}
if (mode === 0 || last !== s.length)
a[a.length] = s.slice(last);
return a;
}
// for IE3: 去除s之空白,包括字與字之間的
function disposeSpace(s) {
if (!s)
return s;
var r = "", i, last;
while ((i = s.indexOf(' ', last)) !== NOT_FOUND)
r += s.slice(last, i), last = i + 1;
r += s.slice(last);
return r;
}
// for IE3: 以label,mode:m置換s,先找到先贏
// 輸入t['$k']=..會有問題需用t['\\$k']=..
function changeV(s, l, m) {
var i, r, re, t; // var I='';
if (!m)
m = 'g';
if (s && (t = l ? l : label))
for (i in t) {
// I+=', '+i+'='+t[i];
re = new RegExp(i, m);
// r=s.replace(re,t[i]);s=r;
s = s.replace(re, t[i]);
}
// pLog(I.substr(2));
// pLog('changeV:'+s);
return s;
}
/**
* <code>
// 以label置換s,先找到先贏
function changeV(s) {
for (var i, j = 0; j < labelN.length; j++)
if ((i = s.indexOf(labelN[j])) != NOT_FOUND)
s = s.slice(0, i) + labelV[j] + s.slice(i + labelN[j].length)
, j = 0; // search again from beginning
return s;
}
</code>
*/
_// JSDT:_module_
.get_Object_value = function(o) {
// if (Array.isArray(o)) return o;
// if (!library_namespace.is_Object(o)) return;
var i, l = [];
for (i in o)
l.push(o[i]);
return l;
};
_// JSDT:_module_
.
/**
* 互換/reverse key/value pairs.
*
* @example <code>
swap_key_value({A:1,B:2,s:4,t:[]}, [], /^[A-Z_\-\d]+$/) === [,'A','B']
</code>
* @param {Object|object}pairs
* key/value pairs
* @param {Object|Array}[base]
* 把互換結果放在 base
* @param {RegExp}[key_filter]
* 僅放入符合的 key
* @returns
*/
swap_key_value = function(pairs, base, key_filter) {
if (!base)
base = {};
var k;
if (library_namespace.is_type(key_filter, 'RegExp')) {
for (k in pairs)
if (key_filter.test(k))
base[pairs[k]] = k;
} else
for (k in pairs)
base[pairs[k]] = k;
return base;
};
if (library_namespace.dependency_chain)
_.dependency_chain = library_namespace.dependency_chain;
/**
* new_Array=[,,]: 可以使用 Array 常值中的空白元素來建立零星稀疏的陣列。
*/
// ---------------------------------------------------------------------//
// UTF-8 char and bytes.
/**
* 計算指定 UTF-8 char code 之 bytes。
*
* TODO:<br />
* 加快速度。
*
* @param {Number}code
* 指定之 UTF-8 char code。
* @returns {Number} 指定 UTF-8 char code 之 bytes。
* @see https://en.wikipedia.org/wiki/UTF-8#Description
*/
function bytes_of_UTF8_char_code(code) {
return code < 0x0080 ? 1 : code < 0x0800 ? 2 : code < 0x10000 ? 3
: code < 0x200000 ? 4 : code < 0x4000000 ? 5
: code < 0x80000000 ? 6 : 7;
}
/**
* 計算指定 UTF-8 text 之 bytes。
*
* TODO:<br />
* use Buffer.byteLength
*
* @param {String}text
* 指定之 UTF-8 text。
* @returns {Number} 指定 UTF-8 text 之 bytes。
*/
function byte_count_of_UTF8(text) {
var i = 0, length = text.length, bytes = 0;
for (; i < length; i++)
bytes += bytes_of_UTF8_char_code(text.charCodeAt(i));
return bytes;
}
/**
* 將 UTF-8 text 截成指定 byte 長度。
*
* @param {String}text
* 指定之 UTF-8 text。
* @param {Number}byte_length
* 指定之 byte 長度。
* @returns {String} UTF-8 text, length <= byte_length.
*/
function cut_UTF8_by_bytes(text, byte_length) {
var i = 0, length = text.length;
for (; byte_length > 0 && i < length; i++) {
byte_length -= bytes_of_UTF8_char_code(text.charCodeAt(i));
if (byte_length < 0)
i--;
}
return i === length ? text : text.slice(0, i);
}
_.bytes_of_char_code = bytes_of_UTF8_char_code;
_.byte_count = byte_count_of_UTF8;
_.cut_by_bytes = cut_UTF8_by_bytes;
// ---------------------------------------------------------------------//
// for bencode & torrent file data.
/**
* [ key_1, value_1, key_2, value_2, key_3, value_3 ]<br /> →<br /> {
* key_1: value_1, key_2: value_2, key_3: value_3 }
*
* @param {Array}list
* list to convert
*
* @returns {Object} pair Object converted
* @since 2014/7/21 23:17:32
*/
function list_to_Object(list) {
var i = 0, length = list.length, pair = Object.create(null);
if (length % 2 !== 0)
library_namespace.warn('list_to_Object: The length (' + length
+ ') of list is not an even number!');
for (; i < length; i += 2) {
if (typeof list[i] !== 'string')
library_namespace.warn(
// Set key to non-string type. e.g., integer
'Set (' + (typeof list[i]) + ') [' + list[i] + '] as key.');
if (list[i] in pair)
library_namespace.warn('Duplicated key: [' + list[i] + ']');
library_namespace.debug('pair[' + list[i] + '] = [' + list[i + 1]
+ ']', 3);
pair[list[i]] = list[i + 1];
}
return pair;
}
/**
* parse bencode data
*
* @param {String}data
* bencode data
* @param {Object}[status]
* get the parse status
* @param {Boolean}[is_ASCII]
* 若設定為真,則當作 ASCII 處理。若設定為假,則當作 UTF-8 處理。
*
* @returns
*
* @see https://zh.wikipedia.org/wiki/Bencode
*
* @since 2014/7/21 23:17:32
*/
function parse_bencode(data, status, is_ASCII) {
function make_end() {
// assert: object_now === queue.pop()
if ((tmp = object_now) !== queue.pop()) {
library_namespace.error('Bad data structure!');
// assert: queue.length === 0
if (queue !== object_now)
// 回存。
queue.push(object_now);
} else {
if (tmp.d)
tmp = list_to_Object(tmp);
// assert: queue.length > 0
(object_now = queue.at(-1)).push(tmp);
}
}
// 盡可能不動到 data因為 data 可能很大。
var index = 0, tmp, queue = [],
// 即使在 data 有缺陷的情況下,也盡可能解析出資料。
// 因此先將 data 設定成 list。
object_now = queue,
// 為了多行程,因此這些 pattern 應該放在函數內,不可為 global 為其他行程存取。
PATTERN_controller = /(.*?)([ldei\d])/g,
// 為了盡快 match所以盡可能選擇可能 match 的 pattern之後再來檢查是否相符。
PATTERN_integer = /(-?\d*)(\D)/g, PATTERN_string_length = /(\d*)(\D)/g;
for (;;) {
PATTERN_controller.lastIndex = index;
if (!(tmp = PATTERN_controller.exec(data))) {
if (index < data.length)
library_namespace.error('Last data skipped! ('
+ data.slice(index) + ')');
break;
}
if (tmp[1]) {
index += tmp[1].length;
// control char should be next char.
library_namespace.error('Some data skipped! (' + tmp[1] + ')');
}
switch (tmp[2]) {
case 'l':
// list 列表
case 'd':
// dictionary 關聯數組
++index;
queue.push(object_now = []);
if (tmp[2] === 'd')
object_now.d = true;
break;
case 'e':
// ending
++index;
make_end();
break;
case 'i':
// integer 整數
PATTERN_integer.lastIndex = ++index;
tmp = PATTERN_integer.exec(data);
if (tmp && tmp[2] === 'e') {
// 確定為 /i\d+e/
if (!tmp[1])
library_namespace
.error('No integer specified ("ie" instead of /i\d+e/)!');
else if (PATTERN_integer.lastIndex !== index
+ tmp[0].length)
library_namespace.error('Some integer data skipped! ('
+ data.slice(index, PATTERN_integer.lastIndex
- tmp[0].length) + ')');
object_now.push(parseInt(tmp[1]));
index = PATTERN_integer.lastIndex;
} else {
// fatal error
library_namespace.error('Bad integer format! Exit parse!');
index = data.length;
}
break;
default:
// assert: 接下來是 string (\d+:.+) 字串
PATTERN_string_length.lastIndex = index;
tmp = PATTERN_string_length.exec(data);
if (tmp && tmp[2] === ':') {
// 確定為 /\d+:/
if (!tmp[1] || !(tmp[1] | 0))
library_namespace.error('No string length specified! ('
+ tmp[1] + ')');
else if (PATTERN_string_length.lastIndex !== index
+ tmp[0].length)
library_namespace.error('Some string data skipped! ('
+ data.slice(index,
PATTERN_string_length.lastIndex
- tmp[0].length) + ')');
if ((index = PATTERN_string_length.lastIndex)
+ (tmp = tmp[1] | 0) > data.length)
library_namespace.error(
//
'The end of string is beyond the end of data! (ask '
// remaining
+ (index + tmp) + ' - data left ' + data.length
+ ' = lost ' + (index + tmp - data.length)
+ ')');
// tmp: length of string.
library_namespace.debug(index + '+' + tmp, 3);
if (is_ASCII) {
object_now.push(data.substr(index, tmp));
index += tmp;
} else {
// 對 UTF-8 (non-ASCII string) 特別處理:
// 此時因取得 Unicode所指定之 length >= 實際 length。
tmp = cut_UTF8_by_bytes(data.substr(index, tmp), tmp);
object_now.push(tmp);
index += tmp.length;
}
} else {
// fatal error
library_namespace.error('Bad string format! Exit parse!');
index = data.length;
}
}
}
if (queue.length > 1)
library_namespace.warn('Illegal data: 有錯誤或缺陷!');
while (queue.length > 1 && Array.isArray(queue.at(-1)))
make_end();
if (status)
if (queue.length !== 1)
status.error = true;
return queue.length === 1 ? queue[0] : queue;
}
/**
* parse torrent file data
*
* @example <code>
// @ JScript
CeL.run('data', function () {
// http://www.ubuntu.com/download/alternative-downloads
CeL.log(CeL.parse_torrent('http://releases.ubuntu.com/14.04/ubuntu-14.04-desktop-i386.iso.torrent', true));
});
* </code>
*
* @param {String}path
* torrent file path.
* @param {Boolean}name_only
* get the torrent name only.
*
* @returns {Object} torrent file data
* @since 2014/7/21 23:17:32
*/
function parse_torrent(path, name_only) {
// 注意:此方法不可跨 domain!
// JScript 下XMLHttpRequest 會將檔案當作 UTF-8 讀取。
var data = library_namespace.get_file(path);
var status = Object.create(null);
if (!data || data.charAt(0) !== 'd') {
library_namespace.error((data ? 'Illegal' : 'Cannot get')
+ ' torrent data of [' + path + ']!');
return;
}
library_namespace.debug(data, 4);
if (name_only) {
// a fast way to get torrent name.
var PATTERN_name = /4:name(\d{1,4}):/, matched = data
.match(PATTERN_name), index;
if (matched && (matched = matched[1] | 0) > 0) {
library_namespace.debug('[' + path + '] length: ' + matched, 3);
// fix for non-ASCII chars, it will be change to Unicode,
// and the real length <= length specified.
if (false) {
// assert: 'piece length' 恰好在 PATTERN_name 之後。
index = data.indexOf('12:piece lengthi')
- PATTERN_name.lastIndex;
return data.substr(PATTERN_name.lastIndex, index > 0 ? Math
.min(index, matched) : matched);
}
return cut_UTF8_by_bytes(data.substr(PATTERN_name.lastIndex,
matched), matched);
}
return;
}
data = parse_bencode(data, status);
return data;
}
_.list_to_Object = list_to_Object;
_.parse_bencode = parse_bencode;
_.parse_torrent = parse_torrent;
// ---------------------------------------------------------------------//
function is_natural(value) {
return value >= 1 && Math.floor(value) === value;
}
// is_non_negative
function is_natural_or_0(value) {
return value >= 0 && Math.floor(value) === value;
}
function is_integer(value) {
return Math.floor(value) === value;
}
import_options.filters = {
number : {
range : function in_range(value) {
return (typeof this[0] !== 'number' || this[0] <= value)
&& (typeof this[1] !== 'number' || value <= this[1]);
},
// 自然數 natural numbers *, +, >0, +
natural : is_natural,
'' : is_natural,
'natural+0' : is_natural_or_0,
// '0'
'+0' : is_natural_or_0,
// 整數
integer : is_integer,
'' : is_integer
},
string : {
IPv4 : /^[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}$/,
// RFC2822 :
// http://regexlib.com/DisplayPatterns.aspx
// /^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/,
email :
// http://www.regular-expressions.info/email.html
// /^[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+([a-z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b$/i,
/^[a-z0-9+_~-]+(\.[a-z0-9+_~-]+)*@([a-z\d]([a-z\d-]*[a-z\d])?\.)+([a-z]{2}|com|org|net)\b$/i,
// 十進位小數
decimal : /^[+\-]?(?:\d+|\d*\.\d+)$/,
// 數字
digits : library_namespace.is_digits
}
};
/**
* @inner
*/
function string_options_to_normalizer(string_normalizer) {
var normalizer = Object.create(null);
string_normalizer.split('|').forEach(function(type) {
var matched = type.match(/^([a-z]+):([\s\S]+)$/);
if (!matched) {
normalizer[type] = true;
return;
}
type = matched[1];
// condition
var _normalizer = matched[2];
if (_normalizer in import_options.filters[type]) {
_normalizer = import_options.filters[type][_normalizer];
} else if (type === 'number' && (matched = _normalizer.match(
// @see CeL.date.parse_period.PATTERN
// [ all, min, max ]
/([+\-]?\d+(?:\.\d+)?)?\s*[~-—─~〜﹣至]\s*([+\-]?\d+(?:\.\d+)?)?/))) {
_normalizer = import_options.filters[type]
// this: [ min, max ]
.range.bind([ matched[1] && +matched[1],
//
matched[2] && +matched[2] ]);
} else if (type === 'string') {
matched = _normalizer.match(library_namespace.PATTERN_RegExp);
if (matched) {
_normalizer = new RegExp(matched[1], matched[2]);
} else {
_normalizer = _normalizer.split(';');
}
} else {
library_namespace.warn('import_options: Invalid normalizer: '
//
+ _normalizer);
}
normalizer[type] = _normalizer;
});
return normalizer;
}
/**
* 將 options 裡面可使用之選項(依照 options_normalizer 之定義),篩選、正規化並提取至 target。
*
* @param {Object}options
* @param {Object|String|Function}options_normalizer
* options allowed
* @param {Object}[target]
* target options to modify
* @returns
*
* @see function verify_arg(key, value)
* @see function generate_argument_condition(condition) @ CeL.application.net.work_crawler.arguments
* @see _.default_verify_pattern @ CeL.interact.form.select_input
*/
function import_options(options, options_normalizer, target) {
options = library_namespace.setup_options(options);
if (!target) {
target = Object.create(null);
}
for ( var key in options) {
var value = options[key];
var normalizer = options_normalizer && options_normalizer[key];
if (typeof normalizer === 'string') {
// e.g., 'boolean|string:changed;multi_parts_changed'
normalizer = string_options_to_normalizer(normalizer);
// console.trace(normalizer);
}
if (typeof normalizer === 'object') {
var type = Array.isArray(value) ? 'Array'
//
: library_namespace.is_RegExp(value) ? 'RegExp'
//
: library_namespace.is_Date(value) ? 'Date' : null;
if (!type || !(type in normalizer)
&& !((type = type.toLowerCase()) in normalizer)) {
type = typeof value;
}
if (type in normalizer) {
normalizer = normalizer[type];
} else {
// invalid value type
continue;
}
}
if (normalizer === undefined && options_normalizer) {
// invalid key / parameter name
continue;
}
if (typeof normalizer === 'function') {
value = normalizer(value);
} else if (!fit_filter(normalizer, value)) {
// treat normalizer as filter
// invalid value
continue;
}
if (value !== import_options.INVALID
// && value !== undefined
) {
target[key] = value;
}
}
// console.trace(target);
return target;
}
import_options.INVALID = {
invalid_value : true
};
_.import_options = import_options;
/**
* validity value
*
* generate_filter: fit_filter.bind(null, filter)
*
* @param {Function|RegExp|Array}filter
* @param value
* value to test
*
* @returns value fits the filter
*
* @see function receive() @ CeL.application.net.wiki.page
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/text#pattern
*/
function fit_filter(filter, value) {
// if (filter === true) return true;
if (typeof filter === 'boolean' || filter === null
|| typeof filter === 'undefined')
return filter;
// 驗證 pattern
if (library_namespace.is_RegExp(filter))
return filter.test(value);
if (typeof filter === 'function')
return filter(value);
if (typeof filter === 'string') {
return filter === value;
// return filter.includes(value);
// return String(value).includes(filter);
}
// e.g., ['A','B','C']
if (Array.isArray(filter))
return filter.includes(value);
if (false && library_namespace.is_Object(filter))
return value in filter;
throw new TypeError('Invalid filter');
}
_.fit_filter = fit_filter;
// ---------------------------------------------------------------------//
return (_// JSDT:_module_
);
}