在人民银行那里,每个银行的每一个营业网点都有自己唯一的银行联行号,根据这个号码能快速定位一间银行具体的分支行,就像根据一个身份证号码能快速确定一个人一样。例如汇款时,汇款单上要求填写收款人开户行,然后银行会把收款人开户行的联行号连其他信息发到人民银行进行清算,这样能保证以最快的速度汇到收款人的手上。如果联行号不准确,那么在汇款的时候会发生分行落地,支行间调拨等操作,影响导致时间,尤其是跨行汇款的时候。一般银行的代收付接口,都会要求提供此参数。

银行联行号一般是根据输入的分支行信息模糊查询出来的,有的银行接口也会提供类似的根据传入的信息返回联行号的接口,其实现的技术也是根据模糊匹配思路,只是不同的银行实现的水准高低不同,如输入"工行海淀支行"有的返回的是中国工商银行北京市分行海淀镇支行营业室102100000458,有的返回的是中国工商银行北京市海淀支行四季青分理处102100024537。

本文主要是基于前两年在支付行业的代码实战,通过联行号模糊查询示例讲解KMP与Levenshtein模糊匹配算法,有关此两种算法的介绍可以参考Levenshtein字符串距离算法介绍KMP字符串匹配算法,本文只是整个查询功能的代码示例,为了专注算法重点,略去了银行同义词之间的匹配与模糊地市查询能力。(银行同义词如工行、工商银行、中国工商银行股份有限公司,模糊地市如江西省南昌市、江西南昌)

先看整体效果

主要代码说明:

  1. 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("执行出错!");
    }
  2. 联行号数据加载:需要把联行号数据库先加载到内存中,其单行格式为: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;
    }
  3. 根据传入的参数模糊查询,返回符合条件的列表,并按最佳匹配程度进行排序
         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;
    }
  4. 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;
    }
  5. 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];
    }
  6. 附件下载:Eclipse工程,直接导入运行BankMatch类即可看到效果。下载
  7. 遗留代码问题:如整体效果看到的那样,每次从输入框输入完释放最后一次按键时,如果1秒内没有接着按下一个键,才会开始查询,这样既可以做到根据输入的效果实时查询,又不至于要每次输入一个字符就开始查。对于这个实现采用的是wihe(true)的方式,但是发现如果不加线程sleep的话会出现不响应查询的情况,请万能的博客园高手看看。

基于KMP与Levenshtein模糊匹配算法的银行联行号查询的更多相关文章

  1. 基于KMP与Levenshtein模糊匹配算法的银行联行号查询(转)

    在人民银行那里,每个银行的每一个营业网点都有自己唯一的银行联行号,根据这个号码能快速定位一间银行具体的分支行,就像根据一个身份证号码能快速确定一个人一样.例如汇款时,汇款单上要求填写收款人开户行,然后 ...

  2. 求最长公共前缀和后缀—基于KMP的next数组

    KMP算法最主要的就是计算next[]算法,但是我们知道next[]求的是当前字符串之前的子字符串的最大前后缀数,但是有的时候我们需要比较字符串中前后缀最大数,比如 LeetCode的shortest ...

  3. 基于KMP算法的字符串模式匹配问题

    基于KMP算法的字符匹配问题 反正整个清明都在纠结这玩意...差点我以为下个清明要给自己过了. 至于大体的理解,我就不再多说了(还要画图多麻烦鸭),我参考了以下两个博客,写的真的不错,我放了超链接,点 ...

  4. C#:根据银行卡卡号判断银行名称

    原文地址:android 根据银行卡卡号判断银行 原文是 java ,现在将它翻译成 C# ,并对代码重新编排整理,博主是一个今年刚出来的应届毕业生,不足之处请多多包涵. 根据银行卡号判断所属银行,依 ...

  5. 国内银行CNAPS CODE 查询

    原地址:http://weekend.blog.163.com/blog/static/746895820127961346724/ 全国各地,无论哪个银行,无论什么分行,所有的CNAPS CODE都 ...

  6. C#:根据银行卡卡号推断银行名称

    原文:C#:根据银行卡卡号推断银行名称 原文地址:android 根据银行卡卡号判断银行 原文是 java ,现在将它翻译成 C# ,并对代码重新编排整理,不足之处请多多包涵. 根据银行卡号判断所属银 ...

  7. C#_根据银行卡卡号判断银行名称

    /// <summary> /// 银行信息 /// </summary> public class BankInfo { #region 数组形式存储银行BIN号 /// & ...

  8. 前端JS校验银行卡卡号和身份证号码(附ES6版方法)

    1.银行卡卡号校验方法. function luhnCheck(bankno) { var lastNum = bankno.substr(bankno.length - 1, 1); //取出最后一 ...

  9. 华为OJ训练之 简易的银行排号叫号系统

    闯关第五关的题目,一个中级题和一个高级题.中间题比較简单,半个小时完毕了.题目例如以下 实现一个简易的银行排号叫号系统 get    取号                     演示样例:" ...

随机推荐

  1. Java方法重写与super关键字

    ----------siwuxie095                     方法的重写:     (1)在继承中也存在着重写的概念,其实就是子类定义了和父类同名的方法     (2)定义:方法名 ...

  2. c++ 观察者模式(observer)

    观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.它还有两个别名,依赖 (Dependents),发布-订阅(Publish-Subs ...

  3. 256. Paint House房屋染色

    [抄题]: There are a row of n houses, each house can be painted with one of the three colors: red, blue ...

  4. Linux Bash脚本编程语言中的美学与哲学

    我承认,我再一次地当了标题党.但是不可否认,这一定是一篇精华随笔.在这一篇中,我将探讨Bash脚本语言中的美学与哲学. 这不是一篇Bash脚本编程的教程,但是却能让人更加深入地了解Bash脚本编程,更 ...

  5. spring aop两种配置方式

    基于注解的Spring AOP开发 简单案例快速入门 定义目标类接口和实现类 /** * Created by zejian on 2017/2/19.*/ //接口类 public interfac ...

  6. appium_server_v1.4.16版本不适配android7.0系统,运行报错“Attempt to re-install io.appium.settings without first uninstalling”

    要解决的问题:appium在androidV7.0系统上运行时报错 Failure [INSTALL_FAILED_ALREADY_EXISTS: Attempt to re-install io.a ...

  7. [Excel]鼠标右键菜单没有新建Word、Excel、PPT怎么办?

    很多朋友在安装好Office(2010或2013等)之后,发现右键新建中没有Word.Excel.PowerPoint等项,但是自己的Office却明明安装好了.这个时候该怎么办呢?这里,本文为大家提 ...

  8. maven 执行本地、服务器 jar包安装

    开发时遇到过第三方jar包依赖不了时的尴尬 因为遇到过几次所以记录一下,POM文件引入的个推jar包无效,就必须本地安装了,服务器上的也是一样,执行相同的maven命令就行,注意修改路径!和将jar包 ...

  9. log4j-over-slf4j工作原理详解

    log4j-over-slf4j工作原理详解 摘自:https://blog.csdn.net/john1337/article/details/76152906 置顶 2017年07月26日 17: ...

  10. [C#] readonly vs const

    C#中的readonly和const两个关键字都可以用来定义系统变量,那两者之间有什么区别呢? 1. const变量赋值后,就不可以对其进行修改.且在定义时就需要给它赋值,使用const修饰的变量是s ...