美文网首页
golang学习笔记(九)异常、文本、JSON、文件

golang学习笔记(九)异常、文本、JSON、文件

作者: NIIIICO | 来源:发表于2022-11-24 18:22 被阅读0次

一、异常

1、error

errors 包

package main

import (
    "errors"
    "fmt"
)

func main() {
    result, err := MyDiv(1, 0)
    if err != nil {
        fmt.Println("err = ", err)
    } else {
        fmt.Println("result = ", result)
    }

}

func MyDiv(a, b float32) (result float32, err error) {
    if b == 0 {
        // err = fmt.Errorf("分母不能为零")
        err = errors.New("分母不能为零")
    } else {
        result = a / b
    }
    return
}

2、panic

调用panic会导致程序中断

package main

import (
    "fmt"
)

func main() {
    fmt.Println("1")
    fmt.Println("2")
    panic("test")
    fmt.Println("3")
}

3、recover

(1)程序在崩溃时继续运行
(2)recover 仅在延迟函数 defer 中有效
(3)类似于java中的 try/catch

package main

import (
    "fmt"
)

func main() {
    fmt.Println("1")
    test()
    fmt.Println("3")
}

func test() {
    // 在defer中使用recover,如果代码异常,不会崩溃
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()
    panic("panic 导致崩溃")
    fmt.Println("2")
}

二、文本处理

1、字符串操作

strings 包

package main

import (
    "fmt"
    "strings"
)

func main() {
    fmt.Println("\nContains 返回是否包含指定字符串")
    fmt.Println(strings.Contains("hello", "h"))
    fmt.Println(strings.Contains("hello", "a"))

    fmt.Println("\nJoin 将切片通过指定字符串链接起来")
    s := []string{"h", "e", "l", "l", "o"}
    fmt.Println(strings.Join(s, "-"))

    fmt.Println("\nIndex 返回指定字符串的起始位置,不包含返回-1")
    fmt.Println(strings.Index("hello", "h"))
    fmt.Println(strings.Index("hello", "a"))

    fmt.Println("\nRepeat 将字符串重复指定次数")
    fmt.Println(strings.Repeat("hello", 3))

    fmt.Println("\nSplit 将字符串按照指定次字符串拆分,中途相邻两个会被拆分成\"\"")
    fmt.Println(strings.Split("hello", "l"))

    fmt.Println("\nTrim 去掉字符串前后的指定字符串")
    fmt.Println(strings.Trim("hello", "h"))

    fmt.Println("\nFields 去掉字符串前后的空格,并将字符串去除空格拆分")
    fmt.Println(strings.Fields(" he l lo "))
}

2、字符串转换

strconv 包

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // Append:将其他类型转换成字符串后追加到字节数组中
    s := []byte{}
    s = strconv.AppendBool(s, true)
    fmt.Println(string(s))

    // Format:其他类型转换成字符串
    s1 := strconv.FormatBool(true)
    fmt.Println(s1)

    // Format:其他类型转换成字符串
    b1, err := strconv.ParseBool("true")
    fmt.Println(b1, err)
}

3、正则

(1)regexp 包
(2)regexp文档:https://studygolang.com/pkgdoc

单字符:
        .              任意字符(标志s==true时还包括换行符)
        [xyz]          字符族
        [^xyz]         反向字符族
        \d             Perl预定义字符族
        \D             反向Perl预定义字符族
        [:alpha:]      ASCII字符族
        [:^alpha:]     反向ASCII字符族
        \pN            Unicode字符族(单字符名),参见unicode包
        \PN            反向Unicode字符族(单字符名)
        \p{Greek}      Unicode字符族(完整字符名)
        \P{Greek}      反向Unicode字符族(完整字符名)

结合:
        xy             匹配x后接着匹配y
        x|y            匹配x或y(优先匹配x)

