GO WEB 学习笔记(五)文本处理

文章目录

  • XML处理
  • JSON处理
  • 正则处理
  • 模板处理
  • 文件操作
  • 字符串处理

XML处理

  1. 首先XML作为一种数据交换和信息传递格式在如今得web服务日益广泛的应用,所以xml文本的解析在如今也是至关重要
  2. 解析XML
  • 如何解析XML文件呢,go自带有XML包来解析,其中Unmarshall这个函数可以解析:func Unmarshall(data []byte, v interface{}) error
    • data接收的是XML数据流
    • v是需要输出的结构
  • XML本质上是一种树形的数据格式,我们可以定义与之匹配的struct类型,通过xml.Unmarshall将xml中的数据解析成对应的struct对象。

<servers version="1">
<server>
    <serverName>chengxupangserverName>
    <serverIP>127.0.0.1serverIP>
server>
servers>
import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
)

type Recurlyservers struct {
	XMLName xml.Name `xml:"servers"`
	Version string   `xml:"version,attr"`
	Svs     []server `xml:"server"`
}

type server struct {
	XMLName    xml.Name `xml:"server"`
	ServerName string   `xml:"serverName"`
	ServerIP   string   `xml:"serverIP"`
}

func main() {
	file, err := os.Open("main/servers.xml")
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}
	defer file.Close()
	data, err := ioutil.ReadAll(file)
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}
	v := Recurlyservers{}
	err = xml.Unmarshal(data, &v)
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}
	fmt.Println(v)
}
  • 输出结果就是这个
    在这里插入图片描述
  • 根据上面的例子可以看到xml.Unmarshal可以完成xml的解析,然后再映射到对应的实体类上,下面我们就来看看这个底层代码
  • 首先来看看这个函数 ,第一个参数是XML的数据流,第二个参数是存储对应的类型,目前只支持struct,slice,string
    在这里插入图片描述
  • 然后思考一个问题,解析的时候,XML元素是怎么跟字段对应起来的?
  • 这里是有个优先级读取流程的,首先会先读取struct tag,如果没有,那么就会对应字段名。必须注意一点的是,解析的时候,tag、字段名、XML元素都是大小写敏感的,所以必须一一对应字段。
  • go语言具有反射机制,可以利用这里tag信息将xml文件中的数据反射成对应的struct对象。
  • 但是数据反射也是需要遵循规则的,下面就来看看有哪些规则:
    • 如果struct的一个字段是string或者[]byte类型,且它的tag含有",innerxml",Unmarshal会将此字段所对应的元素内所有内嵌的原始xml累加到此字段上,如上面例子中的Description定义。最后输出Shanghai_VPN127.0.0.1Beijing_VPN127.0.0.2。
    • 如果struct中有一个叫做XMLName,且类型为xml.Name字段,那么在解析的时候就会保存这个element的名字到该字段,如上面例子中的servers。
    • 如果某个struct字段的tag定义中含有XML结构中element的名称,那么解析的时候就会把相应的element值赋值给该字段,如上servername和serverip定义。
    • 如果某个struct字段的tag定义中含有",attr",那么解析的时候就会将该结构所对应的element与字段同名的属性的值赋值给该字段,如上version定义。
    • 如果某个struct字段的tag定义形如"a>b>c",则解析的时候,会将XML结构a中的子结构b的c元素的值赋值给该字段。
    • 如果某个struct字段的tag定义了"-",那么不会为该字段解析匹配任何xml数据。
    • 如果struct字段后面的tag定义了",any",它的子元素在不满足其他规则的时候就会匹配到这个字段。
    • 如果某个XML元素包含一条或者多条注释,那么这些注释将被累加到第一个tag含有",comments"的字段上,这个字段的类型可能是[]byte或string,如果没有这样的字段存在,那么注释将会被抛弃。
  1. 输出XML
  • 假设我们不知需要解析对应的XML文件,我们还需要生成XML文件,那么又需要怎么实现呢?
  • XML包提供了两个函数来解决我们对应的问题,这两个函数的第一个参数都是用来生成XML的结构定义类型数据,都是返回生成的XML数据流
    • func Marshal(v interface{}) ([]byte, error)
    • func MarshalIndent(v interface{}, prefix, indent string)([]byte, error)
  • 下面我们看看测试代码
import (
	"encoding/xml"
	"fmt"
	"os"
)

type Recurlyservers struct {
	XMLName xml.Name `xml:"servers"`
	Version string   `xml:"version,attr"`
	Svs     []server `xml:"server"`
}

type server struct {
	XMLName    xml.Name `xml:"server"`
	ServerName string   `xml:"serverName"`
	ServerIP   string   `xml:"serverIP"`
}

