文本处理(有关go web方面)

文本处理 3.21

本文基本摘录至https://learnku.com/docs/build-web-application-with-golang/073-regular-processing/3197,仅供学习,如果有需要学习web的同学可以看这个,不懂的再来看我的,我的仅作补充

文本处理是什么?

通常情况下,我们作为设置服务器的,需要对客户端发送过来的文本文件进行解析/对数据进行验证(验证码)/对关键词进行提取(搜索引擎)/除去其他无关信息/对一些信息进行安全处理(扫黄?)/接收到的信息是否符合业务逻辑

正则判断

我想既然我不会设计正则表达式,那么我想让chatgpt帮我实现

嗯,我只是想一下

但其实还是要会一点点东西

不然那个机器人打出来我都看不懂

还是了解一下正则表达式的基本符号吧(可以结合例子来看,看那个太枯燥了)

  1. 匹配单个字符:

    • .:匹配除换行符之外的任意单个字符。
    • [abc]:匹配字符集合中的任意一个字符,例如匹配a、b或c。
  2. 量词:

    • *:匹配前面的字符零次或多次。
    • +:匹配前面的字符一次或多次。
    • ?:匹配前面的字符零次或一次。
    • {n}:匹配前面的字符恰好n次。
    • {n,}:匹配前面的字符至少n次。
    • {n,m}:匹配前面的字符至少n次但不超过m次。
  3. 位置锚点:

    • ^:匹配输入字符串的开始位置。
    • $:匹配输入字符串的结束位置。
  4. 特殊字符转义:

    • \:用于转义特殊字符,使其成为普通字符。例如,\.匹配句点字符.。
  5. 字符类别简写:

    • \d:匹配数字字符,相当于[0-9]。
    • \w:匹配单词字符(字母、数字、下划线),相当于[a-zA-Z0-9_]。
    • \s:匹配空白字符(空格、制表符、换行符等)。
    • \D、\W、\S:分别是\d、\w、\s的反义。
  6. 分组和捕获:

    • ():用于创建捕获组,将匹配的内容分组。
    • (?:):非捕获分组,不会存储匹配结果。
  7. 选择符:

    • |:用于在多个模式之间选择匹配其中之一。
  8. 反义:

    • [^]:匹配除括号中字符之外的任意一个字符。
  9. 其他常用语法:

    • *?、+?、??:非贪婪匹配,尽可能少地匹配字符。
    • \b、\B:单词边界和非单词边界。

常见的正则表达式:

1.匹配邮箱地址:

\w+@\w+\.\w+

\w+是用来匹配单个或多个字母,数字或下划线,也就是说

\w+可以匹配字符串"19366566265safa_saf"。\w+匹配一个或多个字母、数字或下划线字符,因此它能够匹配字符串中的数字、字母和下划线部分。

@用来匹配@符号

注意:正则表达式是一个整体,+不是用来连接的,而只是用来表明可以接收单个或多个(在原本的含义上)

2.匹配URL:

https?://\w+(\.\w+)+

?是用来表示匹配前面的字符(单个)零次或者一次,也就是协议只有两种https/http

通常一个域名

https://chat.openai.com/c/f378fb54-707b-4412-8123-540bb47735ad

https?://\w+(\.\w+)+(/.*)?

需要修改成这样

(/.*)?注意?之前是有个括号的,.表示匹配除了换行符以外的字符,*****表示多次

类似于这样子他会有很多个

3.匹配日期

\d{4}-\d{2}-\d{2}

我们可以观察到我们的日期的格式是

20040819

这个就不多解释了

4.匹配HTML标签

<[^>]+>

两边的< >是用来匹配<>这个不多说

\^\>是用来匹配除了>的的任何字符,然后后面跟着一个+说明可以匹配很多

5.匹配手机号码:

go 复制代码
regexCopy code
1[3-9]\d{9}

这个正则表达式匹配中国大陆手机号码,其中1匹配手机号码的开头,[3-9]匹配第二位数字(3至9中的一个),\d{9}匹配后面的9位数字。

回归正题,我们来看一下go语言中regexp包,这个是和匹配正则表达式相关的

go 复制代码
func Match(pattern string, b []byte) (matched bool, error error)
func MatchReader(pattern string, r io.RuneReader) (matched bool, error error)
func MatchString(pattern string, s string) (matched bool, error error)
/*
三个输入源分别是byte slice,RuneReader,string
patter就是输入源
*/

