package study.java.hanyx.rpn.crmPatternExp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
/**
* Copyright: Asiainfo-Linkage
*
* @desc: 号码模式匹配
* @version: v1.0
* @author: lvyh
* @date: 2011.02.20
*/
@SuppressWarnings({ "unchecked", "unused" , "rawtypes"})
public class PatternMatch {
//从A开始,有10个字母可供模式定义
public static int BIT_REL_LENGTH = 10;
// 单个号码批量匹配号段表达式和分类表达式
public static Map matchExp(List billIdList, List segmentExp, List typeDefExp, String regionId) throws Exception {
Map map = new HashMap();
StringBuffer matchRst = new StringBuffer();
String billId = null;
String segmentMatch = null;
String typeDefMatch = null;
for (int i = 0; i < billIdList.size(); i++) {
billId = (String) billIdList.get(i);
segmentMatch = PatternMatch.matchExp(billId, segmentExp, regionId);// 返回结果为模式号段编号
// 如果匹配结果为空,则默认归属普通号码模式
if (null == segmentMatch) {
segmentMatch = "10000014";
}
typeDefMatch = PatternMatch.matchExp(billId, typeDefExp, regionId);// 返回结果为模式分类定义编号
if (null == typeDefMatch) {
typeDefMatch = "20000121";
}
if (null != segmentMatch && null != typeDefMatch)
// matchRst.append("\"").append(segmentMatch).append("#").append(typeDefMatch).append("\"");
matchRst.append(segmentMatch).append("#").append(typeDefMatch);
else
matchRst.append("");
map.put(billId, matchRst.toString());// {15951942775,100001#100000005}
}
return map;
}
// 单个号码批量匹配号段表达式和分类表达式
public static Map matchExp(String billId, HashMap segmentExp, HashMap typeDefExp, String regionId) throws Exception {
Map map = new HashMap();
StringBuffer matchRst = new StringBuffer();
String segmentMatch = PatternMatch.matchExp(billId, segmentExp, regionId);
String typeDefMatch = PatternMatch.matchExp(billId, typeDefExp, regionId);
if (null != segmentMatch && null != typeDefMatch) {
matchRst.append("\"").append(segmentMatch).append("#").append(typeDefMatch).append("\"");
}
map.put(billId, matchRst.toString());// {15951942775,100001#100000005}
return map;
}
// 单个号码批量匹配模式表达式
public static String matchExp(String billId, HashMap expMap, String regionId) throws Exception {
boolean rst = false;
Iterator it = expMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String value = (String) entry.getValue();
String key = (String) entry.getKey();
rst = PatternMatch.matchExp(billId, value, regionId);
if (rst == true)
return key;
}
return null;
}
// 单个号码批量匹配模式表达式
public static boolean matchExp(String billId, String[] exps, String regionId) throws Exception {
boolean rst = false;
for (int i = 0; i < exps.length; i++) {
rst = PatternMatch.matchExp(billId, exps[i], regionId);
if (rst == true)
break;
}
return rst;
}
// 单个号码批量匹配模式表达式
public static String matchExp(String billId, List list, String regionId) throws Exception {
boolean rst = false;
PatternBean bean = null;
String numExp = null;
if (billId.startsWith("5")) {
// 1.特殊处理:如果号码为无线铁通号码,则模式号段只需要匹配一个即可-提升性能考虑
numExp = ResConst.WIRELESS_NUM_PATTERN_SEG_EXP;
rst = PatternMatch.matchExp(billId, numExp, regionId);
if (rst == true)
return ResConst.WIRELESS_NUM_PATTERN_SEG_ID;
else
return null;
} else if (billId.startsWith("0")) {
// 2.特殊处理:如果号码为有线铁通固话号码,则模式号段只需要匹配一个即可-提升性能考虑
numExp = ResConst.FIX_NUM_PATTERN_SEG_ID;
rst = PatternMatch.matchExp(billId, numExp, regionId);
if (rst == true)
return ResConst.FIX_NUM_PATTERN_SEG_EXP;
else
return null;
}
for (int i = 0; i < list.size(); i++) {
bean = (PatternBean) list.get(i);
rst = PatternMatch.matchExp(billId, bean.getValue(), regionId);
if (rst == true)
return bean.getKey();// 返回模式编号
}
return null;
}
//可用字符A,B,C,D,E,F,*,其中相同字母代表在号码中数字也一样,比较从号码尾部开始,出现三种字母或以上意味着从A开始升序。
//*代表匹配任何字母
//举例 AABB = 1387495[3344],1387495[5566],ABC = 1387495[123],1387495[345],ABAB = 1387495[3434]
//号码或者比较模式为空,或者号码长度小于模式长度的时候,默认返回true
public static boolean checkBitRel(String resId,String bitRel,int bitOrder){
if(bitRel == null ||bitRel.length() == 0)
return true;
else if(resId == null ||resId.length() == 0||resId.length() < bitRel.length())
return false;
Map chMap = new HashMap();
//逆序,因为比较是从尾部开始
char[] resIdReverseChs = (new StringBuilder(resId)).reverse().toString().toCharArray();
char[] bitRelReverseChs = (new StringBuilder(bitRel)).reverse().toString().toCharArray();
for (int i = 0; i < bitRelReverseChs.length;i++) {
//将A,B,C等字符对应上号码具体的数字
setChMap(chMap,bitRelReverseChs[i],resIdReverseChs[i]);
}
//说明模式字符串的字母种类多余两个,需要根据abc升序输出数字,比如a=3 那么 abc = 123
if(chMap.size() > 2){
//如果不等于1
if(bitOrder != 1)
setChMapAsc(chMap);
}
//如果只有两个字母,字母代表值有一样,那就要返回false 比如ABBA 对 1333333这个号码取值,回到A=3 B=3 而这不是我们的本意
if(chMap.size() == 2){
Iterator e = chMap.values().iterator();
Character ch1 = (Character)e.next();
Character ch2 = (Character)e.next();
if(ch1.equals(ch2)){
return false;
}
}
//检查是否符合规则
boolean re = true;
for (int i = 0; i < bitRelReverseChs.length;i++) {
if(bitRelReverseChs[i] == '*')
continue;
else if(isNum(bitRelReverseChs[i])){
//如果是数字,需要完全相等。
if(bitRelReverseChs[i] != resIdReverseChs[i]){
re = false;
break;
}
}else if(!chMap.get(bitRelReverseChs[i]).equals(resIdReverseChs[i])){
re = false;
break;
}
}
return re;
}
public static boolean isNum(char ch){
return ch >= '0' && ch <= '9';
//return StringUtils.isNumericSpace(String.valueOf(ch));
}
//将map里包含的ABCD等对应具体数字升序赋值
private static void setChMapAsc(Map chMap){
Set keys = chMap.keySet();;
Iterator e = keys.iterator();
Character minCh = Character.MAX_VALUE;
while(e.hasNext()){
Character chRel = (Character)e.next();
if(chRel.compareTo(minCh) < 0){
minCh = chRel;
}
}
char phoneCh = ((Character)chMap.get(minCh)).charValue();
char patternCh = minCh.charValue();
for(int i = 0;i<BIT_REL_LENGTH;i++){
chMap.put(new Character((char) (patternCh + i)),new Character((char) (phoneCh + i)));
}
}
private static void setChMap(Map chMap,char chRel,char chPhone){
if(chRel == '*')
return;
if(!chMap.containsKey(chRel)){
chMap.put(chRel, chPhone);
}
}
public static boolean matchExp(String billId, String exp, String regionId) throws Exception {
exp = PatternMatch.preProcessExp(billId, exp, regionId);
// 预处理表达式后进行分支处理:两种不同风格的表达式类型
if (PatternMatch.isSpecialExp(exp)) {
return ExtPatternMatch.processExp(billId, exp);
} else
return PatternMatch.processExp(billId, exp);
}
public static boolean isSpecialExp(String exp) throws Exception {
if (exp.contains(")&&(") || exp.contains(")||("))
return true;
return false;
}
public static String preProcessExp(String billId, String exp, String regionId) throws Exception {
String newExp = PatternMatch.transform(exp, regionId);
return newExp;
}
// S(v,L(v)-6,1) == '6'|| S(v,L(v)-6,1) == '8'|| S(v,L(v)-6,1) == '9'
public static boolean processExp(String billId, String exp) throws Exception {
Queue queue = PatternMatch.splitExp(exp);
boolean flag = false;
boolean flag2 = false;
boolean rst = false;
for (int i = 0; i < queue.size(); i++) {
String temp = (String) queue.get(i);
if (temp.startsWith("("))// 如果表达式带括号则需要预处理
temp = PatternMatch.transfromExp(temp);// 预处理子表达式
if (temp.startsWith("S") || temp.startsWith("C")) {
flag = PatternMatch.processSubExp(billId, temp);
rst = flag;
} else if (temp.equals("||")) {
temp = (String) queue.get(i + 1);
if (temp.startsWith("("))// 如果表达式带括号则需要预处理
temp = PatternMatch.transfromExp(temp);// 预处理子表达式
flag2 = PatternMatch.processSubExp(billId, temp);
if (flag == true || flag2 == true) {
rst = true;
} else {
rst = false;
}
flag = rst;
i++;
} else if (temp.equals("&&")) {
temp = (String) queue.get(i + 1);
if (temp.startsWith("("))// 如果表达式带括号则需要预处理
temp = PatternMatch.transfromExp(temp);// 预处理子表达式
flag2 = PatternMatch.processSubExp(billId, temp);
if (flag == true && flag2 == true) {
rst = true;
} else {
rst = false;
}
flag = rst;
i++;
}
}
return rst;
}
public static boolean processSubExp(String billId, String exp) throws Exception {
String[] expTemp = null;
if (exp.contains("==")) {
expTemp = PatternMatch.split(exp, "==");
expTemp[0] = expTemp[0].trim();
expTemp[1] = expTemp[1].trim();
if (exp.startsWith("S")) {// S(v,L(v)-6,1) == '6'
String rst = PatternMatch.processSubstr(billId, expTemp[0]);
if (expTemp[1].startsWith("'")) {
expTemp[1] = expTemp[1].substring(1, expTemp[1].length() - 1);
} else if (expTemp[1].startsWith("S")) {// (S(v,L(v)-4,1)!=S(v,L(v)-3,1))
// expTemp[1] = PatternMatch.transfromExp(expTemp[1]);//
// 去掉右括号
expTemp[1] = PatternMatch.processSubstr(billId, expTemp[1]);
}
if (rst.equals(expTemp[1]))
return true;
} else if (exp.startsWith("C")) {// C(S(v,3,4),'4')==true
boolean flag = PatternMatch.processContain(billId, expTemp[0]);
if (Boolean.toString(flag).equals(expTemp[1])) {
return true;
} else
return false;
} else if (exp.startsWith("L")) {
}
return false;
} else if (exp.contains("!=")) {
expTemp = PatternMatch.split(exp, "!=");
expTemp[0] = expTemp[0].trim();
expTemp[1] = expTemp[1].trim();
if (exp.startsWith("S")) {// S(v,L(v)-6,1) == '6'
String rst = PatternMatch.processSubstr(billId, expTemp[0]);
if (expTemp[1].startsWith("'")) {
expTemp[1] = expTemp[1].substring(1, expTemp[1].length() - 1);
} else if (expTemp[1].startsWith("S")) {// (S(v,L(v)-4,1)!=S(v,L(v)-3,1))
//expTemp[1] = PatternMatch.transfromExp(expTemp[1]);// 去掉右括号
expTemp[1] = PatternMatch.processSubstr(billId, expTemp[1]);
}
if (!rst.equals(expTemp[1]))
return true;
} else if (exp.startsWith("C")) {// C(S(v,3,4),'4')==true
boolean flag = PatternMatch.processContain(billId, expTemp[0]);
if (!Boolean.toString(flag).equals(expTemp[1])) {
return true;
} else
return false;
} else if (exp.startsWith("L")) {
}
return false;
}
return false;
}
public static boolean processContain(String billId, String exp) throws Exception {
// C(S(v,3,4),'4')
boolean rst = false;
char c = exp.charAt(2);
if (c == 'S') {
if (exp.contains("L(v)")) {
// 需处理如下情况-C(S(v,L(v)-3,3),'4')--转换--C(S(v,3,4),'4')
exp = PatternMatch.getSubStrExp(billId, exp);
}
int index = exp.indexOf(")");
String temp = exp.substring(2, index + 1);// para: S(v,3,4)
String substr = PatternMatch.processSubstr(billId, exp);
exp = exp.replace(temp, substr);// C("5104",'4');
String[] para = PatternMatch.split(exp, ",");
para[1] = PatternMatch.getParaInt(para[1]);
rst = PatternMatch.invokeContain(substr, para[1]);
}
return rst;
}
public static String getSubStrExp(String billId, String exp) throws Exception {// C(S(v,L(v)-3,3),'4')---------C(S(v,3,4),'4')
int three = PatternMatch.isThreeComma(exp);
String subExp = exp.substring(2, three);// subExp--------S(v,L(v)-3,3)
String temp = PatternMatch.processSubStrExp(billId, subExp);// temp-----S(v,5,3)
CharSequence cs = temp.subSequence(0, temp.length());
String str = exp.replace(subExp, cs);
return str;
}
public static String processSubStrExp(String billId, String exp) throws Exception {
// S(v,L(v)-6,1)
String[] paras = PatternMatch.split(exp, ",");
// Substr共三个参数,第1个为billId,只需处理后两个参数
// 第2个参数
if (paras[1].contains("L(v)")) {
String str = Integer.toString(PatternMatch.invokeLength(billId));
CharSequence cs = str.subSequence(0, str.length());
paras[1] = paras[1].replace("L(v)", cs);
paras[1] = Arithmetic.calculate(paras[1]);// 计算算术表达式字符串值,比如"11-6"
}
// 第3个参数
// 需要截掉最后位的右括号才能进行算术运算
paras[2] = paras[2].substring(0, paras[2].length() - 1);
if (paras[2].contains("L(v)")) {
String str = Integer.toString(PatternMatch.invokeLength(billId));
CharSequence cs = str.subSequence(0, str.length());
paras[2] = paras[2].replace("L(v)", cs);
paras[2] = Arithmetic.calculate(paras[2]);// 计算算术表达式字符串值,比如"11-6"
}
StringBuffer sb = new StringBuffer();
sb.append(paras[0]).append(",").append(paras[1]).append(",").append(paras[2]).append(")");
return sb.toString();// S(v,5,1)
}
public static String processSubstr(String billId, String exp) throws Exception {
// S(v,L(v)-6,1)
String[] paras = PatternMatch.split(exp, ",");
// Substr共三个参数,第1个为billId,只需处理后两个参数
// 第2个参数
if (paras[1].contains("L(v)")) {
String str = Integer.toString(PatternMatch.invokeLength(billId));
CharSequence cs = str.subSequence(0, str.length());
paras[1] = paras[1].replace("L(v)", cs);
paras[1] = Arithmetic.calculate(paras[1]);// 计算算术表达式字符串值,比如"11-6"
}
// 第3个参数
// 需要截掉最后位的右括号才能进行算术运算
paras[2] = paras[2].substring(0, paras[2].length() - 1);
if (paras[2].contains("L(v)")) {
String str = Integer.toString(PatternMatch.invokeLength(billId));
CharSequence cs = str.subSequence(0, str.length());
paras[2] = paras[2].replace("L(v)", cs);
paras[2] = Arithmetic.calculate(paras[2]);// 计算算术表达式字符串值,比如"11-6"
}
int begin = Integer.parseInt(paras[1]);
int length = Integer.parseInt(paras[2]);
String rst = PatternMatch.invokeSubstr(billId, begin, length);
return rst;// S(v,5,1)
}
public static String processContainSubstr(String billId, String exp) throws Exception {
// S(v,L(v)-6,1)
String[] paras = PatternMatch.split(exp, ",");
// Substr共三个参数,第1个为billId,只需处理后两个参数
// 第2个参数
if (paras[1].contains("L(v)")) {
String str = Integer.toString(PatternMatch.invokeLength(billId));
CharSequence cs = str.subSequence(0, str.length());
paras[1] = paras[1].replace("L(v)", cs);
paras[1] = Arithmetic.calculate(paras[1]);// 计算算术表达式字符串值,比如"11-6"
}
// 第3个参数
// 需要截掉最后位的右括号才能进行算术运算
paras[2] = paras[2].substring(0, paras[2].length() - 1);
if (paras[2].contains("L(v)")) {
String str = Integer.toString(PatternMatch.invokeLength(billId));
CharSequence cs = str.subSequence(0, str.length());
paras[2] = paras[2].replace("L(v)", cs);
paras[2] = Arithmetic.calculate(paras[2]);// 计算算术表达式字符串值,比如"11-6"
}
int begin = Integer.parseInt(paras[1]);
int length = Integer.parseInt(paras[2]);
String rst = PatternMatch.invokeSubstr(billId, begin, length);
return rst;
}
public static int isFirstComma(String exp) {// ,
for (int i = 0; i < exp.length(); i++) {
char c = exp.charAt(i);
if (c == ',')
return i;
}
return 0;
}
// 表达式分为2种:带左右括号和不带左右括号;表达式约束:同一表达式逻辑运算符(逻辑或||、逻辑与&&)两侧要么都带,要么都不带括号
public static String transfromExp(String exp) {
// 去掉左括号 (S(v,L(v)-4,1)=='4'---------S(v,L(v)-4,1)=='4'
if (exp.startsWith("(")) {
exp = exp.substring(1, exp.length());
}
// 去掉右括号 S(v,L(v)-4,1)=='4')---------S(v,L(v)-4,1)=='4'
if (exp.endsWith(")")) {
exp = exp.substring(0, exp.length() - 1);
}
return exp;
}
public static int isSecondComma(String exp, int j) {// ,
for (int i = j + 1; i < exp.length(); i++) {
char c = exp.charAt(i);
if (c == ',')
return i;
}
return 0;
}
public static int isThreeComma(String exp) {// ,
int flag = 0;
for (int i = 0; i < exp.length(); i++) {
char c = exp.charAt(i);
if (c == ',') {
flag++;
if (flag == 3) {
return i;
}
}
}
return 0;
}
private List parse(String exp) {
List expList = new ArrayList();
int length = exp.length();
for (int i = 0; i < length; i++) {
char c = exp.charAt(i);
switch (c) {
case 'S': {
expList.add(String.valueOf(c));
continue;
}
case '(': {
expList.add(String.valueOf(c));
continue;
}
case ')': {
expList.add(String.valueOf(c));
continue;
}
case ',': {
expList.add(String.valueOf(c));
continue;
}
case '-': {
expList.add(String.valueOf(c));
continue;
}
case '!': {
char[] token = new char[2];
token[0] = c;
token[1] = exp.charAt(i + 1);
String temp = String.valueOf(token);
expList.add(temp);
i++;
continue;
}
case '\'': {
char[] token = new char[3];
token[0] = c;
token[1] = exp.charAt(i + 1);
token[2] = exp.charAt(i + 2);
String temp = String.valueOf(token);
expList.add(temp);
i++;
i++;
continue;
}
}
if (PatternMatch.isNumeric(c)) {
expList.add(String.valueOf(c));
continue;
}
}
return expList;
}
public static int invokeLength(String billId) throws Exception {
// L(v)
return PatternMatch.length(billId);
}
public static String invokeSubstr(String billId, int begin, int length) throws Exception {
// S(v,8,1)
return PatternMatch.substr(billId, begin, length);
}
public static boolean invokeContain(String billId, String str) throws Exception {
// C(v,'6')
return PatternMatch.contain(billId, str);
}
public static Queue splitExp(String exp) {
Queue queue = new Queue();
// 首先对表达式进行分割,第一次采用"||"分割,确保分割后每段都没有"||"
String[] firstSplit = PatternMatch.split(exp, "||");
for (int i = 0; i < firstSplit.length; i++) {
// 其次对分割后表达式再进行分割,第二次采用"&&"分割,确保分割后每段都没有"&&"
String[] secendSplit = PatternMatch.split(firstSplit[i], "&&");
int size = secendSplit.length;
if (secendSplit.length > 1) {
for (int j = 0; j < size; j++) {
queue .put(secendSplit[j].trim());
if (j < size - 1)
queue.put("&&");
}
} else {
queue.put(firstSplit[i].trim());
}
if (i < firstSplit.length - 1)
queue.put("||");
}
return queue;
}
public static String[] split(String str, String splitChar) {
StringTokenizer st = null;
if ("||".equals(splitChar)) {
st = new StringTokenizer(str, "||");
} else if ("&&".equals(splitChar)) {
st = new StringTokenizer(str, "&&");
} else if (",".equals(splitChar)) {
st = new StringTokenizer(str, ",");
} else if ("==".equals(splitChar)) {
st = new StringTokenizer(str, "==");
} else if ("!=".equals(splitChar)) {
st = new StringTokenizer(str, "!=");
}
String[] temp = new String[st.countTokens()];
int i = 0;
while (st.hasMoreTokens()) {
temp[i] = st.nextToken();
i++;
}
return temp;
}
/**
* 判断当前字符串是否是数字,用ascii码
*
* @param str
* @return
*/
public static boolean isNumeric(String str) {
for (int i = str.length(); --i >= 0;) {
int chr = str.charAt(i);
if (chr < 48 || chr > 57)
return false;
}
return true;
}
/**
* 判断当前字符是否是数字,用ascii码
*
* @param str
* @return
*/
public static boolean isNumeric(char c) {
int ch = (int) c;
if (ch < 48 || ch > 57)
return false;
return true;
}
public static String transform(String exp, String regionId) {
String str = exp.replace("@bill_id", "v");
str = str.replace("@region_id", regionId);
str = str.replace("$substr", "S");
str = str.replace("$length", "L");
str = str.replace("$contain", "C");
//System.out.println("简化后表达式: " + str);
return str;
}
// $length
public static int length(String v) {
return v.length();
}
// $substr-从字符串第begin个字符开始截取长度为length的字符串(下标从1开始)
public static String substr(String v, int begin, int length) throws Exception {
//if (begin == 0)
//begin = 1;// 需要特殊处理
//int beginIndex = begin - 1;
int beginIndex = begin;
int endIndex = begin + length ;
if (endIndex > v.length()) {
//throw new Exception("警告:传入参数有误【数组越界】,函数$substr(@bill_id,para1,para2)中para2<=" + (v.length() - begin + 1));
// throw new Exception(CrmLocaleFactory.getResource("RSS0006744"));
}
// 从字符串索引(下标从0开始)为beginIndex的字符开始截取长度为endIndex-beginIndex 的字符串。
String str ="ERROR";
if(begin>=0){//2011-11-10 开始小于0时,扔出错误字符串
str = v.substring(beginIndex, endIndex);
}
return str;
}
// $contain
public static boolean contain(String v, String s) {
return v.contains(s);
}
public static String getParaInt(String str) {
String temp = null;
if (str.startsWith("'")) {
temp = str.substring(1, str.length() - 2);
} else
temp = str.substring(0, str.length() - 1);
return temp;
}
}