文本处理(有关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.匹配手机号码:

regexCopy code
1[3-9]\d{9}

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

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

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就是输入源
*/

下面我们来举个例子,

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上面进行了一个实验的,大家可以做一下,加强对这个函数的理解,代码不用全部打

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过正则来获取内容

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文件转换成我们想要得到的信息

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

func Compile(expr string) (*Regexp, error)
func CompilePOSIX(expr string) (*Regexp, error)
func MustCompile(str string) *Regexp
func MustCompilePOSIX(str string) *Regexp

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

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

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

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

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

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

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
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数据 的结构前提下

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包中采用map[string]interface{} 和 []interface{} 结构来存储任意的JSON对形象和数组

  • bool 代表 JSON booleans,
  • float64 代表 JSON numbers,
  • string 代表 JSON strings,
  • nil 代表 JSON null.
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包

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函数来处理,函数

func Marshal(v interface{}) ([]byte, error)
/*
v就是我们要转换成json的源文件,然后我们要转化成[]byte类型的格式
因为json文件是byte类型的文件
*/
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))
}

模板处理

img

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

Go模板使用

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

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中必须是要大写的,否则在渲染中会报错

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

当然也不会报错

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)
}

输出嵌套字段内容

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

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,它将当前元素传递给下一个命令或操作符。

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}}结束标价之前

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)
	}
}

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

直接到文件操作吧

文件操作

目录操作

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

func Mkdir(name string, perm FileMode) error

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

在权限设置中,八进制的第一个数字表示所有者的权限,第二个数字表示群组的权限,第三个数字表示其他用户的权限。他们的位置分别是421.
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 信息到文件

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])
	}
}

字符串处理

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

字符串操作
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 Join(a []string,sep string)string
字符串链接,把slice a 通过sep连接起来
*/
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  "))
}

字符串转换

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

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系列函数把其他类型的转换为字符串
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系列函数把字符串转换为其他类型
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)
}

这前面三个看看就行

  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值