下面我们来举个例子,

go 复制代码
func IsIP(ip string) (b bool) {
    if m, _ := regexp.MatchString("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$", ip); !m {
        
        return false
    }
    return true
}

/Pv4地址的范围是0.0.0.0到255.255.255.255 $表示结束
\.这里查了chatgpt,就是说因为.本身表示的是匹配除了.之外的字符,但是我偏偏就需要匹配. 但是\也是一个特殊字符,他不能单独使用,例如\n对吧

所以我们需要使用\/

这里我是在goLand上面进行了一个实验的,大家可以做一下,加强对这个函数的理解,代码不用全部打

go 复制代码
func main() {
    if len(os.Args) == 1 {
        fmt.Println("Usage: regexp [string]")
        os.Exit(1)
    } else if m, _ := regexp.MatchString("^[0-9]+$", os.Args[1]); m {
        fmt.Println("数字")
    } else {
        fmt.Println("不是数字")
    }
}

我一开始也没有弄懂os.Args什么意思,我是个小菜鸡

chatgpt回答:

os包主要用于处理命令行参数和退出程序。

os.Args 是一个字符串切片,其中存储了命令行参数。os.Args[0] 存储了程序的名称,而后续的元素存储了传递给程序的命令行参数。

这个要做实验的话需要用到我们的终端(也就是cmd),不能直接使用run

通过正则来获取内容

go 复制代码
package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "regexp"
    "strings"
)

func main() {
    resp, err := http.Get("http://www.baidu.com")
    if err != nil {
        fmt.Println("http get error.")
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("http read error")
        return
    }

    src := string(body)

    // 将 HTML 标签全转换成小写
    re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
    src = re.ReplaceAllStringFunc(src, strings.ToLower)

    // 去除 STYLE
    re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
    src = re.ReplaceAllString(src, "")

    // 去除 SCRIPT
    re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
    src = re.ReplaceAllString(src, "")

    // 去除所有尖括号内的 HTML 代码,并换成换行符
    re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
    src = re.ReplaceAllString(src, "\n")

    // 去除连续的换行符
    re, _ = regexp.Compile("\\s{2,}")
    src = re.ReplaceAllString(src, "\n")

    fmt.Println(strings.TrimSpace(src))
}

这个大家可以直接复制这段代码然后直接运行

大概意思就是将网页中的HTML文件转换成我们想要得到的信息

然后他会有这么几个方法:

go 复制代码
func Compile(expr string) (*Regexp, error)
func CompilePOSIX(expr string) (*Regexp, error)
func MustCompile(str string) *Regexp
func MustCompilePOSIX(str string) *Regexp

前面我们都是新建一个Regexp,然后还可以辅助操作我们得到的字符串

go 复制代码
func (re *Regexp) Find(b []byte) []byte
func (re *Regexp) FindAll(b []byte, n int) [][]byte
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
func (re *Regexp) FindAllString(s string, n int) []string
func (re *Regexp) FindAllStringIndex(s string, n int) [][]int
func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string
func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int
func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte
func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int
func (re *Regexp) FindIndex(b []byte) (loc []int)
func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int)
func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int
func (re *Regexp) FindString(s string) string
func (re *Regexp) FindStringIndex(s string) (loc []int)
func (re *Regexp) FindStringSubmatch(s string) []string
func (re *Regexp) FindStringSubmatchIndex(s string) []int
func (re *Regexp) FindSubmatch(b []byte) [][]byte
func (re *Regexp) FindSubmatchIndex(b []byte) []int

简化之后,主要就是使用这几个方法

go 复制代码
func (re *Regexp) Find(b []byte) []byte
func (re *Regexp) FindAll(b []byte, n int) [][]byte
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte
func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int
func (re *Regexp) FindIndex(b []byte) (loc []int)
func (re *Regexp) FindSubmatch(b []byte) [][]byte
func (re *Regexp) FindSubmatchIndex(b []byte) []int

然后下面的这个实验部分我还是老老实实的打了的,毕竟要了解一下

go 复制代码
package main

import (
	"fmt"
	"regexp"
)

