[笔记]Go语言实现同一结构体适配多种消息源

问题:

提供天气信息的网站有很多,每家的数据及格式都不同,为了适配各种不同的天气接口,写了如下程序。

代码如下:

package main

import (
  "encoding/json"
  "errors"
  "fmt"
  "regexp"
  "strconv"
  "strings"
)

var s string = `
{
    "error": 0,
    "status": "success",
    "date": "2015-03-26",
    "results": [
        {
            "test": [
                [
                    "fuck",
                    "shit"
                ],
                {
                    "ao": "xxx"
                },
                "vfe"
            ],
            "currentCity": "郑州",
            "pm25": "95",
            "index": [
                {
                    "title": "穿衣",
                    "zs": "较冷",
                    "tipt": "穿衣指数",
                    "des": "建议着厚外套加毛衣等服装。年老体弱者宜着大衣、呢外套加羊毛衫。"
                },
                {
                    "title": "洗车",
                    "zs": "不宜",
                    "tipt": "洗车指数",
                    "des": "不宜洗车,未来24小时内有雨,如果在此期间洗车,雨水和路上的泥水可能会再次弄脏您的爱车。"
                },
                {
                    "title": "旅游",
                    "zs": "适宜",
                    "tipt": "旅游指数",
                    "des": "温度适宜,又有较弱降水和微风作伴,会给您的旅行带来意想不到的景象,适宜旅游,可不要错过机会呦!"
                },
                {
                    "title": "感冒",
                    "zs": "少发",
                    "tipt": "感冒指数",
                    "des": "各项气象条件适宜,无明显降温过程,发生感冒机率较低。"
                },
                {
                    "title": "运动",
                    "zs": "较不宜",
                    "tipt": "运动指数",
                    "des": "有降水,推荐您在室内进行健身休闲运动;若坚持户外运动,须注意保暖并携带雨具。"
                },
                {
                    "title": "紫外线强度",
                    "zs": "最弱",
                    "tipt": "紫外线强度指数",
                    "des": "属弱紫外线辐射天气,无需特别防护。若长期在户外,建议涂擦SPF在8-12之间的防晒护肤品。"
                }
            ],
            "weather_data": [
                {
                    "date": "周四 03月26日 (实时:12℃)",
                    "dayPictureUrl": "http://api.map.baidu.com/images/weather/day/zhenyu.png",
                    "nightPictureUrl": "http://api.map.baidu.com/images/weather/night/duoyun.png",
                    "weather": "阵雨转多云",
                    "wind": "微风",
                    "temperature": "12 ~ 4℃"
                },
                {
                    "date": "周五",
                    "dayPictureUrl": "http://api.map.baidu.com/images/weather/day/qing.png",
                    "nightPictureUrl": "http://api.map.baidu.com/images/weather/night/qing.png",
                    "weather": "晴",
                    "wind": "微风",
                    "temperature": "16 ~ 8℃"
                },
                {
                    "date": "周六",
                    "dayPictureUrl": "http://api.map.baidu.com/images/weather/day/qing.png",
                    "nightPictureUrl": "http://api.map.baidu.com/images/weather/night/duoyun.png",
                    "weather": "晴转多云",
                    "wind": "微风",
                    "temperature": "22 ~ 9℃"
                },
                {
                    "date": "周日",
                    "dayPictureUrl": "http://api.map.baidu.com/images/weather/day/qing.png",
                    "nightPictureUrl": "http://api.map.baidu.com/images/weather/night/qing.png",
                    "weather": "晴",
                    "wind": "微风",
                    "temperature": "25 ~ 11℃"
                }
            ]
        }
    ]
}
`

// 天气
type Weather struct {
  Error_Code string `json:"error_code"` //错误码  0没有错误
  Status     string `json:"status"`     // 状态描述, success 成功
  Result     Result `json:"result"`     // 天气状况
}

// 天气结果
type Result struct {
  Now         Real
  LivingIndex []Indicate `json:"living_index"` //生活指数
  Future      []ForeCast `json:"future"`       //未来几天的预报,包括当天
}

// 实时报告
type Real struct {
  City          string `json:"city"`           // 城市
  Temperature   string `json:"temperature"`    // 当前温度
  WindDirection string `json:"wind_direction"` // 风向
  WindStrength  string `json:"wind_strength"`  // 风强度
  Humidity      string `json:"humidity"`       // 湿度
  PM25          string `json:"pm25"`           // PM2.5
}

