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

银行联行号一般是根据输入的分支行信息模糊查询出来的,有的银行接口也会提供类似的根据传入的信息返回联行号的接口,其实现的技术也是根据模糊匹配思路,只是不同的银行实现的水准高低不同,如输入"工行海淀支行"有的返回的是中国工商银行北京市分行海淀镇支行营业室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的话会出现不响应查询的情况,请万能的博客园高手看看。

最新文章

  1. LINQ to SQL语句(20)之存储过程
  2. *HDU1847 博弈
  3. Java虚拟机2:Java内存区域及对象
  4. 利用Weblogic的iisproxy、iisforward插件实现IIS转发
  5. JDE910笔记2--OMW项目建立及简单使用[转]
  6. NodeJS学习之文件操作
  7. hdoj 2023 求平均成绩
  8. POJPower Network (最大流)
  9. JAVA 并发实现六(Volatile的使用)
  10. J2SE之基础语法总结一
  11. springboot(十一):Spring boot中mongodb的使用
  12. 关于欧几里得算法(gcd)的证明
  13. 【BZOJ4652】【NOI2016】循环之美(莫比乌斯反演,杜教筛)
  14. 玩转Web之html+CSS(一)---论坛首页表格的实现
  15. 修改oracle数据库允许连接的数
  16. Aladdin and the Flying Carpet LightOJ - 1341 (素数打表 + 算术基本定理)
  17. java获取视频缩略图
  18. studio配置本地gradle-x.x.x-all.zip
  19. SAP ALV 修改数字需要添零问题
  20. 3. 支持向量机(SVM)拉格朗日对偶性(KKT)

热门文章

  1. 利用Fiddler对Android模拟器网络请求进行抓包
  2. 混合开发之iOS快速集成DSBridge
  3. 开发微信小程序入门教程,含破解工具
  4. unary_function和binary_function详解
  5. Notepad++ xml/json格式化
  6. 认识Web前端、Web后端、桌面app和移动app新开发模式 - 基于Node.js环境和VS Code工具
  7. Spring下集成ActiveMQ推送
  8. 正则表达式(javascript)
  9. android多lib库工程的自动批量构建--编写ant脚本
  10. TunnelBroker for EdgeRouter 后记