func main() {
	v := Recurlyservers{Version: "2"}
	v.Svs = append(v.Svs, server{v.XMLName, "chengxupang2", "127.0.0.1"})
	out, err := xml.MarshalIndent(v, "123", "")
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}
	os.Stdout.Write([]byte(xml.Header))
	os.Stdout.Write(out)
}
  • 运行打印之后的效果是这样的:
    GO WEB 学习笔记(五)文本处理_第1张图片
  • 和之前定义的文件格式一模一样,之所以会有os.Stdout.Write([]byte(xml.Header))这句代码的出现,是因为xml.MarshalIndent或者xml.Marshal输出的信息都是不带XML头的,为了生成正确的XML文件,我们使用了XML包预定义的Header变量。
  • 虽然知道了用法,但是有个问题,Marshal函数接收的参数v是interface{}类型的,即它可以接受任意类型的参数,那么xml包根据什么规则来生成相应的XML文件呢?
  • 下面我们就来说一说这些规则:
    • 如果v是array或者slice,那么输出每一个元素,类似value。
    • 如果v是指针,那么会Marshal指针指向的内容,如果指针为空,什么都不输出。
    • 如果v是interface,那么就处理interface所包含的数据。
    • 如果v是其他数据类型,就会输出这个数据类型所拥有的字段信息。
  • 但是生成的XML文件中的element的名字又是根据什么决定的呢?
  • 也是有特定的规则来决定,并且元素的名称有一个优先级,元素名会按照下面的优先级来从struct 结构体来获取:
    • 如果v是struct,tag中定义为XMLName的字段。
    • 通过strcut中字段的tag来获取。
    • 通过strcut的字段名用来获取。
    • Marshall的类型名称。
  • 那么我们应如何设置struct中字段的tag信息以控制最终xml文件的生成呢?
    • XMLName不会被输出。
    • tag中含有"-"的字段不会输出。
    • tag中含有"name,attr",会以name作为属性名,字段值作为值输出为这个XML元素的属性,如上version字段所描述。
    • tag中含有",attr",会以这个struct的字段名作为属性名输出为XML元素的属性,类似上一条,只是这个name默认是字段名。
    • tag中含有",chardata",输出为xml的character data,而非element。
    • tag中含有",innerxml",将会被原样输出,而不会进行常规的编码过程。
    • tag中含有",comment",将被当作xml注释来输出,而不会进行常规的编码过程,字段值中不能含有"–"字符串。
    • tag中含有"omitempty",如果该字段的值为空值,那么该字段就不会被输出到XML,空值包括:false、0、nil指针或nil接口,任何长度为0的array、slice、map或者string。
    • tag中含有"a>b>c",那么就会循环输出三个元素a包含b、b包含c

JSON处理

  1. Json 是现在web中比较常用的前后端交互的数据传输格式,因为具有自我描述性且易于阅读,并且因为更加轻便和更容易解析,所以很多开放平台基本上都是采用了JSON作为其数据交互的接口。
  2. 解析JSON
  • 首先先写个字符串示例,后面的例子都根据这个来进行解析
{
		"userName":"chengxupang",
		"age":18
}
  • 解析到结构体
    • 通过json包中的Unmarshal 函数进行解析:func Unmarshal(data []byte, v interface{}) error
    • 通过下面的示例代码,我们发现定义了与JSON数据对应的结构体,数组对应slice,字段名对应JSON里面的key,但是在解析的时候,如何将JSON数据与struct字段相匹配呢?
    • 例如JSON的key是userName,那么怎么找对应的字段呢?
    • 首先查找tag含有userName的可导出的struct字段(首字母大写)
    • 其次查找字段名是userName的导出字段
    • 最后查找类似 userName 或者 userName 这类除首字母之外,其他大小写不敏感的导出字段。
import (
	"encoding/json"
	"fmt"
)

type user struct {
	UserName string
	Age      int64
}

func main() {
	var u user
	jsonStr := `{
		"userName":"chengxupang",
		"age":18
	}`
	json.Unmarshal([]byte(jsonStr), &u)
	fmt.Println(u)
}
  • 解析到Interface
    • 上面的那种解析方式是在我们已经知晓被解析的JSON数据结构的前提下采用的方案,如果我们不知道被解析的数据格式,又应当如何解析呢?
    • 我们知道interface{}可以用来存储任意数据类型的对象,这种数据结构正好用于存储解析的未知结构的JSON数据的结果。JSON包中采用map[string]interface{}和[]interface{}结构来存储任意的JSON对象和数组。
    • 下面是示例代码
import (
	"encoding/json"
	"fmt"
)

type user struct {
	UserName string
	Age      int64
}