// 预报
type ForeCast struct {
  Temperature string `json:"temperature"` // 温度范围
  Weather     string `json:"weather"`     // 天气  (晴,多云,阴转多云)
  Wind        string `json:"wind"`        // 风向和强度
  Week        string `json:"week"`        // 星期几
  Date        string `json:"date"`        // 日期
}

type Indicate struct {
  Title       string `json:"titile"` // 指数标题
  Status      string `json:"status"` //指数状态 (适宜,不宜)
  Description string `json:"desc"`   //描述信息
}

func NewWeather() *Weather {
  return NewWeatherWithNum(6, 4)
}

func NewWeatherWithNum(livingIndexNum, forecastNum int) *Weather {
  w := &Weather{}
  w.Result.LivingIndex = make([]Indicate, livingIndexNum)
  w.Result.Future = make([]ForeCast, forecastNum)
  return w
}

type ElementExtractor struct {
  Err error
  m   map[string]interface{}
  r   *regexp.Regexp
}

func NewElementExtractor(jsonString string) *ElementExtractor {
  ee := &ElementExtractor{r: regexp.MustCompile(`(.*)\[(\d+)\]+`)}
  ee.Err = json.Unmarshal([]byte(jsonString), &ee.m)
  return ee
}

func (ee *ElementExtractor) ExtractElementByPattern(patten string) (string, error) {
  if ee.Err != nil {
    return "", ee.Err
  }

  var mm map[string]interface{} = ee.m
  var sa []interface{}

  patten = strings.Replace(patten, "][", "].[", -1)

  for _, k := range strings.Split(patten, ".") {
    ki := ee.r.FindStringSubmatch(k)
    if len(ki) == 3 {
      j, _ := strconv.Atoi(ki[2])
      if ki[1] != "" {
        sa = mm[ki[1]].([]interface{})
      }

      switch s := sa[j].(type) {
      case string:
        return s, nil
      case map[string]interface{}:
        mm = s
      case []interface{}:
        sa = sa[j].([]interface{})
      default:
        return fmt.Sprintf("%v", s), nil
      }
    } else {
      switch s := mm[k].(type) {
      case string:
        return s, nil
      case map[string]interface{}:
        mm = s
      default:
        return fmt.Sprintf("%v", s), nil
      }
    }
  }

  ee.Err = errors.New("Pattern Error: " + patten)
  return "", ee.Err
}

func main() {
  ee := NewElementExtractor(s)
  w := NewWeather()

  w.Status, _ = ee.ExtractElementByPattern("status")
  w.Error_Code, _ = ee.ExtractElementByPattern("error")
  w.Result.Now.City, _ = ee.ExtractElementByPattern("results[0].currentCity")
  w.Result.Now.PM25, _ = ee.ExtractElementByPattern("results[0].pm25")
  w.Result.Future[2].Date, _ = ee.ExtractElementByPattern("results[0].weather_data[2].date")
  w.Result.LivingIndex[0].Title, _ = ee.ExtractElementByPattern("results[0].index[0].title")
  w.Result.Future[2].Temperature, _ = ee.ExtractElementByPattern("results[0].weather_data[2].temperature")
  w.Result.Now.PM25, _ = ee.ExtractElementByPattern("results[0].test[0][1]")
  w.Result.Now.WindDirection, _ = ee.ExtractElementByPattern("results[0].test[1].ao")
  w.Result.Now.WindStrength, _ = ee.ExtractElementByPattern("results[0].test[2]")

  if ee.Err != nil {
    fmt.Println(ee.Err)
  } else {
    fmt.Println(w)
  }
}

运行结果:

&{0 success {{郑州  xxx vfe  shit} [{穿衣  } {  } {  } {  } {  } {  }] [{    } {    } {22 ~ 9℃    周六} {    }]}}
时间: 2024-10-05 12:21:52

[笔记]Go语言实现同一结构体适配多种消息源的相关文章

关于c语言中的结构体使用偏移量求值问题

最近在看nginx源码,看到定时器的时候,发现一个结构体利用偏移量求值问题, 结构体相信做c开发的都遇到过,那么不知你对结构体中成员变量偏移这块是如何理解的; 首先我们先看一下nginx中的那个让我迷惑的地方 ev =    (event_t*)((char*)node - offsetof(event_t, timer)); 这里,可以得知道是利用event_t结构体的timer变量,来反求event_t结构体的地址 说明一下: event_t是一个结构体 node 也是一个结构体 timer