func main() {
	a := "I am learning Go language"
	re, _ := regexp.Compile("[a-z]{2,4}")
	/*
		找到第一个小写字母 2-4个
	*/
	one := re.Find([]byte(a))
	fmt.Println("Find:", string(one))
	all := re.FindAll([]byte(a), -1)
	//FindAll返回的是当前字符串UTF表中的序号
	fmt.Println("FindAll:", all)
	// 查找符合条件的 index 位置, 开始位置和结束位置
	index := re.FindIndex([]byte(a))
	fmt.Println("FindIndex", index)

	// 查找符合条件的所有的 index 位置,n 同上
	allindex := re.FindAllIndex([]byte(a), -1)
	fmt.Println("FindAllIndex", allindex)

	re2, _ := regexp.Compile("am(.*)lang(.*)")

	// 查找 Submatch, 返回数组,第一个元素是匹配的全部元素,第二个元素是第一个 () 里面的,第三个是第二个 () 里面的
	// 下面的输出第一个元素是 "am learning Go language"
	// 第二个元素是 " learning Go ",注意包含空格的输出
	// 第三个元素是 "uage"
	submatch := re2.FindSubmatch([]byte(a))
	fmt.Println("FindSubmatch", submatch)
	for _, v := range submatch {
		fmt.Println(string(v))
	}

	// 定义和上面的 FindIndex 一样
	submatchindex := re2.FindSubmatchIndex([]byte(a))
	fmt.Println(submatchindex)

	// FindAllSubmatch, 查找所有符合条件的子匹配
	submatchall := re2.FindAllSubmatch([]byte(a), -1)
	fmt.Println(submatchall)

	// FindAllSubmatchIndex, 查找所有字匹配的 index
	submatchallindex := re2.FindAllSubmatchIndex([]byte(a), -1)
	fmt.Println(submatchallindex)

}

这个后面的我没有很弄懂,但是我感觉我现在弄懂了也没有什么意义

然后他解释一个Expand

go 复制代码
func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte
func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte
go 复制代码
package main

import (
	"fmt"
	"regexp"
)

func main() {

	src := []byte(`
        call hello alice
        hello bob
        call hello eve
    `)
	pat := regexp.MustCompile(`(?m)(call)\s+(?P<cmd>\w+)\s+(?P<arg>.+)\s*$`)
    /*
    这里创建了一个字符串(正则表达式),匹配类似函数调用的字符串
    */
	res := []byte{}//用来存储最终的替换结果
	for _, s := range pat.FindAllSubmatchIndex(src, -1) {
		res = pat.Expand(res, []byte("$cmd('$arg')\n"), src, s)
	}//按照pat的格式对src进行格式替换
	fmt.Println(string(res))
	
}

这个我就迷迷糊糊的过了

JSON处理

总有一天,你会知道你学的这个其实是有用的,知识是不断建立起来的,你现在是不会知道有用,但未来会知道的

会有一个JSON文件需要我们去处理,提取json中的相关信息,通过方法

我们会有两种解决方案

一种是已知JSON数据 的结构前提下

json 复制代码
package main

import (
    "encoding/json"
    "fmt"
)

type Server struct {
    ServerName string
    ServerIP   string
}
/*
如果说你不想要ServerName可以将开头字母小写,这样的画就不会访问得到
*/

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"}]}`
    json.Unmarshal([]byte(str), &s)
    fmt.Println(s)
}

接着不知道Json的数据结构,这样我们上面的ServerName 和 ServerIP是没有任何用的

但是我们的interface可以接受任意类型的

识记:

JSON包中采用mapstringinterface{} 和 \[\]interface{} 结构来存储任意的JSON对形象和数组

  • bool 代表 JSON booleans,
  • float64 代表 JSON numbers,
  • string 代表 JSON strings,
  • nil 代表 JSON null.
go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

type Server struct {
	ServerName string
	ServerIP   string
}

type Serverslice struct {
	Servers []Server
}

