568 lines
19 KiB
JavaScript
568 lines
19 KiB
JavaScript
// 通用方法
|
|
import _filter from './filter';
|
|
import _map from './map';
|
|
import _pair from './pair';
|
|
|
|
var _mode = {}; // 模式数据
|
|
var _data = Object.assign({},_map); // 最终数据
|
|
|
|
// 中文数字转阿拉伯数字
|
|
var zh2number = function(text){
|
|
var num = 0;
|
|
var map = {'大':1,'小':99};
|
|
var textAttr = ['','一','二','三','四','五','六','七','八','九','十'];
|
|
if(map[text]){
|
|
num = map[text];
|
|
}else{
|
|
if(text.indexOf('十')>-1){
|
|
var numAttr = text.split('十');
|
|
if(!numAttr[0]){
|
|
num = 10;
|
|
}else{
|
|
num = textAttr.indexOf(numAttr[0])*10;
|
|
}
|
|
num += textAttr.indexOf(numAttr[1]);
|
|
}else{
|
|
num += textAttr.indexOf(text)>-1?textAttr.indexOf(text):0;
|
|
}
|
|
}
|
|
return num;
|
|
};
|
|
|
|
// 阿拉伯数字转中文数字
|
|
var number2zh = function(num){
|
|
var text = '';
|
|
var map = {1:'大',99:'小'};
|
|
var textAttr = ['','一','二','三','四','五','六','七','八','九','十'];
|
|
if(map[num]){
|
|
text = map[num];
|
|
}else{
|
|
var dec = ~~(num/10);
|
|
var unit = num%10;
|
|
if(dec){
|
|
if(dec>1){
|
|
text = dec<textAttr.length?textAttr[dec]:'';
|
|
}
|
|
text += '十';
|
|
text += unit<textAttr.length?textAttr[unit]:'';
|
|
}else{
|
|
text += num<textAttr.length?textAttr[num]:'';
|
|
}
|
|
}
|
|
return text;
|
|
};
|
|
|
|
// 获得代数
|
|
var getGen = function(id){
|
|
var gMap = {'f':1,'m':1,'s':-1,'d':-1};
|
|
var arr = id.split(',');
|
|
var gen = 0;
|
|
arr.forEach(function(sub){
|
|
var s = sub.replace(/&[ol\d]+/,'');
|
|
gen += gMap[s]||0;
|
|
});
|
|
return gen;
|
|
};
|
|
|
|
// 获得最简
|
|
var getOptimal = function(options){
|
|
var from = options['from'];
|
|
var to = options['to']
|
|
var from_chain = options['from'].split(',');
|
|
var to_chain = options['to'].split(',');
|
|
for(var i=0;i<from_chain.length&&i<to_chain.length;i++){
|
|
if(from_chain[i]==to_chain[i]){
|
|
from = from_chain.slice(i+1).join(',');
|
|
to = to_chain.slice(i+1).join(',');
|
|
continue;
|
|
}else{
|
|
if(getGen(from_chain[i])==getGen(to_chain[i])&&from_chain[i].match(/^[xol][bs]|^[sd]/)){
|
|
var from_match = from_chain[i].match(/&([ol\d]+)/);
|
|
var to_match = to_chain[i].match(/&([ol\d]+)/);
|
|
if(!from_match){
|
|
from_match = from_chain[i].match(/([xol])[bs]/);
|
|
}
|
|
if(!to_match){
|
|
to_match = to_chain[i].match(/([xol])[bs]/);
|
|
}
|
|
var from_attr = from_match?from_match[1]:'';
|
|
var to_attr = to_match?to_match[1]:'';
|
|
if(!isNaN(from_attr)&&!isNaN(to_attr)){
|
|
if(from_attr>to_attr){
|
|
from_chain[i] = from_chain[i].replace(/^[xol]b|^s/,'lb').replace(/^[xol]s|^d/,'ls');
|
|
from = from_chain.slice(i).join(',');
|
|
to = to_chain.slice(i+1).join(',');
|
|
}else if(from_attr<to_attr){
|
|
from_chain[i] = from_chain[i].replace(/^[xol]b|^s/,'ob').replace(/^[xol]s|^d/,'os');
|
|
from = from_chain.slice(i).join(',');
|
|
to = to_chain.slice(i+1).join(',');
|
|
}
|
|
}else if(!isNaN(from_attr)&&to_attr=='o'||from_attr=='l'&&!isNaN(to_attr)){
|
|
from_chain[i] = from_chain[i].replace(/^[xol]b|^s/,'lb').replace(/^[xol]s|^d/,'ls');
|
|
from = from_chain.slice(i).join(',');
|
|
to = to_chain.slice(i+1).join(',');
|
|
}else if(!isNaN(from_attr)&&to_attr=='l'||from_attr=='o'&&!isNaN(to_attr)){
|
|
from_chain[i] = from_chain[i].replace(/^[xol]b|^s/,'ob').replace(/^[xol]s|^d/,'os');
|
|
from = from_chain.slice(i).join(',');
|
|
to = to_chain.slice(i+1).join(',');
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return {
|
|
'from':from,
|
|
'to':to
|
|
};
|
|
};
|
|
|
|
// 数组去重
|
|
export function unique(arr){
|
|
var sameList = arr.filter(item=>item==item.replace(/[ol](?=s|b)/,'x').replace(/&[ol]/,''));
|
|
return arr.filter(item=>{
|
|
var temp = item.replace(/[ol](?=s|b)/,'x').replace(/&[ol]/,'');
|
|
return sameList.indexOf(item)>-1||item!=temp&&sameList.indexOf(temp)==-1;
|
|
}).filter((item,idx,arr) => arr.indexOf(item) === idx);
|
|
};
|
|
|
|
// 中文获取选择器
|
|
export function getSelectors(str){
|
|
str = str.replace(/之/g,'的').replace(/吾之?(.+)/,'$1').replace(/我的?(.+)/,'$1');
|
|
if(str.match(/[^娘婆岳亲]家的?/)){
|
|
str = str.replace(/家的?/,'的');
|
|
}
|
|
var lists = str.split('的');
|
|
var result = [];
|
|
var isMatch = true;
|
|
// 双向替换
|
|
var replaceMap = {
|
|
'晜':'兄',
|
|
'哥':'兄',
|
|
'姐':'姊',
|
|
'侄':'姪',
|
|
'婿':'壻',
|
|
'祖父':'王父',
|
|
'祖母':'王母',
|
|
'弟媳':'弟妇',
|
|
'嫂':'兄妇',
|
|
'孙女婿':'孙婿',
|
|
'甥女婿':'甥婿',
|
|
'侄女婿':'侄婿',
|
|
'孙媳妇':'孙妇',
|
|
'甥媳妇':'甥妇',
|
|
'侄媳妇':'侄妇',
|
|
};
|
|
// 含义扩展
|
|
var replaceFilter = {
|
|
'^从表':['从父姑表','从父舅表','从父姨表','从母姑表','从母舅表','从母叔表'],
|
|
'^表表':['姑表叔表','姑表姑表','姑表舅表','姑表姨表','舅表叔表','舅表姑表','舅表舅表','舅表姨表'],
|
|
'^([夫妻内外]?)表':['$1姑表','$1舅表'],
|
|
'^([姑舅])表(?=[^伯叔])':['$1表伯','$1表叔'],
|
|
'^姻':['姑姻','姨姻','姊妹姻','女姻'],
|
|
'^眷':['叔眷','舅眷','兄弟眷','男眷'],
|
|
'^亲家':['姊妹姻','兄弟眷'],
|
|
'^([堂表姨]?)([曾高天烈太远鼻]?)(祖?)([伯叔姑舅姨])':['$1$4$2$3'],
|
|
'^([曾高天烈太远鼻]?)祖?王姑':['姑$1祖母'],
|
|
'^([曾玄来晜仍云耳])([侄甥])':['$2$1'],
|
|
'^外表([伯叔姑舅姨])':['姑表$1外','舅表$1外'],
|
|
'^([堂表姨]?)外甥':['$1甥'],
|
|
'^([舅叔])([曾玄外]*)孙':['$1侄$2孙'],
|
|
'^([姨姑])([曾玄外]*)孙':['$1甥$2孙'],
|
|
'([孙甥侄])$':['$1男','$1女'],
|
|
'([姑舅姨叔])([孙外]*)([男女])$':['$1表侄$2$3','$1表甥$2$3'],
|
|
'祖$':['祖父'],
|
|
'嫂$':['兄妇'],
|
|
'女儿$':['女'],
|
|
'外甥$':['甥'],
|
|
};
|
|
while(lists.length){
|
|
var name = lists.shift(); //当前匹配词
|
|
var items = []; //当前匹配词可能性
|
|
var x_items = [];
|
|
var r_items = [];
|
|
var keywords = [name];
|
|
var getList = function(name){
|
|
for(var filter in replaceFilter){
|
|
var word_list = replaceFilter[filter];
|
|
word_list.forEach(function(word){
|
|
var name1 = name.replace(new RegExp(filter),word);
|
|
if(name1!=name){
|
|
keywords.push(name1);
|
|
getList(name1);
|
|
}
|
|
});
|
|
}
|
|
for(var word in replaceMap){
|
|
var name1 = name.replace(word,replaceMap[word]);
|
|
var name2 = name.replace(replaceMap[word],word);
|
|
if(name1!=name){
|
|
keywords.push(name1);
|
|
}
|
|
if(name2!=name){
|
|
keywords.push(name2);
|
|
}
|
|
}
|
|
};
|
|
getList(name);
|
|
// 通过关键词找关系
|
|
keywords.forEach(function(name){
|
|
var x_name = name.replace(/^[大|小]|^[一|二|三|四|五|六|七|八|九|十]+/,'几');
|
|
var r_name = name.replace(/^[大|小]|^[一|二|三|四|五|六|七|八|九|十]+/,'');
|
|
var match = name.match(/^[大|小]|^[一|二|三|四|五|六|七|八|九|十]+/);
|
|
for(var i in _data){
|
|
var isInclude = false;
|
|
if(_data[i].indexOf(name)>-1){
|
|
items.push(i);
|
|
}
|
|
if(match){
|
|
if(_data[i].indexOf(x_name)>-1){
|
|
var num = zh2number(match[0]);
|
|
var r_i = i.replace(/(,[hw])$/,'&'+num+'$1').replace(/(,[^hw]+)$/,'$1&'+num);
|
|
x_items.push(r_i);
|
|
}
|
|
if(_data[i].indexOf(r_name)>-1){
|
|
if(!i.match(/^[mf,]+$/)&&!r_name.match(/^[从世]/)){ // 直系祖辈不参与排序
|
|
var num = zh2number(match[0]);
|
|
var r_i = i.replace(/(,[hw])$/,'&'+num+'$1').replace(/([^hw]+)$/,'$1&'+num);
|
|
r_items.push(r_i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
// console.log('[keywords]',keywords);
|
|
// 如找不到结果,再是否存在称呼的排行问题(不直接判断,因存在"大舅""三从父兄""三世祖"这样特俗含义的情况)
|
|
if(!items.length){
|
|
items = x_items;
|
|
}
|
|
if(!items.length){
|
|
items = r_items;
|
|
}
|
|
// 完全匹配不到结果
|
|
if(!items.length){
|
|
isMatch = false;
|
|
}
|
|
var res = [];
|
|
if(!result.length){
|
|
result = [''];
|
|
}
|
|
result.forEach(function(a){
|
|
items.forEach(function(b){
|
|
res.push(a+(b?','+b:''));
|
|
});
|
|
});
|
|
result = res;
|
|
}
|
|
return isMatch?result:[];
|
|
};
|
|
|
|
// 合并选择器,查找两个对象之间的关系
|
|
export function mergeSelector(param){
|
|
var from_selector = param['from'];
|
|
var to_selector = param['to'];
|
|
var my_sex = param['sex'];
|
|
if(my_sex<0){
|
|
var to_sex = -1;
|
|
var from_sex = -1;
|
|
if(from_selector.match(/^,[w1]/)){
|
|
from_sex = 1;
|
|
}else if(from_selector.match(/^,[h0]/)){
|
|
from_sex = 0;
|
|
}
|
|
if(to_selector.match(/^,[w1]/)){
|
|
to_sex = 1;
|
|
}else if(to_selector.match(/^,[h0]/)){
|
|
to_sex = 0;
|
|
}
|
|
if(from_sex==-1&&to_sex>-1){
|
|
my_sex = to_sex;
|
|
}else if(from_sex>-1&&to_sex==-1){
|
|
my_sex = from_sex;
|
|
}else if(from_sex==to_sex){
|
|
my_sex = from_sex;
|
|
}else{
|
|
return [];
|
|
}
|
|
}
|
|
var from_ids = selector2id(param['from'],my_sex);
|
|
var to_ids = selector2id(param['to'],my_sex);
|
|
if(!from_ids.length||!to_ids.length){
|
|
return [];
|
|
}
|
|
var result = [];
|
|
from_ids.forEach(function(from){
|
|
to_ids.forEach(function(to){
|
|
var sex = my_sex;
|
|
var selector = ','+to;
|
|
if(selector.match(/,([fhs1](&[ol\d]+)?|[olx]b)(&[ol\d]+)?$/)){
|
|
sex = 1;
|
|
}
|
|
if(selector.match(/,([mwd0](&[ol\d]+)?|[olx]s)(&[ol\d]+)?$/)){
|
|
sex = 0;
|
|
}
|
|
if(from&&to){
|
|
var isOptimal = param.optimal;
|
|
if(from.match(/&\d+/)||to.match(/&\d+/)){
|
|
isOptimal = true;
|
|
}
|
|
if(isOptimal){
|
|
var ops = getOptimal({
|
|
'from':from,
|
|
'to':to
|
|
});
|
|
from = ops['from'];
|
|
to = ops['to'];
|
|
}
|
|
}
|
|
var to_rids = to?reverseId(to,my_sex):[''];
|
|
to_rids.forEach(function(to_r){
|
|
var selector = (to_r?','+to_r:'')+(from?','+from:'');
|
|
result.push({
|
|
'selector':selector,
|
|
'sex':sex
|
|
});
|
|
});
|
|
});
|
|
});
|
|
return result;
|
|
};
|
|
|
|
// 选择器转ID
|
|
export function selector2id(selector,sex){
|
|
var result = [];
|
|
var hash = {};
|
|
if(!selector.match(/^,/)){
|
|
selector = ','+selector;
|
|
}
|
|
//性别判断
|
|
if(sex<0){
|
|
if(selector.match(/^,[w1]/)){
|
|
sex = 1;
|
|
}else if(selector.match(/^,[h0]/)){
|
|
sex = 0;
|
|
}
|
|
}else if(sex==1&&selector.match(/^,[h0]/)){
|
|
return [];
|
|
}else if(sex==0&&selector.match(/^,[w1]/)){
|
|
return [];
|
|
}
|
|
// console.log('[selector]',selector);
|
|
var getId = function(selector,sex){
|
|
if(!selector.match(/^,/)){
|
|
selector = ','+selector;
|
|
}
|
|
if(sex>-1&&selector.indexOf(',1')==-1&&selector.indexOf(',0')==-1){
|
|
selector = ','+sex+selector;
|
|
}
|
|
if(selector.match(/,[mwd0](&[ol\d]+)?,w|,[hfs1](&[ol\d]+)?,h/)){ //同志关系去除
|
|
return [];
|
|
}
|
|
var s='';
|
|
if(!hash[selector]){
|
|
hash[selector] = true;
|
|
do{
|
|
s = selector;
|
|
for(var i in _filter){
|
|
var item = _filter[i];
|
|
// console.log('[filter]',item['exp'],selector);
|
|
selector = selector.replace(item['exp'],item['str']);
|
|
if(selector.indexOf('#')>-1){
|
|
selector.split('#').forEach(getId);
|
|
return false;
|
|
}
|
|
}
|
|
}while(s!=selector);
|
|
if(selector.match(/,[mwd0](&[ol\d+])?,w|,[hfs1](&[ol\d]+)?,h/)){ //同志关系去除
|
|
return false;
|
|
}
|
|
selector = selector.replace(/,[01]/,'').substr(1); //去前面逗号和性别信息
|
|
result.push(selector);
|
|
}
|
|
}
|
|
getId(selector,sex);
|
|
return unique(result);
|
|
};
|
|
|
|
// 逆转ID
|
|
export function reverseId(id,sex){
|
|
var hash = {
|
|
f:['d','s'],
|
|
m:['d','s'],
|
|
h:['w',''],
|
|
w:['','h'],
|
|
s:['m','f'],
|
|
d:['m','f'],
|
|
lb:['os','ob'],
|
|
ob:['ls','lb'],
|
|
xb:['xs','xb'],
|
|
ls:['os','ob'],
|
|
os:['ls','lb'],
|
|
xs:['xs','xb']
|
|
};
|
|
var age = '';
|
|
if(id.match(/&o$/)){
|
|
age = '&l';
|
|
}else if(id.match(/&l$/)){
|
|
age = '&o';
|
|
}
|
|
if(id){
|
|
id = id.replace(/&[ol\d+]/g,'');
|
|
//性别判断
|
|
if(sex<0){
|
|
if(id.match(/^w/)){
|
|
sex = 1;
|
|
}else if(id.match(/^h/)){
|
|
sex = 0;
|
|
}
|
|
}
|
|
var result = [];
|
|
var doing = function(sex){
|
|
var sid = (','+sex+','+id).replace(/,[fhs]|,[olx]b/g,',1').replace(/,[mwd]|,[olx]s/g,',0');
|
|
sid = sid.substring(0,sid.length-2);
|
|
var id_arr = id.split(',').reverse();
|
|
var sid_arr = sid.split(',').reverse();
|
|
var arr = id_arr.map((id,i)=>hash[id][sid_arr[i]]);
|
|
var r_id = arr.join(',');
|
|
var gen = getGen(r_id);
|
|
return r_id +(gen?'':age);
|
|
};
|
|
if(sex<0){
|
|
result.push(doing(1));
|
|
result.push(doing(0));
|
|
}else{
|
|
result.push(doing(sex));
|
|
}
|
|
return result;
|
|
}
|
|
return [''];
|
|
};
|
|
|
|
// 通过ID获取关系称呼
|
|
export function getItemsById(id){
|
|
var items = [];
|
|
var getData = function(d){
|
|
var res = [];
|
|
if(_data[d]){
|
|
res.push(_data[d][0]);
|
|
}else{
|
|
for(var i in _data){
|
|
if(i.replace(/&[ol]/g,'')==d){
|
|
res.push(_data[i][0]);
|
|
}else{
|
|
var expr = d;
|
|
while (expr.match(/[ol](b|s)/)){
|
|
expr = expr.replace(/[ol](b|s)/,'x$1');
|
|
if(expr==i){
|
|
res.push(_data[i][0]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
};
|
|
// 对排序进行处理
|
|
while(id.match(/&\d+/)){
|
|
var num = id.match(/&([\d]+)/)[1];
|
|
var zh = number2zh(num);
|
|
id = id.replace(/&\d+/,'');
|
|
if(_data[id]){
|
|
var item = '';
|
|
_data[id].forEach(function(name){
|
|
if(!item&&name.indexOf('几')>-1){
|
|
item = name.replace('几',zh);
|
|
}
|
|
});
|
|
if(!item){
|
|
item = _data[id][0].match(/^[大小]/)?_data[id][0].replace(/^[大小]/,zh):zh+_data[id][0];
|
|
}
|
|
items.push(item);
|
|
break;
|
|
}
|
|
}
|
|
// 直接匹配称呼
|
|
if(!items.length){
|
|
items = getData(id);
|
|
}
|
|
// 忽略年龄条件查找
|
|
if(!items.length){
|
|
id = id.replace(/&[ol]/g,'');
|
|
items = getData(id);
|
|
}
|
|
// 忽略年龄条件查找
|
|
if(!items.length){
|
|
id = id.replace(/[ol](b|s)/g,'x$1');
|
|
items = getData(id);
|
|
}
|
|
// 缩小访问查找
|
|
if(!items.length){
|
|
var l = id.replace(/x/g,'l');
|
|
var o = id.replace(/x/g,'o');
|
|
items = items.concat(getData(o),getData(l));
|
|
}
|
|
return items;
|
|
};
|
|
|
|
// 通过ID获取关系链
|
|
export function getChainById(id){
|
|
var arr = id.split(',');
|
|
return arr.map(function(sign){
|
|
var key = sign.replace(/&[ol]/,'');
|
|
var data = Object.assign({},_data,{
|
|
'xb':['兄弟'],
|
|
'xs':['姐妹']
|
|
});
|
|
return data[key][0];
|
|
}).join('的');
|
|
};
|
|
|
|
// 通过ID获取关系合称
|
|
export function getPairsByIds(id1,id2){
|
|
var result = [];
|
|
var result_r = [];
|
|
id1 = id1.replace(/&\d+/,'');
|
|
id2 = id2.replace(/&\d+/,'');
|
|
var id1_r = id1.replace(/([ol])([bs])/,'x$2');
|
|
var id2_r = id2.replace(/([ol])([bs])/,'x$2');
|
|
for(var key in _pair){
|
|
var selectors = key.split('#');
|
|
if(selectors.length>1){
|
|
var list1 = selector2id(selectors[0]);
|
|
var list2 = selector2id(selectors[1]);
|
|
var list1_r = list1.map(function(selector){
|
|
return selector.replace(/&[ol\d]+/,'').replace(/([ol])([bs])/,'x$2');
|
|
});
|
|
var list2_r = list2.map(function(selector){
|
|
return selector.replace(/&[ol\d]+/,'').replace(/([ol])([bs])/,'x$2');
|
|
});
|
|
if(list1.indexOf(id1)>-1&&list2.indexOf(id2)>-1||list1.indexOf(id2)>-1&&list2.indexOf(id1)>-1){
|
|
result.push(_pair[key][0]);
|
|
}
|
|
if(list1_r.indexOf(id1_r)>-1&&list2_r.indexOf(id2_r)>-1||list1_r.indexOf(id2_r)>-1&&list2_r.indexOf(id1_r)>-1){
|
|
result_r.push(_pair[key][0]);
|
|
}
|
|
}
|
|
}
|
|
if(!result.length){
|
|
result = result_r;
|
|
}
|
|
return result;
|
|
};
|
|
|
|
// 设置模式数据
|
|
export function setMode(sign,data){
|
|
_mode[sign] = Object.assign(_mode[sign]||{},data);
|
|
};
|
|
|
|
// 获取模式数据
|
|
export function getDataByMode(sign){
|
|
var data = Object.assign({},_map);
|
|
if(sign&&_mode[sign]){
|
|
for(var key in _mode[sign]){
|
|
data[key] = [].concat(_mode[sign][key],_map[key]||[]);
|
|
}
|
|
}
|
|
return data;
|
|
};
|