基于KMP与Levenshtein模糊匹配算法的银行联行号查询
在人民银行那里,每个银行的每一个营业网点都有自己唯一的银行联行号,根据这个号码能快速定位一间银行具体的分支行,就像根据一个身份证号码能快速确定一个人一样。例如汇款时,汇款单上要求填写收款人开户行,然后银行会把收款人开户行的联行号连其他信息发到人民银行进行清算,这样能保证以最快的速度汇到收款人的手上。如果联行号不准确,那么在汇款的时候会发生分行落地,支行间调拨等操作,影响导致时间,尤其是跨行汇款的时候。一般银行的代收付接口,都会要求提供此参数。
银行联行号一般是根据输入的分支行信息模糊查询出来的,有的银行接口也会提供类似的根据传入的信息返回联行号的接口,其实现的技术也是根据模糊匹配思路,只是不同的银行实现的水准高低不同,如输入"工行海淀支行"有的返回的是中国工商银行北京市分行海淀镇支行营业室102100000458,有的返回的是中国工商银行北京市海淀支行四季青分理处102100024537。
本文主要是基于前两年在支付行业的代码实战,通过联行号模糊查询示例讲解KMP与Levenshtein模糊匹配算法,有关此两种算法的介绍可以参考Levenshtein字符串距离算法介绍与KMP字符串匹配算法,本文只是整个查询功能的代码示例,为了专注算法重点,略去了银行同义词之间的匹配与模糊地市查询能力。(银行同义词如工行、工商银行、中国工商银行股份有限公司,模糊地市如江西省南昌市、江西南昌)
先看整体效果