func main() {

	b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)

	var f interface{}
	err := json.Unmarshal(b, &f)
	if err != nil {

	}
	m := f.(map[string]interface{})
	/*
		这里我疑惑,这个不是知道它的数据类型了吗
	*/

	for k, v := range m {
		switch vv := v.(type) {
		case string:
			fmt.Println(k, "is string", vv)
		case int:
			fmt.Println(k, "is int", vv)
		case float64:
			fmt.Println(k, "is float64", vv)
		case []interface{}:
			fmt.Println(k, "is an array:")
			for i, u := range vv {
				fmt.Println(i, u)
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
}

这样子不是很方便,所以我们使用bitly公司开发的一个simplejson包

json 复制代码
package main

import "github.com/bitly/go-simplejson"

func main() {

	js, err := simplejson.NewJson([]byte(`{
    "test": {
        "array": [1, "2", 3],
        "int": 10,
        "float": 5.150,
        "bignum": 9223372036854775807,
        "string": "simplejson",
        "bool": true
    }
}`))
/*
实际上,我们假设有一个test的这样一个json文件
然后key他是我们的文件名,后面的就是我们要获取的数组 int 或者string类型的参数
*/
	arr, _ := js.Get("test").Get("array").Array()
	i, _ := js.Get("test").Get("int").Int()
	ms := js.Get("test").Get("string").MustString()
}

生成JSON

JSON包可以通过Marshal函数来处理,函数

go 复制代码
func Marshal(v interface{}) ([]byte, error)
/*
v就是我们要转换成json的源文件,然后我们要转化成[]byte类型的格式
因为json文件是byte类型的文件
*/
go 复制代码
package main

import (
    "encoding/json"
    "fmt"
)

type Server struct {
    ServerName string
    ServerIP   string
}

type Serverslice struct {
    Servers []Server
}

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.0.2"})
    b, err := json.Marshal(s)
    if err != nil {
        fmt.Println("json err:", err)
    }
    fmt.Println(string(b))
}

模板处理

这个模板的意思解析一下就是:很多时候,在用户的界面我们只需要修改它的某个项目,eg:姓名,电话,其他的样式,图片是一样的

Go模板使用

在Go语言中,我们使用template包进行模板处理

go 复制代码
func handler(w http.ResponseWriter,r *http.Request){
t := template.New("some template")//创建一个模板
t,_ := t.ParseFiles("tmpl/welcome.html")//解析模板文件
user := GetUser() //获取当前用户信息
t.Execute(w,user) //执行模板的merge操作
}

步骤:先获取数据,然后渲染数据

在下面的实例中:

我们将:

使用 Parse 代替 ParseFiles,因为 Parse 可以直接测试一个字符串,而不需要额外的文件

不使用 handler 来写演示代码,而是每个测试一个 main,方便测试

使用 os.Stdout 代替 http.ResponseWriter,因为 os.Stdout 实现了 io.Writer 接口

一个模板都是应用在go的一个对象中,那么我们如何将对象的字段插入到模板中呢?

字段操作

Go语言的模板通过{``{}}来包含需要在渲染时被替换的字段

{``{.}}表示当前的对象,和this相似

{``{.FieldName}}用来访问当前对象的FieldName的字段,但是这个访问字段在struct中必须是要大写的,否则在渲染中会报错

go 复制代码
package main

import (
	"html/template"
	"os"
)

type Person struct {
	UserName string
}

func main() {
	t := template.New("fieldname example")
	t, _ = t.Parse("hello {{.UserName}}")//这个就是模板
	p := Person{UserName: "AStaxie"}
	t.Execute(os.Stdout, p)
}

我们在字段中重新添加一个email,虽然说最后不会输出email

当然也不会报错

go 复制代码
package main

import (
	"html/template"
	"os"
)

type Person struct {
	UserName string
	email    string
}

func main() {
	t := template.New("fieldname example")
	t, _ = t.Parse("hello {{.UserName}}! {{.email}}") //这个就是模板文件
	p := Person{UserName: "AStaxie"}
	t.Execute(os.Stdout, p)
}

输出嵌套字段内容

如果字段里面有对象,该怎么输出

go 复制代码
package main

import (
	"html/template"
	"os"
)

type Friend struct {
	Fname string
}

type Person struct {
	UserName string
	Emails   []string
	Friends  []*Friend
}

func main() {
	f1 := Friend{Fname: "minux.ma"}
	f2 := Friend{Fname: "xushiwei"}
	t := template.New("fieldname example")
	t.Parse(`hello{{.UserName}}!
{{range .Emails}}
an email {{.}}
{{end}}
{{with .Friends}}
{{range .}}
my friend name is {{.Fname}}
{{end}}
{{end}}`)
	p := Person{UserName: "Astaxie",
		Emails:  []string{"astaxie@beego.me", "astaxie@gmail.com"},
		Friends: []*Friend{&f1, &f2}}
	t.Execute(os.Stdout, p)
}

这段代码我是着实没有看懂什么,作者也没有解释

我们可以发现Person结构体中是有Friends对象的,对于这种我们可以使用with来牵扯出这个对象 with .Friends 注意一下这里的点是附属关系的表现

然后我们 使用{``{range.}} 这个就是遍历我们的Friends中的全部集合元素

然后在之后访问的时候

假设你想得到的是FieldName这个属性

{{.FieldName}}

通过 {``{range .}} 结构迭代集合时,你可以访问到对象中的所有字段和方法,只需要在 . 后面加上你想访问的字段名或方法名即可。

{``{range}} 和 {``{with}} 结构都是带有起始标签和结束标签的控制结构。这些结构的起始标签是 {``{range .}} 和 {``{with .}},而对应的结束标签是 {``{end}}。

条件处理

对于一个模板,我们可以对输入的信息进行判断,然后切换不同的模板

pipeline 是一种将多个命令和操作符连接起来的方式,用于对数据进行处理或转换

在模板语法中,我们可以使用 range 结构迭代一个切片,并使用 {``{.}} 来获取当前迭代元素的值。而 {``{.}} 表示当前迭代元素的值,就是一个 pipeline,它将当前元素传递给下一个命令或操作符。

go 复制代码
package main

import (
    "os"
    "text/template"
)

func main() {
    tEmpty := template.New("template test")
    tEmpty = template.Must(tEmpty.Parse("空 pipeline if demo: {{if ``}} 不会输出. {{end}}\n"))
    // {{if ``}}这个是如果为空的意思
    tEmpty.Execute(os.Stdout, nil)

    tWithValue := template.New("template test")
    tWithValue = template.Must(tWithValue.Parse("不为空的 pipeline if demo: {{if `anything`}} 我有内容,我会输出. {{end}}\n"))
    //{{if `anything`}}这个是如果不为空
    tWithValue.Execute(os.Stdout, nil)

    tIfElse := template.New("template test")
    tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} if部分 {{else}} else部分.{{end}}\n"))
    tIfElse.Execute(os.Stdout, nil)
}
模板变量