重复:
        x*             重复>=0次匹配x,越多越好(优先重复匹配x)
        x+             重复>=1次匹配x,越多越好(优先重复匹配x)
        x?             0或1次匹配x,优先1次
        x{n,m}         n到m次匹配x,越多越好(优先重复匹配x)
        x{n,}          重复>=n次匹配x,越多越好(优先重复匹配x)
        x{n}           重复n次匹配x
        x*?            重复>=0次匹配x,越少越好(优先跳出重复)
        x+?            重复>=1次匹配x,越少越好(优先跳出重复)
        x??            0或1次匹配x,优先0次
        x{n,m}?        n到m次匹配x,越少越好(优先跳出重复)
        x{n,}?         重复>=n次匹配x,越少越好(优先跳出重复)
        x{n}?          重复n次匹配x

分组:
        (re)           编号的捕获分组
        (?P<name>re)   命名并编号的捕获分组
        (?:re)         不捕获的分组
        (?flags)       只是为了设置当前分组的标志,不会进行匹配
        (?flags:re)    设置re段的标志,不捕获的分组

标志的语法为xyz(设置)、-xyz(清楚)、xy-z(设置xy,清楚z),标志如下:
        I              大小写敏感(默认关闭)
        m              ^和$在匹配文本开始和结尾之外,还可以匹配行首和行尾(默认开启)
        s              让.可以匹配\n(默认关闭)
        U              非贪婪的:交换x*和x*?、x+和x+?……的含义(默认关闭)

边界匹配:
        ^              匹配文本开始,标志m为真时,还匹配行首
        $              匹配文本结尾,标志m为真时,还匹配行尾
        \A             匹配文本开始
        \b             单词边界(一边字符属于\w,另一边为文首、文尾、行首、行尾或属于\W)
        \B             非单词边界
        \z             匹配文本结尾

转义序列:
        \a             响铃符(\007)
        \f             换纸符(\014)
        \t             水平制表符(\011)
        \n             换行符(\012)
        \r             回车符(\015)
        \v             垂直制表符(\013)
        \123           八进制表示的字符码(最多三个数字)
        \x7F           十六进制表示的字符码(必须两个数字)
        \x{10FFFF}     十六进制表示的字符码
        \*             字面值'*'
        \Q...\E        反斜线后面的字符的字面值

字符族(预定义字符族之外,方括号内部)的语法:
        x              单个字符
        A-Z            字符范围(方括号内部才可以用)
        \d             Perl字符族
        [:foo:]        ASCII字符族
        \pF            单字符名的Unicode字符族
        \p{Foo}        完整字符名的Unicode字符族

预定义字符族作为字符族的元素:
        [\d]           == \d
        [^\d]          == \D
        [\D]           == \D
        [^\D]          == \d
        [[:name:]]     == [:name:]
        [^[:name:]]    == [:^name:]
        [\p{Name}]     == \p{Name}
        [^\p{Name}]    == \P{Name}

Perl字符族:
        \d             == [0-9]
        \D             == [^0-9]
        \s             == [\t\n\f\r ]
        \S             == [^\t\n\f\r ]
        \w             == [0-9A-Za-z_]
        \W             == [^0-9A-Za-z_]

