基于KMP与Levenshtein模糊匹配算法的银行联行号查询

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

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

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

先看整体效果

主要代码说明:

  1. swing初始化及数据加载

     1 try {
     2             JFrame frame = new JFrame("银行模糊匹配---edited by Dimmacro");
     3             textLabel = new JLabel("请输入待匹配的字符串:");
     4             textLabel.setFont(new Font("Default", Font.PLAIN, 18));
     5             textField = new JTextField(30);
     6             textField.setFont(new Font("Default", Font.PLAIN, 18));
     7             resultArea = new JTextArea();
     8             resultArea.setFont(new Font("Default", Font.BOLD, 15));
     9             resultArea.setEditable(false);
    10             // 设置窗口初始化大小为屏幕大小的1/4,位置在最中间
    11             JPanel panel = new JPanel();
    12             panel.add(textLabel);
    13             panel.add(textField);
    14             frame.getContentPane().add(panel, BorderLayout.NORTH);
    15             frame.getContentPane().add(new JScrollPane(resultArea), BorderLayout.CENTER);
    16
    17             frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    18             Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    19             frame.setSize(d.width / 2, d.height / 2);
    20             frame.setLocation((d.width - frame.getSize().width) / 2, (d.height - frame.getSize().height) / 2);
    21             frame.setVisible(true);
    22             textField.addKeyListener(new KeyAdapter() {
    23                 public void keyReleased(KeyEvent e) {
    24                     startTime = System.nanoTime();
    25                     readyCheck = true;
    26                 }
    27
    28                 public void keyPressed(KeyEvent e) {
    29                     startTime = System.nanoTime();
    30                     readyCheck = false;
    31                 }
    32
    33             });
    34         } catch (Exception e) {
    35             e.printStackTrace();
    36             resultArea.setText("执行出错!");
    37         }
  2. 联行号数据加载:需要把联行号数据库先加载到内存中,其单行格式为:102100000030,中国工商银行北京市分行营业部

     1 private static long initSourceData() {
     2         long counts = 0;
     3         try {
     4             InputStream bankCodeInputStream = BankMatch.class.getClassLoader().getResourceAsStream(bankCodeFile);
     5             BufferedReader bReader = new BufferedReader(new InputStreamReader(bankCodeInputStream, "GBK"),20480);
     6             String lineString;
     7             bankMap = new HashMap<String, String>();
     8             String code, name;
     9             while ((lineString = bReader.readLine()) != null) {
    10                 int firstCommaIndex = lineString.indexOf(",");
    11                 code = lineString.substring(0, firstCommaIndex);
    12                 name = lineString.substring(firstCommaIndex + 1);
    13                // System.out.println("code=" + code + " and name=" + name+"=========="+counts);
    14                 bankMap.put(code, name);
    15                 counts++;
    16             }
    17         } catch (Exception e) {
    18             e.printStackTrace();
    19         }
    20         return counts;
    21     }
  3. 根据传入的参数模糊查询,返回符合条件的列表,并按最佳匹配程度进行排序

     1     public List<String> handleMatch() {
     2         List<String> resultList = new ArrayList<String>();
     3         String code, name;
     4         String[] nameArray;
     5         String findResult;
     6         for (Map.Entry<String, String> entry : bankMap.entrySet()) {
     7             code = entry.getKey();
     8             name = entry.getValue();
     9             nameArray = name.split(",");
    10             findResult = code + "," + nameArray[0];
    11             List<String> arrangeList = new ArrayList<String>();
    12             resultStr = new String[nameArray.length];
    13             arrageArray(arrangeList, nameArray); // 如果有省份城市,重排其顺序以保证匹配的准确性
    14             for (String oneArrangeStr : arrangeList) {
    15                 name = oneArrangeStr.replaceAll(",", "");
    16                 // 处理BMP全字匹配的情况
    17                 if ((KMPMatchString.kmpMatch(name, matchStr) || KMPMatchString.kmpMatch(matchStr, name)) && !resultList.contains(findResult)) {
    18                     resultList.add(findResult);
    19                     match.printOut(findResult);
    20                     match.getShowArea().selectAll();
    21                 }
    22             }
    23         }
    24         // Levenshtein 模糊算法
    25         if (resultList.size() > 0) {
    26             // 根据Levenshtein 模糊算法排序
    27             Collections.sort(resultList, new Comparator<String>() {
    28                 public int compare(String s1, String s2) {
    29                     return LevenshteinMacthString.levenshteinMacth(s1.split(",")[1], matchStr)
    30                     - LevenshteinMacthString.levenshteinMacth(s2.split(",")[1], matchStr);
    31                 }
    32             });
    33         }
    34         return resultList;
    35     }
  4. KMP算法

     1 public static boolean kmpMatch(String source, String target)
     2     {
     3         if(null == source || null == target || "".equals(source.trim()) || "".equals(target.trim()))
     4         {
     5             return false;
     6         }
     7
     8         int bl = source.length();
     9         int al = target.length();
    10
    11         for(int bi = 0,ai = 0;bi < al;ai++)
    12         {
    13             if(bi == al || ai == bl)
    14             {
    15                 return false;
    16             }
    17             else if(source.charAt(ai) == target.charAt(bi))
    18             {
    19                 bi++;
    20             }
    21         }
    22         return true;
    23     }
  5. Levenshtein算法

     1 public static int levenshteinMacth(String source,String target) {
     2         int n = target.length();
     3         int m = source.length();
     4         int[][] d = new int[n + 1][m + 1];
     5
     6         // Step 1
     7         if (n == 0) {
     8             return m;
     9         }
    10
    11         if (m == 0) {
    12             return n;
    13         }
    14
    15         // Step 2
    16         for (int i = 0; i <= n; d[i][0] = i++) {
    17         }
    18
    19         for (int j = 0; j <= m; d[0][j] = j++) {
    20         }
    21
    22         // Step 3
    23         for (int i = 1; i <= n; i++) {
    24             // Step 4
    25             for (int j = 1; j <= m; j++) {
    26                 // Step 5
    27                // System.out.println(t.charAt(j - 1));
    28               //  System.out.println(s.charAt(i - 1));
    29                // int cost = (t.charAt(j - 1) == s.charAt(i - 1)) ? 0 : 1;
    30                 int cost = (source.substring(j - 1, j) == target.substring(i - 1, i) ? 0 : 1);
    31
    32                 // Step 6
    33                 d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + cost);
    34             }
    35         }
    36         // Step 7
    37         return d[n][m];
    38     }
  6. 附件下载:Eclipse工程,直接导入运行BankMatch类即可看到效果。下载
  7. 遗留代码问题:如整体效果看到的那样,每次从输入框输入完释放最后一次按键时,如果1秒内没有接着按下一个键,才会开始查询,这样既可以做到根据输入的效果实时查询,又不至于要每次输入一个字符就开始查。对于这个实现采用的是wihe(true)的方式,但是发现如果不加线程sleep的话会出现不响应查询的情况,请万能的博客园高手看看。