我们使用{``{variable := pipeline}}语法来声明一个模板变量。将在当前作用域内创建一个局部变量,该变量的生命周期限定在该作用域内,通常是在{{end}}结束标价之前

go 复制代码
package main

import (
	"os"
	"text/template"
)

func main() {
	// 定义模板
	tmpl := `{{with $x := "output"}}{{$x | printf "%q"}}{{end}}`
     //将字符串output格式化为带引号的字符串
	// 解析模板
	t := template.Must(template.New("tmpl").Parse(tmpl))

	// 执行模板并输出结果
	err := t.Execute(os.Stdout, nil)
	if err != nil {
		panic(err)
	}
}

我真的感觉好大的阻力看这个东西,有种欲哭无泪的感觉

直接到文件操作吧

文件操作

目录操作

就是我们可以创建或者删除目录的一些函数

go 复制代码
func Mkdir(name string, perm FileMode) error

创建名称为 name 的目录,权限设置是 perm,例如 0777
说一下权限设置是什么意思
权限是由三个数字组成的,每个数字表示对应用户组(所有者,群组,其他用户)的权限,采用8进制,每个数字分别表示读(r),写(w),执行(x)权限
r:表示能读取文件内容或者查看目录中的文件列表
w:表示能写入或修改文件内容,对目录而言表示能够在其中创建,删除或重命名文件
x:表示能够执行文件或者进入目录

在权限设置中,八进制的第一个数字表示所有者的权限,第二个数字表示群组的权限,第三个数字表示其他用户的权限。他们的位置分别是4,2,1.
4+2+1 = 7

func MkdirAll(path string, perm FileMode) error

根据 path 创建多级子目录,例如 astaxie/test1/test2。

func Remove(name string) error

删除名称为 name 的目录,当目录下有文件或者其他目录时会出错

func RemoveAll(path string) error

根据 path 删除多级子目录,如果 path 是单个名称,那么该目录下的子目录全部删除。

文件操作

新建文件可以通过如下两个方法

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 是权限

写文件

写文件函数:

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 信息到文件

go 复制代码
package main

import (
	"fmt"
	"os"
)

