统一社会信用代码校验位校验udf关键代码

package com.audaque.udf;

import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* <p>社会统一信用代码校验
* 社会统一信用代码由18位数字和字母组合而成。
* 1)第1位 【1-9ANY】
* 2)第2-8位 【全数字】
* 3)第9-17位 【数字和字母】
* 4)第18位校验位 【由前17数字字母通过规则计算而得,具体计算规则参照sheet2】
* 需求:上述4条规则,只要一项未满足则返回0,全部通过校验返回1
* </p>
*
* @author 谭黄
* @since 2023/10/31
*/
@org.apache.hadoop.hive.ql.exec.Description(name = "SocialUnifiedCreditCodeVerification",
extended = "示例:select SocialUnifiedCreditCodeVerification(name) from src;",
value = "_FUNC_(col)-将校验col字段是否为合法的社会统一信用代码,校验通过返回1,否则返回0")
public class SocialUnifiedCreditCodeVerification extends UDF {
/**
* 通过的返回值
*/
private static final String YES = "0";
/**
* 未校验通过的返回值
*/
private static final String NO = "1";
/**
* 验证18位的正则
*/
private static final String REGEX = "^[1-9anyANY][0-9]{7}[0-9A-HJ-NP-RTUW-Ya-hj-np-rtuw-y]{10}$";
/**
* 正则预编译
*/
private static final Pattern PATTERN = Pattern.compile(REGEX);

/**
* 函数的执行逻辑
* @param s
* @return
*/
public Text evaluate(final Text s) {
if (s == null) {
return null;
}
String text = s.toString();
//不是18位
if (!(text.length() == 18)) {
return new Text(NO);
}
Matcher matcher = PATTERN.matcher(text);
//正则不匹配,1,2,3条件不满足
if (!matcher.matches()) {
return new Text(NO);
}
String text1_17 = text.substring(0, 17);
int value18 = calculateChekeCode(text1_17);
int text18 = CODE_MAPPING.get(Character.toUpperCase(text.charAt(17)));
//第18位校验失败
if (value18 != text18) {
return new Text(NO);
}
//迭代2 截取9-16位,计算校验码
String text9_16 = text.substring(8, 16);
int value17 = calculateChekeCode2(text9_16);
int text17 = Character.toUpperCase(text.charAt(16));
//第17位校验失败
if(value17!=text17){
return new Text(NO);
}
return new Text(YES);
}

/**
* 根据前17位计算校验码,也就是第18位
*
* @param text17
* @return
*/
private int calculateChekeCode(String text17) {
char[] charArray = text17.toCharArray();
List<Integer> nums = new ArrayList<>();
for (char c : charArray) {
Integer num = CODE_MAPPING.get(Character.toUpperCase(c));
nums.add(num);
}
int sum = 0;
//按顺序迭代计算因子乘积,因子是按下标排列的,所以通过下标直接取因子
for (int i = 0; i < nums.size(); i++) {
int value = nums.get(i) * FACTORS.get(i);
sum += value;
}
//31-sum%31
int value18 = CODE_MAPPING.size() - sum % CODE_MAPPING.size();
//31又映射为0
value18=value18==31?0:value18;
return value18;

}

/**
* 根据前9-16位计算校验码,也就是第17位
*
* @param text9_16
* @return
*/
private int calculateChekeCode2(String text9_16) {
char[] charArray = text9_16.toCharArray();
List<Integer> nums = new ArrayList<>();
for (char c : charArray) {
Integer num = CODE_MAPPING2.get(Character.toUpperCase(c));
nums.add(num);
}
int sum = 0;
//按顺序迭代计算因子乘积,因子是按下标排列的,所以通过下标直接取因子
for (int i = 0; i < nums.size(); i++) {
int value = nums.get(i) * FACTORS2.get(i);
sum += value;
}
//11-sum%11
int value18 = VALUE_MAPPING.size() - sum % VALUE_MAPPING.size();
return VALUE_MAPPING.get(value18);

}

private final static List<Integer> FACTORS;
/**
* 17为校验用的因子
*/
private final static List<Integer> FACTORS2;
/**
* 代码字符与数值映射
*/
private final static Map<Character, Integer> CODE_MAPPING;
/**
* 代码字符与数值映射校验第17位
*/
private final static Map<Character, Integer> CODE_MAPPING2;
/**
* 17位余数和校验码的映射关系
*/
private final static Map<Integer,Character> VALUE_MAPPING;
static {
Map<Integer,Character> map = new HashMap<>(16);
map.put(1,'1');
map.put(2,'2');
map.put(3,'3');
map.put(4,'4');
map.put(5,'5');
map.put(6,'6');
map.put(7,'7');
map.put(8,'8');
map.put(9,'9');
map.put(10,'X');
map.put(11,'0');
VALUE_MAPPING=Collections.unmodifiableMap(map);
}

static {
Map<Character, Integer> map = new HashMap<>(32);
map.put('0', 0);
map.put('1', 1);
map.put('2', 2);
map.put('3', 3);
map.put('4', 4);
map.put('5', 5);
map.put('6', 6);
map.put('7', 7);
map.put('8', 8);
map.put('9', 9);
map.put('A', 10);
map.put('B', 11);
map.put('C', 12);
map.put('D', 13);
map.put('E', 14);
map.put('F', 15);
map.put('G', 16);
map.put('H', 17);
map.put('J', 18);
map.put('K', 19);
map.put('L', 20);
map.put('M', 21);
map.put('N', 22);
map.put('P', 23);
map.put('Q', 24);
map.put('R', 25);
map.put('T', 26);
map.put('U', 27);
map.put('W', 28);
map.put('X', 29);
map.put('Y', 30);

CODE_MAPPING = Collections.unmodifiableMap(map);

}

static {
Map<Character, Integer> map = new HashMap<>(64);
map.put('0', 0);
map.put('1', 1);
map.put('2', 2);
map.put('3', 3);
map.put('4', 4);
map.put('5', 5);
map.put('6', 6);
map.put('7', 7);
map.put('8', 8);
map.put('9', 9);
map.put('A', 10);
map.put('B', 11);
map.put('C', 12);
map.put('D', 13);
map.put('E', 14);
map.put('F', 15);
map.put('G', 16);
map.put('H', 17);
map.put('I', 18);
map.put('J', 19);
map.put('K', 20);
map.put('L', 21);
map.put('M', 22);
map.put('N', 23);
map.put('O', 24);
map.put('P', 25);
map.put('Q', 26);
map.put('R', 27);
map.put('S', 28);
map.put('T', 29);
map.put('U', 30);
map.put('V', 31);
map.put('W', 32);
map.put('X', 33);
map.put('Y', 34);
map.put('Z', 35);
CODE_MAPPING2 = Collections.unmodifiableMap(map);

}

static {
List<Integer> list = new ArrayList<>(17);
list.add(1);
list.add(3);
list.add(9);
list.add(27);
list.add(19);
list.add(26);
list.add(16);
list.add(17);
list.add(20);
list.add(29);
list.add(25);
list.add(13);
list.add(8);
list.add(24);
list.add(10);
list.add(30);
list.add(28);
FACTORS = Collections.unmodifiableList(list);
}

static {
List<Integer> list = new ArrayList<>(8);
list.add(3);
list.add(7);
list.add(9);
list.add(10);
list.add(5);
list.add(8);
list.add(4);
list.add(2);
FACTORS2 = Collections.unmodifiableList(list);
}

public static void main(String[] args) {
SocialUnifiedCreditCodeVerification abc = new SocialUnifiedCreditCodeVerification();
System.out.println(abc.evaluate(new Text("91500108MABXW70B0N")));
System.out.println(abc.evaluate(new Text("91500108MABXW7OB0N")));
}
}

posted @ 2024-12-19 15:51  似懂非懂视为不懂  阅读(153)  评论(0)    收藏  举报