Golang系列(八)之文本处理

1. JSON处理

JSON是一种轻量级的数据交换语言。

1.1. 解析JSON[Unmarshal(data []byte, v interface{})]

1.1.1. Unmarshal源码

/src/encoding/json/decode.go

func Unmarshal(data []byte, v interface{}) error {
    // Check for well-formedness.
    // Avoids filling out half a data structure
    // before discovering a JSON syntax error.
    var d decodeState
    err := checkValid(data, &d.scan)
    if err != nil {
        return err
    }
    d.init(data)
    return d.unmarshal(v)
}
...
func (d *decodeState) unmarshal(v interface{}) (err error) {
    defer func() {
        if r := recover(); r != nil {
            if _, ok := r.(runtime.Error); ok {
                panic(r)
            }
            err = r.(error)
        }
    }()
    rv := reflect.ValueOf(v)
    if rv.Kind() != reflect.Ptr || rv.IsNil() {
        return &InvalidUnmarshalError{reflect.TypeOf(v)}
    }
    d.scan.reset()
    // We decode rv not rv.Elem because the Unmarshaler interface
    // test must be applied at the top level of the value.
    d.value(rv)
    return d.savedError
}
1.1.2. 解析到结构体
package main
import (
    "encoding/json"
    "fmt"
)
type Server struct {
    ServerName string
    ServerIP   string
}
type Serverslice struct {
    Servers []Server
}
func main() {
    var s Serverslice
    str := `{"servers":
    [{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},
    {"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}`
    err:=json.Unmarshal([]byte(str), &s)
    if err!=nil{
        fmt.Println(err)
    }
    fmt.Println(s)
}

说明

JSON格式与结构体一一对应,Unmarshal方法即将JSON文本转换成结构体。只会匹配结构体中的可导出字段,即首字母大写字段(类似java的public),匹配规则如下:json的key为Foo为例

  1. 先查找struct tag中含有Foo的可导出的struct字段(首字母大写)
  2. 其次查找字段名为Foo的可导出字段。
  3. 最后查找类似FOO或者FoO这类除首字母外,其他大小写不敏感的可导出字段。
1.1.3. 解析到interface

1.2. 生成JSON[Marshal(v interface{})]

1.2.1. Marshal源码

/src/encoding/json/encode.go

func Marshal(v interface{}) ([]byte, error) {
    e := &encodeState{}
    err := e.marshal(v)
    if err != nil {
        return nil, err
    }
    return e.Bytes(), nil
}
...
func (e *encodeState) marshal(v interface{}) (err error) {
    defer func() {
        if r := recover(); r != nil {
            if _, ok := r.(runtime.Error); ok {
                panic(r)
            }
            if s, ok := r.(string); ok {
                panic(s)
            }
            err = r.(error)
        }
    }()
    e.reflectValue(reflect.ValueOf(v))
    return nil
}
1.2.2. 使用方法
package main
import (
    "encoding/json"
    "fmt"
)
type Server struct {
    ServerName string `json:"serverName,string"`
    ServerIP   string `json:"serverIP,omitempty"`
}
type Serverslice struct {
    Servers []Server `json:"servers"`
}
func main() {
    var s Serverslice
    s.Servers = append(s.Servers, Server{ServerName: "Shanghai_VPN", ServerIP: "127.0.0.1"})
    s.Servers = append(s.Servers, Server{ServerName: "Beijing_VPN", ServerIP: "127.0.02"})
    b, err := json.Marshal(s)
    if err != nil {
        fmt.Println("JSON ERR:", err)
    }
    fmt.Println(string(b))
}
1.2.3. 说明

Marshal方法将结构体转换成json文本,匹配规则如下:

  1. 如果字段的tag是“-”,那么该字段不会输出到JSON。
  2. 如果tag中带有自定义名称,那么该自定义名称会出现在JSON字段名中。例如例子中的“serverName”
  3. 如果tag中带有“omitempty”选项,那么如果该字段值为空,就不会输出到JSON中。
  4. 如果字段类型是bool,string,int,int64等,而tag中带有“,string”选项,那么这个字段在输出到JSON的时候会把该字段对应的值转换成JSON字符串。

注意事项:

  1. Marshal只有在转换成功的时候才会返回数据,JSON对象只支持string作为key,如果要编码一个map,那么必须是map[string]T这种类型。(T为任意类型)
  2. Channel,complex和function不能被编码成JSON。
  3. 嵌套的数据不能编码,会进入死循环。
  4. 指针在编码时会输出指针指向的内容,而空指针会输出null。

2. 文件操作

更多文件操作见Go的os包。

2.1. 目录操作

  • func Mkdir(name string, perm FileMode) error
    创建名称为 name 的目录,权限设置是 perm,例如 0777

  • func MkdirAll(path string, perm FileMode) error
    根据 path 创建多级子目录,例如 astaxie/test1/test2。

  • func Remove(name string) error
    删除名称为 name 的目录,当目录下有文件或者其他目录是会出错
  • func RemoveAll(path string) error
    根据 path 删除多级子目录,如果 path 是单个名称,那么该目录不删除