主要代码说明:
- swing初始化及数据加载
try {
JFrame frame = new JFrame("银行模糊匹配---edited by Dimmacro");
textLabel = new JLabel("请输入待匹配的字符串:");
textLabel.setFont(new Font("Default", Font.PLAIN, 18));
textField = new JTextField(30);
textField.setFont(new Font("Default", Font.PLAIN, 18));
resultArea = new JTextArea();
resultArea.setFont(new Font("Default", Font.BOLD, 15));
resultArea.setEditable(false);
// 设置窗口初始化大小为屏幕大小的1/4,位置在最中间
JPanel panel = new JPanel();
panel.add(textLabel);
panel.add(textField);
frame.getContentPane().add(panel, BorderLayout.NORTH);
frame.getContentPane().add(new JScrollPane(resultArea), BorderLayout.CENTER); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
frame.setSize(d.width / 2, d.height / 2);
frame.setLocation((d.width - frame.getSize().width) / 2, (d.height - frame.getSize().height) / 2);
frame.setVisible(true);
textField.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
startTime = System.nanoTime();
readyCheck = true;
} public void keyPressed(KeyEvent e) {
startTime = System.nanoTime();
readyCheck = false;
} });
} catch (Exception e) {
e.printStackTrace();
resultArea.setText("执行出错!");
} - 联行号数据加载:需要把联行号数据库先加载到内存中,其单行格式为:102100000030,中国工商银行北京市分行营业部
private static long initSourceData() {
long counts = 0;
try {
InputStream bankCodeInputStream = BankMatch.class.getClassLoader().getResourceAsStream(bankCodeFile);
BufferedReader bReader = new BufferedReader(new InputStreamReader(bankCodeInputStream, "GBK"),20480);
String lineString;
bankMap = new HashMap<String, String>();
String code, name;
while ((lineString = bReader.readLine()) != null) {
int firstCommaIndex = lineString.indexOf(",");
code = lineString.substring(0, firstCommaIndex);
name = lineString.substring(firstCommaIndex + 1);
// System.out.println("code=" + code + " and name=" + name+"=========="+counts);
bankMap.put(code, name);
counts++;
}
} catch (Exception e) {
e.printStackTrace();
}
return counts;
} - 根据传入的参数模糊查询,返回符合条件的列表,并按最佳匹配程度进行排序
public List<String> handleMatch() {
List<String> resultList = new ArrayList<String>();
String code, name;
String[] nameArray;
String findResult;
for (Map.Entry<String, String> entry : bankMap.entrySet()) {
code = entry.getKey();
name = entry.getValue();
nameArray = name.split(",");
findResult = code + "," + nameArray[0];
List<String> arrangeList = new ArrayList<String>();
resultStr = new String[nameArray.length];
arrageArray(arrangeList, nameArray); // 如果有省份城市,重排其顺序以保证匹配的准确性
for (String oneArrangeStr : arrangeList) {
name = oneArrangeStr.replaceAll(",", "");
// 处理BMP全字匹配的情况
if ((KMPMatchString.kmpMatch(name, matchStr) || KMPMatchString.kmpMatch(matchStr, name)) && !resultList.contains(findResult)) {
resultList.add(findResult);
match.printOut(findResult);
match.getShowArea().selectAll();
}
}
}
// Levenshtein 模糊算法
if (resultList.size() > 0) {
// 根据Levenshtein 模糊算法排序
Collections.sort(resultList, new Comparator<String>() {
public int compare(String s1, String s2) {
return LevenshteinMacthString.levenshteinMacth(s1.split(",")[1], matchStr)
- LevenshteinMacthString.levenshteinMacth(s2.split(",")[1], matchStr);
}
});
}
return resultList;
} - KMP算法
public static boolean kmpMatch(String source, String target)
{
if(null == source || null == target || "".equals(source.trim()) || "".equals(target.trim()))
{
return false;
} int bl = source.length();
int al = target.length(); for(int bi = 0,ai = 0;bi < al;ai++)
{
if(bi == al || ai == bl)
{
return false;
}
else if(source.charAt(ai) == target.charAt(bi))
{
bi++;
}
}
return true;
} - Levenshtein算法
public static int levenshteinMacth(String source,String target) {
int n = target.length();
int m = source.length();
int[][] d = new int[n + 1][m + 1]; // Step 1
if (n == 0) {
return m;
} if (m == 0) {
return n;
} // Step 2
for (int i = 0; i <= n; d[i][0] = i++) {
} for (int j = 0; j <= m; d[0][j] = j++) {
} // Step 3
for (int i = 1; i <= n; i++) {
// Step 4
for (int j = 1; j <= m; j++) {
// Step 5
// System.out.println(t.charAt(j - 1));
// System.out.println(s.charAt(i - 1));
// int cost = (t.charAt(j - 1) == s.charAt(i - 1)) ? 0 : 1;
int cost = (source.substring(j - 1, j) == target.substring(i - 1, i) ? 0 : 1); // Step 6
d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + cost);
}
}
// Step 7
return d[n][m];
} - 附件下载:Eclipse工程,直接导入运行BankMatch类即可看到效果。下载
- 遗留代码问题:如整体效果看到的那样,每次从输入框输入完释放最后一次按键时,如果1秒内没有接着按下一个键,才会开始查询,这样既可以做到根据输入的效果实时查询,又不至于要每次输入一个字符就开始查。对于这个实现采用的是wihe(true)的方式,但是发现如果不加线程sleep的话会出现不响应查询的情况,请万能的博客园高手看看。
基于KMP与Levenshtein模糊匹配算法的银行联行号查询的更多相关文章
- 基于KMP与Levenshtein模糊匹配算法的银行联行号查询(转)
在人民银行那里,每个银行的每一个营业网点都有自己唯一的银行联行号,根据这个号码能快速定位一间银行具体的分支行,就像根据一个身份证号码能快速确定一个人一样.例如汇款时,汇款单上要求填写收款人开户行,然后 ...
- 求最长公共前缀和后缀—基于KMP的next数组
KMP算法最主要的就是计算next[]算法,但是我们知道next[]求的是当前字符串之前的子字符串的最大前后缀数,但是有的时候我们需要比较字符串中前后缀最大数,比如 LeetCode的shortest ...
- 基于KMP算法的字符串模式匹配问题
基于KMP算法的字符匹配问题 反正整个清明都在纠结这玩意...差点我以为下个清明要给自己过了. 至于大体的理解,我就不再多说了(还要画图多麻烦鸭),我参考了以下两个博客,写的真的不错,我放了超链接,点 ...
- C#:根据银行卡卡号判断银行名称
原文地址:android 根据银行卡卡号判断银行 原文是 java ,现在将它翻译成 C# ,并对代码重新编排整理,博主是一个今年刚出来的应届毕业生,不足之处请多多包涵. 根据银行卡号判断所属银行,依 ...
- 国内银行CNAPS CODE 查询
原地址:http://weekend.blog.163.com/blog/static/746895820127961346724/ 全国各地,无论哪个银行,无论什么分行,所有的CNAPS CODE都 ...
- C#:根据银行卡卡号推断银行名称
原文:C#:根据银行卡卡号推断银行名称 原文地址:android 根据银行卡卡号判断银行 原文是 java ,现在将它翻译成 C# ,并对代码重新编排整理,不足之处请多多包涵. 根据银行卡号判断所属银 ...
- C#_根据银行卡卡号判断银行名称
/// <summary> /// 银行信息 /// </summary> public class BankInfo { #region 数组形式存储银行BIN号 /// & ...
- 前端JS校验银行卡卡号和身份证号码(附ES6版方法)
1.银行卡卡号校验方法. function luhnCheck(bankno) { var lastNum = bankno.substr(bankno.length - 1, 1); //取出最后一 ...
- 华为OJ训练之 简易的银行排号叫号系统
闯关第五关的题目,一个中级题和一个高级题.中间题比較简单,半个小时完毕了.题目例如以下 实现一个简易的银行排号叫号系统 get 取号 演示样例:" ...
随机推荐
- Hibernate事务代码规范写法
----------------siwuxie095 事务相关概念 1.什么是事务 逻辑上的一组操作,构成这组操作的各个单元,要么一起成功, 要么一起失败 2.事务的四个特性 1)原子性 2)一致性 ...
- 微信小程序文档里看不到的小Tips
前几天折腾了下.然后列出一些实验结果,供大家参考. 0. 使用开发工具模拟的和真机差异还是比较大的.也建议大家还是真机调试比较靠谱. 1. WXML(HTML) 1.1 小程序的WXML没有HTML的 ...
- HDFS Hbase
Hbase:Hbase是Hadoop的数据库,是bigtable的实现,基于HDFSHDFS:文件系统,是gfs的实现 Hive,Hbase,HDFS等之间的关系Hive:Hive不支持更改数据的操作 ...
- vim调用替换文件内容
:s/vivian/sky/ 替换当前行第一个 vivian 为 sky :s/vivian/sky/g 替换当前行所有 vivian 为 sky :n,$s/vivian/sky/ 替换 ...
- Spring Data JPA初使用 *****重要********
Spring Data JPA初使用 我们都知道Spring是一个非常优秀的JavaEE整合框架,它尽可能的减少我们开发的工作量和难度. 在持久层的业务逻辑方面,Spring开源组织又给我们带来了同样 ...
- [GO]json解析到map
package main import ( "encoding/json" "fmt" ) var str string func main() { m := ...
- 36 有n个整数,使其前面各数顺序向后移n个位置,最后m个数变成最前面的m个数
题目:有n个整数,使其前面各数顺序向后移n个位置,最后m个数变成最前面的m个数 public class _036ExchangeSite { public static void main(Stri ...
- Android开发之Tween(补间动画)
在android中动画主要有三种,①帧动画(http://blog.csdn.net/dmk877/article/details/45893017)这篇文章已经详细的进行了讲解,②补间动画这也是这篇 ...
- Linq聚合操作之Aggregate,Count,Sum,Distinct源码分析
Linq聚合操作之Aggregate,Count,Sum,Distinct源码分析 一:Linq的聚合运算 1. 常见的聚合运算:Aggregate,Count, Sum, Distinct,Max, ...
- mybatis 基础教程
1.引用mybatis.jar包,以后依赖包. 2.配置映射文件(一个是主配置文件,一个是sql映射文件),注意,mapper.xml 文件必须和dao放在一起. 3.mybatis.xml文件说明 ...