文本处理(有关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 ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://file.jishuzhan.net/article/1771505108765380610/34a36df685abd11ce633b01dfd1fa850.webp) **通过正则来获取内容** ```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("\\") src = re.ReplaceAllString(src, "") // 去除 SCRIPT re, _ = regexp.Compile("\\") 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\w+)\s+(?P.+)\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包中采用map\[string\]interface{} 和 \[\]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)) } ``` #### 模板处理 ![img](https://file.jishuzhan.net/article/1771505108765380610/a0a7a7aa7b9dd9c90ac58d76953719e1.webp) 这个模板的意思解析一下就是:很多时候,在用户的界面我们只需要修改它的某个项目,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{"[email protected]", "[email protected]"}, 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) } ``` 这前面三个看看就行

相关推荐
小小小小宇25 分钟前
Vue.nextTick()笔记
前端
C++ 老炮儿的技术栈26 分钟前
UDP 与 TCP 的区别是什么?
开发语言·c++·windows·算法·visual studio
wgslucky31 分钟前
Dubbo报错:module java.base does not “opens java.lang“ to unnamed module
java·开发语言·dubbo
whyeekkk1 小时前
python打卡第48天
开发语言·python
小约翰仓鼠2 小时前
vue3子组件获取并修改父组件的值
前端·javascript·vue.js
Lin Hsüeh-ch'in2 小时前
Vue 学习路线图(从零到实战)
前端·vue.js·学习
DougLiang2 小时前
关于easyexcel动态下拉选问题处理
java·开发语言
烛阴2 小时前
bignumber.js深度解析:驾驭任意精度计算的终极武器
前端·javascript·后端
计蒙不吃鱼2 小时前
一篇文章实现Android图片拼接并保存至相册
android·java·前端