时间: 2024-10-10 13:36:52

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

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

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

基于最小生成树的实时立体匹配算法简介

转载请注明出处:http://blog.csdn.net/wangyaninglm/article/details/51533549, 来自: shiter编写程序的艺术 图割,置信传播等全局优化立体匹配算法,由于运算过程中需要迭代求精,运算时间长,无法达到实时计算立体匹配的需求,然而实时性需求却广泛存在立体匹配的应用场景中.很多基于局部匹配的算法虽然运算时间短,但由于仅考虑匹配窗内的代价聚合,效果很差,视差图只有很多稀疏的视差点,还要经过插值计算,显然无法用于汽车导航,目标拾取等需要精确结果且

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

原文:C#:根据银行卡卡号推断银行名称 原文地址:android 根据银行卡卡号判断银行 原文是 java ,现在将它翻译成 C# ,并对代码重新编排整理,不足之处请多多包涵. 根据银行卡号判断所属银行,依据是卡号的前6位数,称之为bin号. 我们把bin号转化为长整形,再把各个银行卡的bin号做成有序表.通过二分查找的方法,找到bin号在有序表的位置,然后读出银行卡的信息. 1.创建项目:BankInfoDemo(控制台应用程序) 2.新建类:BankInfo.cs 1 /// <summar

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

