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

银行联行号一般是根据输入的分支行信息模糊查询出来的,有的银行接口也会提供类似的根据传入的信息返回联行号的接口,其实现的技术也是根据模糊匹配思路,只是不同的银行实现的水准高低不同,如输入"工行海淀支行"有的返回的是中国工商银行北京市分行海淀镇支行营业室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. 【POJ1509】Glass Beads 【后缀自动机】

    题意 给出一个字符串,求它的最小表示法. 分析 这个题当然可以用最小表示法做啦!但是我是为了学后缀自动机鸭! 我们把这个字符串长度乘二,然后建SAM,然后在SAM上每次跑最小的那个字母,找出长度为n的 ...

  2. spark属性

    应用属性 属性名 缺省值 意义 spark.app.name (none) The name of your application. This will appear in the UI and i ...

  3. SqlServer性能瓶颈分析

    SqlServer性能瓶颈分析 一.内存瓶颈分析--SQLServer:Buffer Manager SELECT TOP 312 * FROM  sys.dm_os_performance_coun ...

  4. 访问tomcat出现java.lang.IllegalStateException No output folder错误解决方法

    访问tomcat出现java.lang.IllegalStateException: No output folder错误解决方法 问题:tomcat分为安装版和解压缩版,解压缩版如果解压到安装盘,在 ...

  5. 1.spark的wordcount解析

    一.Eclipse(scala IDE)开发local和cluster (一). 配置开发环境 要在本地安装好java和scala.  由于spark1.6需要scala 2.10.X版本的.推荐 2 ...

  6. Python爬虫实战一之爬取糗事百科段子

    大家好,前面入门已经说了那么多基础知识了,下面我们做几个实战项目来挑战一下吧.那么这次为大家带来,Python爬取糗事百科的小段子的例子. 首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把 ...

  7. Ubuntu的SWAP设置

    1. 在Ubuntu中配置使用新创建的Swap分区 Command list: 查找Swap分区的UUID sudo blkid 在/ect/fstab中加入新的Swap分区 sudo gedit / ...

  8. Oracle 递归

      当对象存在父节点.子节点时,通过特定的方式获取父节点.子节点数据构建树状结构或其它形式结构时,通常都会使用递归,如:一个公司有多个部门.每个部门下可能有多个小部门,小部门下面又有组-.为了数据容易 ...

  9. 设计模式(java的23种设计模式)

    转自:leshui http://blog.csdn.net/leshui/article/details/11951 在java版看见了这篇文章,作者以轻松的语言比喻了java的32种模式,有很好的 ...

  10. Qt之QML开发常用知识

    小技巧: 1. QML的内部逻辑可以直接调试 2. ctrl+ alt + space,在写QML时,可以直接调出工具条 3. 属性以小写字母开发 4. 属性改变事件,基本都是on+Property+ ...