ASCII字符族:
        [:alnum:]      == [0-9A-Za-z]
        [:alpha:]      == [A-Za-z]
        [:ascii:]      == [\x00-\x7F]
        [:blank:]      == [\t ]
        [:cntrl:]      == [\x00-\x1F\x7F]
        [:digit:]      == [0-9]
        [:graph:]      == [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]
        [:lower:]      == [a-z]
        [:print:]      == [ -~] == [ [:graph:]]
        [:punct:]      == [!-/:-@[-`{-~]
        [:space:]      == [\t\n\v\f\r ]
        [:upper:]      == [A-Z]
        [:word:]       == [0-9A-Za-z_]
        [:xdigit:]     == [0-9A-Fa-f]

示例:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    str := `
<div>1</div>
<div>2</div>
<div>3
4
5</div>
    `

    // 解析规则
    // (.*?)匹配任意字符任意次数,越少越好
    // (?s:())设置括号内的标志为s,s标志可以让 . 匹配\n
    reg, err := regexp.Compile(`<div>(?s:(.*?))</div>`)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 获得所有符合条件的数据
    result1 := reg.FindAllStringSubmatch(str, -1)
    for _, result2 := range result1 {
        fmt.Println(result2[1])
    }

}

三、JSON

encoding/json 包

1、结构体与json操作

(1)要想用json编码,首字母必须大写
(2)可以通过 "json:"name"" 或 `json:"name"` 重命名
(3)通过 `json:",string"` 强制转成string
(4)json转换成结构体时,注意第二个参数是指针类型

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    // 要想用json编码,首字母必须大写
    // 可以通过 "json:\"name\"" 或 `json:"name"`重命名
    Name string `json:"name"`

    // 通过 `json:",string"`强制转成string
    Age int `json:"age,string"`
}

func main() {
    p1 := Person{"LiMing", 18}

    // 将结构体转成json
    // j, e := json.Marshal(p1)
    // 格式化编码
    j, e := json.MarshalIndent(p1, "", " ")
    if e != nil {
        fmt.Println(e)
    } else {
        fmt.Println(string(j))
    }

    var p2 Person
    p2Json := `{"name": "LiMing","age": "18"}`
    // 注意第二个参数是指针
    e2 := json.Unmarshal([]byte(p2Json), &p2)
    if e2 != nil {
        fmt.Println(e2)
    } else {
        fmt.Println(p2)
    }
}

2、map与json操作

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    m1 := make(map[string]interface{})
    m1["name"] = "LiMing"
    m1["age"] = 18

    // j, e := json.Marshal(m1)
    // 格式化编码
    j, e := json.MarshalIndent(m1, "", " ")
    if e != nil {
        fmt.Println(e)
    } else {
        fmt.Println(string(j))
    }

    m2Json := `{"name": "LiMing","age": "18"}`
    m2 := make(map[string]interface{})
    e2 := json.Unmarshal([]byte(m2Json), &m2)
    if e2 != nil {
        fmt.Println(e2)
    } else {
        fmt.Println(m2)
    }
}

四、文件

设备文件:
屏幕 -> 标准输出设备,fmt.Println() // 向标准输出设备写内容
键盘 -> 标准输入设备,fmt.Scan() // 从标准输入设备读取内容

磁盘文件:放在存储设备上的文件
文本文件 -> 用记事本打开,不是乱码
二进制文件 -> 用记事本打开,是乱码

api

(1)标准设备文件os.Stdout,默认已经打开,用户可以直接使用
(2)os.Create(),打开并创建文件,如果文件已经存在,则会清空
(3)Reader.readBytes()可以读到指定字节停止读取,指定字节也会被读进去

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    path := "./demo.txt"

    WriteFile(path)
    ReadFile(path)
    ReadFileLine(path)
}

func WriteFile(path string) {
    // 打开文件,新建文件,如果文件已经存在,就清空文件
    f, e := os.Create(path)
    if e != nil {
        fmt.Println("打开文件失败:", e)
        return
    }

    // 使用完毕关闭文件
    defer f.Close()

    var buf string
    for i := 0; i < 5; i++ {
        buf = fmt.Sprintf("第%d行\n", i+1)
        fmt.Println(buf)
        n, e2 := f.WriteString(buf)
        if e2 != nil {
            fmt.Println("写入内容失败:", e2)
        } else {
            fmt.Println("写入数据:", n)
        }
    }
}

func ReadFile(path string) {
    // 打开文件
    f, e := os.Open(path)
    if e != nil {
        fmt.Println("打开文件失败:", e)
        return
    }

    // 使用完毕关闭文件
    defer f.Close()

    buff := make([]byte, 1024)
    count, err := f.Read(buff)
    if err != nil {
        fmt.Println("文件读取失败:", err)
        return
    }
    fmt.Println(string(buff[:count]))

}

func ReadFileLine(path string) {
    // 打开文件
    f, e := os.Open(path)
    if e != nil {
        fmt.Println("打开文件失败:", e)
        return
    }

    // 使用完毕关闭文件
    defer f.Close()

    r := bufio.NewReader(f)
    for {
        b, err := r.ReadBytes('\n')
        if err != nil {
            if err == io.EOF {
                fmt.Println("文件已经读完了")
                return
            }
            fmt.Println("读取失败:", err)
            return
        }
        fmt.Print(string(b))
    }

}

相关文章

网友评论

      本文标题:golang学习笔记(九)异常、文本、JSON、文件

      本文链接:https://www.haomeiwen.com/subject/poaoxdtx.html