分享
  1. 首页
  2. 文章

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

journeyonmyway · · 4112 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

问题:

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

代码如下:

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°C)", 
 "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°C"
 }, 
 {
 "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°C"
 }, 
 {
 "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°C"
 }, 
 {
 "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°C"
 }
 ]
 }
 ]
}
`
// 天气
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°C 周六} { }]}}

有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:journeyonmyway

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

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
4112 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