2.2. 文件操作

2.2.1. 建立与打开文件

新建文件:

  • func Create(name string) (file *File, err Error)
    根据提供的文件名创建新的文件,返回一个文件对象,默认权限是 0666 的文件,返回的文件对象是可读写的。
  • * func NewFile(fd uintptr, name string) *File*
    根据文件描述符创建相应的文件,返回一个文件对象

打开文件:

  • func Open(name string) (file *File, err Error)
    该方法打开一个名称为 name 的文件,但是是只读方式,内部实现其实调用了 OpenFile。
  • func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
    打开名称为 name 的文件,flag 是打开的方式,只读、读写等,perm 是权限
2.2.2. 写文件

写文件函数:

  • func (file *File) Write(b []byte) (n int, err Error)
    写入 byte 类型的信息到文件
  • func (file *File) WriteAt(b []byte, off int64) (n int, err Error)
    在指定位置开始写入 byte 类型的信息
  • func (file *File) WriteString(s string) (ret int, err Error)
    写入 string 信息到文件
package main
import (
    "fmt"
    "os"
)
func main() {
    userFile := "test.txt"
    fout, err := os.Create(userFile)
    defer fout.Close()
    if err != nil {
        fmt.Println(userFile, err)
        return
    }
    for i := 0; i < 10; i++ {
        fout.WriteString("Just a test!\r\n")
        fout.Write([]byte("Just a test!\r\n"))
    }
}
2.2.3. 读文件

读文件函数:

  • func (file *File) Read(b []byte) (n int, err Error)
    读取数据到 b 中

  • func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
    从 off 开始读取数据到 b 中

package main
import (
    "fmt"
    "os"
)
func main() {
    userFile := "text.txt"
    fl, err := os.Open(userFile)
    defer fl.Close()
    if err != nil {
        fmt.Println(userFile, err)
        return
    }
    buf := make([]byte, 1024)
    for {
        n, _ := fl.Read(buf)
        if 0 == n {
            break
        }
        os.Stdout.Write(buf[:n])
    }
}
2.2.4. 删除文件

Go 语言里面删除文件和删除文件夹是同一个函数

  • func Remove(name string) Error
    调用该函数就可以删除文件名为 name 的文件

3. 字符串处理

字符串操作涉及的标准库有stringsstrconv两个包

3.1. 字符串操作

函数说明
func Contains(s, substr string) bool字符串 s 中是否包含 substr,返回 bool 值
func Join(a []string, sep string) string字符串链接,把 slice a 通过 sep 链接起来
func Index(s, sep string) int在字符串 s 中查找 sep 所在的位置,返回位置值,找不到返回-1
func Repeat(s string, count int) string重复 s 字符串 count 次,最后返回重复的字符串
func Replace(s, old, new string, n int) string在 s 字符串中,把 old 字符串替换为 new 字符串,n 表示替换的次数,小于 0 表示全部替换
func Split(s, sep string) []string把 s 字符串按照 sep 分割,返回 slice
func Trim(s string, cutset string) string在 s 字符串中去除 cutset 指定的字符串
func Fields(s string) []string去除 s 字符串的空格符,并且按照空格分割返回 slice

3.2. 字符串转换

1、Append 系列函数将整数等转换为字符串后,添加到现有的字节数组中

package main
import (
    "fmt"
    "strconv"
)
func main() {
    str := make([]byte, 0, 100)
    str = strconv.AppendInt(str, 4567, 10)
    str = strconv.AppendBool(str, false)
    str = strconv.AppendQuote(str, "abcdefg")
    str = strconv.AppendQuoteRune(str, '单')
    fmt.Println(string(str))
}

2、Format 系列函数把其他类型的转换为字符串

package main
import (
    "fmt"
    "strconv"
)
func main() {
    a := strconv.FormatBool(false)
    b := strconv.FormatFloat(123.23, 'g', 12, 64)
    c := strconv.FormatInt(1234, 10)
    d := strconv.FormatUint(12345, 10)
    e := strconv.Itoa(1023)
    fmt.Println(a, b, c, d, e)
}

3、Parse 系列函数把字符串转换为其他类型

package main
import (
    "fmt"
    "strconv"
)
func main() {

    a, err := strconv.ParseBool("false")
    if err != nil {
        fmt.Println(err)
    }
    b, err := strconv.ParseFloat("123.23", 64)
    if err != nil {
        fmt.Println(err)
    }
    c, err := strconv.ParseInt("1234", 10, 64)
    if err != nil {
        fmt.Println(err)
    }
    d, err := strconv.ParseUint("12345", 10, 64)
    if err != nil {
        fmt.Println(err)
    }
    e, err := strconv.Itoa("1023")
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(a, b, c, d, e)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值