原文地址:android 根据银行卡卡号判断银行 原文是 java ,现在将它翻译成 C# ,并对代码重新编排整理,不足之处请多多包涵. 根据银行卡号判断所属银行,依据是卡号的前6位数,称之为bin号. 我们把bin号转化为长整形,再把各个银行卡的bin号做成有序表.通过二分查找的方法,找到bin号在有序表的位置,然后读出银行卡的信息. 1.创建项目:BankInfoDemo(控制台应用程序) 2.新建类:BankInfo.cs 1 /// <summary> 2 /// 银行信息 3 ///

判断银行卡卡号输入的合法性接口

// 判断银行卡卡号输入的合法性 //参数:输入银行卡号,判断银行卡号是否为合法的银行卡卡号(YES 为合法) - (BOOL) checkCardNo:(NSString*) cardNo;  判断银行卡卡号输入的合法性接口 #pragma mark ---——————————————————————————判断银行卡卡号输入的合法性---—————————————————————————— - (BOOL) checkCardNo:(NSString*) cardNo{ int oddsum

取客户的银行帐号SQL

SELECT ibybanks.bank_name, --银行 ibybanks.bank_branch_name, --分行 ibybanks.bank_account_num_electronic--银行帐号 FROM iby_external_payers_all iepa, iby_pmt_instr_uses_all ipiua, iby_ext_bank_accounts_v ibybanks WHERE iepa.payment_function = 'CUSTOMER_PAYME

OnKeyListener键盘事件验证银行帐号

可以通过键盘事件对EMAIL进行验证(这是网上最多的例子),也可以加入关键字非法文字的过滤.如果要监听键盘事件,必须知道按下和松开两种不同的操作,在OnKeyEvent可以找到按下松开的键.我们这个案例是输入银行卡号,用大字四个一组分隔回显出来,用于提醒是否输错! 知识点:OnKey 一.设计界面 1.打开“res/layout/activity_main.xml”文件. (1)从工具栏向activity拖出1个文本编辑框EditText.2个文本标签TextView. 3.打开activity

基于 request cache 请求缓存技术优化批量商品数据查询接口_一点课堂(多岸学院)

基于 request cache 请求缓存技术优化批量商品数据查询接口 Hystrix command 执行时 8 大步骤第三步,就是检查 Request cache 是否有缓存. 首先,有一个概念,叫做 Request Context 请求上下文,一般来说,在一个 web 应用中,如果我们用到了 Hystrix,我们会在一个 filter 里面,对每一个请求都施加一个请求上下文.就是说,每一次请求,就是一次请求上下文.然后在这次请求上下文中,我们会去执行 N 多代码,调用 N 多依赖服务,有的

基于核方法的模糊C均值聚类

摘要: 本文主要针对于FCM算法在很大程度上局限于处理球星星团数据的不足,引入了核方法对算法进行优化.  与许多聚类算法一样,FCM选择欧氏距离作为样本点与相应聚类中心之间的非相似性指标,致使算法趋向于发现具有相近尺度和密度的球星簇.因此,FCM很大程度上局限于对球星星团的处理,不具有普遍性.联系到支持向量机中的核函数,可采用核方法将数据映射到高维特征空间进行特征提取从而进行聚类.现阶段,核方法已广泛应用于模糊聚类分析算法.核方法的应用目前已成为计算机智能方面的热点之一,对于核学习的深入研究具有