relationship/src/method.js

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;
};