C语言中的结构体,结构体数组

C语言中的结构体是一个小难点,下面我们详细来讲一下:至于什么是结构体,结构体为什么会产生,我就不说了,原因很简单,但是要注意到是结构体也是连续存储的,但要注意的是结构体里面类型各异,所以必然会产生内存对齐的问题.也就是内存里面会有空档. 1.结构体的定义和赋值 结构体是可以直接初始化的,在定义的时候,就可以初始化,而且如果你的结构体中恰好有字符数组的话,这个时候初始化是不错的选择,原因很简单,字符数组只能定义的时候直接初始化 后来就不可以了,后来你就只能用strcpy函数来拷贝初始化了. str

浅谈c语言typedef 与结构体指针(个人小经验)

 #include<stdio.h> #include<string.h> typedef struct emp{ char sex[8]; char name[15]; int age; }*emp;//这里我们用typedef把emp这个结构体变成了*emp这种指向结构体成员的结构体指针 /*typedef struct emp{ char sex[8]; char name[15]; int age; }pi,*emp;//为了程序的可读性最好不要这样声明*/ int m

linux 中 C 语言的使用 -- 结构体多态

在 Linux 内核代码,特别是驱动代码中经常见到的用法是使用一个标准结构,后面的代码基于这个结构来实现,类似面向对象的多态特性. 在 C 语言里面借助结构体和函数指针实现的这个功能,这里我们写了个例子,提取了关键代码: #include <stdio.h> struct s_new{ char name[10]; char* (* my_method)(char *name); }; char* powerful(char *name){ printf("%s is powerfu

9.Go语言基础之结构体

Go语言中没有类的概念,也不支持"类"的继承等面向对象的概念. Go语言中通过结构体的内嵌再配合接口,比面向对象具有更高的扩展性和灵活性. 1.类型别名和自定义类型 1.1自定义类型 在Go语言中有一些基本的数据类型,如string,整型,浮点型,布尔等数据类型,Go语言中可以使用type关键字来定义自定义类型. 自定义类型是定义了一个全新的类型.我们可以基于内置的基本类型定义,也可以通过struct定义. //将MyInt定义为int类型 type MyInt int 通过Type关

Go语言基础之结构体

Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念.Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性. 类型别名和自定义类型 自定义类型 在Go语言中有一些基本的数据类型,如string.整型.浮点型.布尔等数据类型, Go语言中可以使用type关键字来定义自定义类型. 自定义类型是定义了一个全新的类型.我们可以基于内置的基本类型定义,也可以通过struct定义.例如: //将MyInt定义为int类型 type MyInt int 通过Type关键字的定义,

黑马程序员 C语言-枚举,结构体,指针

一.枚举 ※枚举变量的定义 前面只是定义了枚举类型,接下来就可以利用定义好的枚举类型定义变量. 跟结构体一样,有3种方式定义枚举变量 1.先定义枚举类型,再定义枚举变量 enum Season {spring, summer, autumn, winter}; enum Season s; 2.定义枚举类型的同时定义枚举变量 enum Season {spring, summer, autumn, winter} s; 3.省略枚举名称,直接定义枚举变量 enum {spring, summer

c语言中的结构体指针类型的cast

1.我们在c语言中会经常碰到强制类型转换. 在这,我介绍一种结构pointer类型转换,但是有前提(有点类似于c++中的继承中的子父对象的cast). 简单的介绍一下: 首先我们要知道一个结构的指针,并且 在这个结构体中,第一个结构成员必须也是一个结构体(最好是结构体类型). 那么我们可以这个结构体指针转换为指向这个结构体中第一个成员结构体的指针. 直接看代码: ************************************ /* struct transform for struct

黑马程序员— C语言基础之结构体、枚举、预处理、typedef的使用

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 本章我们主要来学习之前所学的复杂数据类型中的同样也很重要的结构体和枚举的知识,以及C语言中的预处理,typedef的使用,简单介绍一下static和extern等一些比较杂的知识.在开始本章的新知识学习之前首先我们来学习一下根据变量的作用域的不同C语言一般把变量分为两种,局部变量和全局变量.下面我们来分别比较和体会一下这两种不同的变量类型: 根据变量的作用域,可以分为: 1. 局部变量: a.