func main() {
	userFile := "test.txt"
	fl, err := os.Open(userFile)
	if err != nil {
		fmt.Println(userFile, err)
		return
	}
	defer fl.Close()
	buf := make([]byte, 1024)
	for {
		n, _ := fl.Read(buf)
		//读取数据到buf中
		if n == 0 {
			break
		}
		os.Stdout.Write(buf[:n])
	}
}

字符串处理

我们通常提取的数据都是字符串,但是如何对这些字符串进行分割连接呢

字符串操作
go 复制代码
package main

import (
	"fmt"
	"strings"
)

func main() {

	/*
	func Contains(s,substr string)bool
	字符串s中是否包含substr,返回bool值
	 */
	fmt.Println(strings.Contains("seafood", "foo"))
	fmt.Println(strings.Contains("seafood", "bar"))
	fmt.Println(strings.Contains("seafood", ""))
	fmt.Println(strings.Contains("", ""))
	// Output:
	// true
	// false
	// true
	// true
}
go 复制代码
	s := []string{"lxy", "zcx", "xzc"}
	fmt.Println(strings.Join(s, " and "))
/*
func Join(a []string,sep string)string
字符串链接,把slice a 通过sep连接起来
*/
go 复制代码
package main

import (
	"fmt"
	"strings"
)

func main() {

	/*
		func Contains(s,substr string)bool
		字符串s中是否包含substr,返回bool值
	*/
	fmt.Println(strings.Contains("seafood", "foo"))
	fmt.Println(strings.Contains("seafood", "bar"))
	fmt.Println(strings.Contains("seafood", ""))
	fmt.Println(strings.Contains("", ""))
	// Output:
	// true
	// false
	// true
	// true
	s := []string{"lxy", "zcx", "xzc"}
	fmt.Println(strings.Join(s, " and "))

	/*
		func index(s,sep string)int
		在字符串s中查找sep所在的位置,返回位置值,找不到返回-1
	*/
	fmt.Println(strings.Index("chicken", "ken"))
	fmt.Println(strings.Index("chicken", "dmr"))

	/*
		func Repeat(s string,count int) string
		重复s字符串count次,最后返回重复的字符串
	*/
	fmt.Println("ba" + strings.Repeat("laa", 2))

	/*
		func Replace(s,old,new string,n int)string
		在s字符串,把old字符串替换为new字符串,n表示替换的次数,小于0表示全部替换
	*/
	fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
	fmt.Println(strings.Replace("hello hello hello", "el", "56", -1))

	/*
		func Split(s,sep string)[]string
		把s字符串按照sep分割,返回slice
	*/
	fmt.Printf("%q\n", strings.Split("a,b,c", ","))
	fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))

	/*
			%q是一种格式化字符串的标记
		也就是会转义像"\n"不会变成换行符

	*/
	/*
		func Trim(s string,cutset string) string
		在s字符串的头部和尾部取出cutset指定的字符串
	*/
	fmt.Printf("[%q]", strings.Trim("!!! action !!!", "!"))
	/*
		func Field(s string)[]string
		去除s字符串的空格符,并且按照空格分割返回slice
	*/
	fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz  "))
}

字符串转换

将整数转化为字符串,并且添加到现有的字节数组中

go 复制代码
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))
}
  • Format系列函数把其他类型的转换为字符串
go 复制代码
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)
}
  • Parse系列函数把字符串转换为其他类型
go 复制代码
package main

import (
    "fmt"
    "strconv"
)
func checkError(e error){
    if e != nil{
        fmt.Println(e)
    }
}
func main() {
    a, err := strconv.ParseBool("false")
    checkError(err)
    b, err := strconv.ParseFloat("123.23", 64)
    checkError(err)
    c, err := strconv.ParseInt("1234", 10, 64)
    checkError(err)
    d, err := strconv.ParseUint("12345", 10, 64)
    checkError(err)
    e, err := strconv.Atoi("1023")
    checkError(err)
    fmt.Println(a, b, c, d, e)
}

这前面三个看看就行

相关推荐
czq_26867194876 小时前
Python打卡第46天
开发语言·python
卸任6 小时前
Vibe coding工具使用心得
前端·ai编程
brien96 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance7 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M7 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写7 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李7 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易7 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马7 小时前
前沿视界
前端
kyriewen7 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员