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


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

 

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

Table of Contents

  • 1 系列文章地址
  • 2 前言
  • 3 获取实时汇率信息
    • 3.1 获取网页内容
    • 3.2 提取web表单
  • 4 正则表达示匹配获取表单信息
  • 5 总结

1 系列文章地址

  • java 汇率换算器的实现(1)

2 前言

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

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

不同类之间的关系图如下(不是严格按照uml规则绘制的):

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

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();
    }
}
   

接下来要干的活就是从获得的网页内容中提取出汇率表信息了. 网页上显示的格式如下:

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包括起来, 每一行由TR包围, 每一项由TD包围. 因此, 正则表达式为:

货币名称
现汇买入价
现钞买入价
卖出价
中间价
基准价
621.8700 
616.8900 
624.3700 
623.1200 
615.5700 
  • \(.*?\): now "\1" means "美元 USD"
  • \(.*?\)

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

    str.startwith(token), where token = "
    

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

    • 实现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(")) {
                    inTable = true;
                    continue;
                }
    
                if (str.startsWith(")) {
                    break;
                }
    
                if (inTable == false)
                    continue;
    
                if (str.startsWith(")) {
                    nRows += 1;
                    // 忽略第一行的标题
                    if (nRows == 1) continue;
    
                    // 汇率表的读取只到港币
                    if (nRows == RateInfo.NKINDS+2) break;
    
                    // 获得第一列的完整代码
                    str = br.readLine().trim();
                    str = str + br.readLine().trim();
    
                    // 获取币种缩写
                    String patt = "(.*)";
                    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 = "(.*?) ";
                        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