func main() {
	var u interface{}
	jsonStr := `{
		"userName":"chengxupang",
		"age":18
	}`
	json.Unmarshal([]byte(jsonStr), &u)
	fmt.Println(u)
}
  1. 生成JSON
  • 开发很多应用时,最后都要输出JSON数据串,那么如何来处理呢?JSON包通过Marshal函数来处理,函数定义如下:func Marshal(v interface{}) ([]byte, error)
import (
	"encoding/json"
	"fmt"
)

type user struct {
	UserName string
	Age      int64
}

func main() {
	str, err := json.Marshal(user{"chengxupang2", 12})
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(str))
}

在这里插入图片描述

  • 我们看到,上面的输出字段名都是大写的,如果你想用小写的怎么办呢?把结构体的字段名改成小写的?JSON输出的时候必须注意,只有导出的字段才会被输出,如果修改字段名,那么就会发现什么都不会输出,所以必须通过struct tag定义来实现。
    GO WEB 学习笔记(五)文本处理_第2张图片
  • 但是在定义struct tag的时候需要注意以下几点:
    • 如果字段的tag是"-",那么这个字段不会输出到JSON。
    • 如果tag中带有自定义名称,那么这个自定义名称会出现在JSON的字段名中,例如上面例子中的serverName。
    • 如果tag中带有"omitempty"选项,那么如果该字段值为空,就不会输出到JSON串中。
    • 如果字段类型是bool、string、int、int64等,而tag中带有",string"选项,那么这个字段在输出到JSON的时候会把该字段对应的值转换成JSON字符串。
  • Marshal 函数只有在转换成功的时候才会返回数据,在转换的过程中,需要注意以下几点:
    • JSON对象只支持string作为key,所以要编码一个map,那么必须是map[string]T这种类型(T是Go语言中任意的类型)。
    • Channel、complex和function不能被编码成JSON。
    • 嵌套的数据不能编码,不然会让JSON编码进入死循环。
    • 指针在编码的时候会输出指针指向的内容,而空指针会输出null。

正则处理

模板处理

文件操作

  1. 在任何计算机设备中,文件是都是必须的对象,而在Web编程中,文件的操作一直是Web程序员经常遇到的问题,文件操作在Web应用中是必须的,非常有用,我们经常遇到生成文件目录、文件(夹)编辑等操作。
  2. 目录操作
    • 创建名称为name的目录,权限设置是perm:func Mkdir(name string, perm FileMode) error
    • 根据path创建多级子目录 :func MkdirAll(path string, perm FileMode) error
    • 删除名称为name的目录,当目录下有文件或者其他目录会出错:func Remove(name string) error
    • 根据path删除多级子目录,如果path是单个名称,那么该目录不删除:func RemoveAll(path string) error
  3. 建立与打开文件
    • 根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666的文件,返回的文件对象是可读写的 :func Create(name string) (file *File, err Error)
    • 根据文件描述符创建相应的文件,返回一个文件对象 :func NewFile(fd uintptr, name string) *File
    • 该方法打开一个名称为name的文件,但是只读方式,内部实现调用了OpenFile :func Open(name string) (file *File, err Error)
    • 打开名称为name的文件,flag是打开的方式,只读、读写等,perm是权限 : func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
  4. 写文件
    • 写入byte类型的信息到文件 :func (file *File) Write(b []byte) (n int, err Error)
    • 在指定位置开始写入byte类型的信息:func (file *File) WriteAt(b []byte, off int64) (n int, err Error)
    • 写入string信息到文件 :func (file *File) WriteString(s string) (ret int, err Error)
  5. 读文件
    • 读取数据到b中 :func (file *File) Read(b []byte) (n int, err Error)
    • 从off开始读取数据到b中 :func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
  6. 删除文件
    • 调用该函数就可以删除文件名为name的文件 :func Remove(name string) Error

字符串处理

  1. 我们在Web开发中经常用到字符串,包括用户的输入,数据库读取的数据等,经常需要对字符串进行分割、连接、转换等操作
  2. 可以操作字符串的函数 ,利用strings这个包
    • 字符串s中是否包含substr,返回bool值 :func Contains(s, substr string) bool
    • 字符串链接,把slice a通过sep链接起来 :func Join(a []string, sep string) string
    • 在字符串s中查找sep所在的位置,返回位置值,找不到返回-1 :func Index(s, sep string) int
    • 重复s字符串count次,最后返回重复的字符串 :func Repeat(s string, count int) string
    • 在s字符串中,把old字符串替换为new字符串,n表示替换的次数,小于0表示全部替换 :func Replace(s, old, new string, n int) string
    • 把s字符串按照sep分割,返回slice :func Split(s, sep string) []string
    • 在s字符串中去除cutset指定的字符串 : func Trim(s string, cutset string) string
    • 去除s字符串的空格符,并且按照空格分割返回slice :func Fields(s string) []string

你可能感兴趣的:(go,golang,前端,学习)