zoukankan      html  css  js  c++  java
  • [java] 汇率换算器实现(2)

    [java] 汇率换算器实现(2)

     

    [java] 汇率换算器实现(2)

    1 系列文章地址

    2 前言

    在上篇文章中, 我们实现了汇率换算器的最简单的版本, 实现了:

    • 帮助信息的提示
    • 汇率表的输入
    • 错误输入的处理
    • 汇率计算的输入
    • 汇率计算结果的输出

    不同类之间的关系图如下(不是严格按照uml规则绘制的): https://images0.cnblogs.com/blog/188068/201405/082238273389754.jpg

    在接下来的内容中主要介绍如何实现汇率表的实时更新.

    3 获取实时汇率信息

    想要获取汇率的实时信息, 很容易想到的方法就是从一个网页中提取相应的汇率信息, 填充到当前的汇率表内. 接着自然想要, 使用java进行network programming, 可以借用java.net库.

    3.1 获取网页内容

    class Rate {
        // 从网站:http://www.usd-cny.com/中获取最新的汇率信息
        final static String webSite = "http://www.usd-cny.com/";
    
        // 利用hashtable对不同货币之间的利率进行存储
        //   key: $from+$to, value: $rate
        private static Hashtable rateTable = new Hashtable();
    
        // 获取网页内容
        public static void update() throws Exception {
            URL hp = new URL(webSite);
            URLConnection hpCon = hp.openConnection();
    
            System.out.println("== Content ==");
            InputStream input = (InputStream)hpCon.getInputStream();
            BufferedReader br = new BufferedReader(new
                                                   InputStreamReader(input, "gb2312"));
    
            String str = null;
            while (( str = br.readLine() ) != null) {
                System.out.println(str);
            }
            input.close();
        }
    }
       

    接下来要干的活就是从获得的网页内容中提取出汇率表信息了. 网页上显示的格式如下: https://images0.cnblogs.com/blog/188068/201405/082238288075769.jpg

    3.2 提取web表单

    为了存储表单中提取的信息, 建立了一个新类: class RateInfo

    class RateInfo {
        String to;
        // [0]: 现汇买入价 [1]: 现钞买入价
        // [2]: 卖出价     [3]: 中间价 [4]: 基准价
        Double price[] = new Double[5];
    }
       

    具体的实现可以通过两种方式:

    • 正则表达示匹配
    • 借用现有的库, jsoup

    该文主要实现了第一种方式, 这里再次说明一下,在后续的文章中会介绍关于jsoup的使用。

    4 正则表达示匹配获取表单信息

    首先让我们来观察一下需要处理的网页的source code.

    <TABLE BORDER CELLSPACING=0 BORDERCOLOR="#CCCCCC" CELLPADDING=0 WIDTH=777 align="center" height="113">
      <TR bgcolor="#E1FDE8"> 
        <TD WIDTH="121" HEIGHT=28 bgcolor="#E1FDE8"> 
          <DIV ALIGN="center"><b><font color="#000000"><font lang="ZH-CN">货币名称</font></font> 
            </b> </TD>
        <TD WIDTH="133" HEIGHT=21> <DIV ALIGN="center"><b><font color="#000000"><font lang="ZH-CN">现汇买入价</font></font> 
            </b> </TD>
        <TD WIDTH="137" HEIGHT=21> <DIV ALIGN="center"><b><font color="#000000"><font lang="ZH-CN">现钞买入价</font></font> 
            </b> </TD>
        <TD WIDTH="132"><div align="center"><b><font color="#000000"><font lang="ZH-CN">卖出价</font></font></b></div></TD>
        <TD WIDTH="130"><div align="center"><b><font color="#000000">中间价</font></b></div></TD>
        <TD WIDTH="133" HEIGHT=21> <DIV ALIGN="center"><b><font color="#000000">基准价</font> 
            </b> </TD>
      </TR>
      
      <TR bgcolor="#FFFFFF"> 
        <TD HEIGHT=28 valign="middle" bgcolor="#FFFFFF"> 
          <div align="center"><!--?hbmc=美元&topic="--><a href="http://www.usd-cny.com/usd-rmb.htm">美元 USD</a></div></TD>
        <TD HEIGHT=15 align="center" valign="middle"><div align="right">621.8700&nbsp;</div></TD>
        <TD HEIGHT=15 align="center" valign="middle"><div align="right">616.8900&nbsp;</div></TD>
        <TD align="center" valign="middle"><div align="right">624.3700&nbsp;</div></TD>
        <TD align="center" valign="middle"><div align="right">623.1200&nbsp;</div></TD>
        <TD HEIGHT=15 align="center" valign="middle"><div align="right">615.5700&nbsp;</div></TD>
      </TR>
    

    分析发现, 汇率表由大写的TABLE包括起来, 每一行由TR包围, 每一项由TD包围. 因此, 正则表达式为:

    • <TABLE: means enter the table
    • </TABLE: means quit the table
    • <TR: means enter a row
    • </TR: means quit a rwo
    • <TD && href: means first col
    • <TD && ~href: means other cols
    • <TD.*<a href.*?>(.*?)</a>: now "1" means "美元 USD"
    • <TD.*<div.*?>(.*?)</d: now 1 meas the rates

    对于上述字符的识别可以用以下方式进行实现:

    str.startwith(token), where token = "<TABLE" or "</TABLE" or "<TR" or "</TR"
    str.startwith("<TD") && str.indexOf("href) != -1, to recognise the first col
    str.startwith("<TD") && str.indexOf("href) == -1, to recognise the other cols
    
    to extract the unit of the money
    import java.util.regex.*;
    String patt = "<TD.*<a href.*?>\(.*?\)</a>"
    Pattern r = Pattern.compile(patt);
    Matcher m = r.matcher(str);
    m.group(1); // is the result, such as "美元 USD"
    
    用类似的方法可以获得rates
    

    然后编写代码进行实现, 具体实现思路如下:

    • 实现html源代码中关于汇率表的相关内容行的识别
    • 然后, 从特定的行中提取出相应的汇率信息
    class Rate {
        // 从网站:http://www.usd-cny.com/中获取最新的汇率信息
        final static String webSite = "http://www.usd-cny.com/";
    
        // 利用hashtable对不同货币之间的利率进行存储
        //   key: $from+$to, value: $rate
        private static Hashtable rateTable = new Hashtable();
    
        // 从网上自动更新汇率信息
        // 只将前16个具有完整汇率信息的内容进行存储
        public static void update() throws Exception {
            URL hp = new URL(webSite);
            URLConnection hpCon = hp.openConnection();
    
            System.out.println("== Content ==");
            InputStream input = (InputStream)hpCon.getInputStream();
            BufferedReader br = new BufferedReader(new
                                                   InputStreamReader(input, "gb2312"));
    
            String str = null;
            boolean inTable = false;
            int nRows = 0;
            String matchStr = null;
            while (( str = br.readLine() ) != null) {
                str = str.trim();
    
                // 判断是否进入汇率表的势力范围内部
                if (str.startsWith("<TABLE")) {
                    inTable = true;
                    continue;
                }
    
                if (str.startsWith("</TABLE")) {
                    break;
                }
    
                if (inTable == false)
                    continue;
    
                if (str.startsWith("<TR")) {
                    nRows += 1;
                    // 忽略第一行的标题
                    if (nRows == 1) continue;
    
                    // 汇率表的读取只到港币
                    if (nRows == RateInfo.NKINDS+2) break;
    
                    // 获得第一列的完整代码
                    str = br.readLine().trim();
                    str = str + br.readLine().trim();
    
                    // 获取币种缩写
                    String patt = "<TD.*<a href.*?>(.*)</a>";
                    Pattern r = Pattern.compile(patt);
                    Matcher m = r.matcher(str);
                    // matchStr = m.group(1);
                    // 将汉字与缩写进行分离
                    // matchStr = (matchStr.split())[1];
                    if (m.find()) {
                        matchStr = m.group(1);
                        matchStr = (matchStr.split(" "))[1];
                        System.out.println(matchStr);
                    } else {
                        System.out.println("No Match");
                    }
    
                    for (int i = 0; i < RateInfo.NELEM; i++) {
                        str = br.readLine();
                        String pattE = "<TD.*>(.*?)&nbsp;</div>";
                        r = Pattern.compile(pattE);
                        m = r.matcher(str);
                        if (m.find())
                            System.out.println(m.group(1));
                        else
                            System.out.println("No Match");
                    }
                }
            }
            input.close();
        }
        
        // 设置不同货币之间的利率
        //    1 $from * $rate = 1 $to
        public static void setRate(String from, String to, double rate) {
            rateTable.put(from+to, new Double(rate));
        }
    
        public static Double getRate(String from, String to) {
            return 615.65;
            // return (Double) rateTable.get(from + to);
        }
    
        // 将一定量的货币$m, 转变成单位为$to的货币量
        // return: 相应的货币值
        public static Money exchangeRate(Money m, String to) {
            if (m.unit.equals(to)) return new Money(m);
            Double rate = getRate(m.unit, to);
    
            if (rate == null) {
                throw new IllegalArgumentException();
            }
    
            return new Money(m.amount*rate.doubleValue(), to);
        }
    }

    5 总结

    该文实现了利用正则表达式获取html表单信息. 但是, 该方法主要有的不足是: 具有太明显的目的性, 根据具体html代码的特征实现相应的匹配. 为了实现更普遍的方法, 应该对该匹配规则进行改进, 下一篇文章种将对该方法进行进一步的改进.

    Date: 2014-05-07 Wed

    Author: Zhong Xiewei

    Org version 7.8.11 with Emacs version 24

    Validate XHTML 1.0
  • 相关阅读:
    原生JS实现new方法、new一个对象发生的四部、new里面常用的优先级
    svg image标签降级技术
    ReflectionToStringBuilder使用
    记一次未解决的异常:java.lang.NoClassDefFoundError: net/sf/json/JSONObject
    eclipse安装Run-Jetty-Run插件,修改实时生效
    jdbcTemplate:包含占位符的SQL无法打印参数信息
    jdbcTemplate异常:like模糊查询报错(Parameter index out of range (1 > number of parameters)
    Spring整合MyBatis
    springmvc整合slf4j、log4j记录文本日志
    Java环境配置
  • 原文地址:https://www.cnblogs.com/grass-and-moon/p/3717843.html
Copyright © 2011-2022 走看看