Go-字符和字符串类型详解(原始字符串、拼接、修改、比较、拆分、查找等)

简介: Go-字符和字符串类型详解(原始字符串、拼接、修改、比较、拆分、查找等)

上篇文章思考题

Go-数字与布尔类型详解

结果:cannot use number2 + 10 (type int) as type int64 in assignment

注意:uint8就是byte,编译通过,但是int和int64需要显示转换

字符型

没有,推荐使用byte或rune,仅包含Ascii码时,使用byte,其余使用rune。

字母一个字节,汉字3个字节

存储过程:字符->码值(数字)->二进制->保存

直接输出为数字,按字符使用 %c

  a := 'a'
  fmt.Printf("a的类型%T,a的值:%v,a对应的字符:%c,a的大小:%d\n",a,a,a,unsafe.Sizeof(a))
  you := '你'
  fmt.Printf("you的类型%T,you的值:%v,you对应的字符:%c,you的大小:%d\n",you,you,you,unsafe.Sizeof(you))

字符串

src->builtin->builtin.go

// string is the set of all strings of 8-bit bytes, conventionally but not
// necessarily representing UTF-8-encoded text. A string may be empty, but
// not nil. Values of string type are immutable.
type string string

由byte组成,是byte数组,不可以变,直接输出可以

  str1 := "hello"
  str2 := "你好"
  fmt.Println("str1 str2:",str1,str2)

内存

src->reflect->value.go

// StringHeader is the runtime representation of a string.
// It cannot be used safely or portably and its representation may
// change in a later release.
// Moreover, the Data field is not sufficient to guarantee the data
// it references will not be garbage collected, so programs must keep
// a separate, correctly typed pointer to the underlying data.
type StringHeader struct {
  Data uintptr
  Len  int
}

目前,在go 1.16.3中是使用指针和长度的结构体表示,以后可能会修改。

1.  world := "world"
  world1 := "世界"
  fmt.Printf("world:%v world1:%v world:%T,world1:%T\n", world,world1,world,world1)
  fmt.Println("&world[0] &world1 len(world) len(world1):",&world,&world1,len(world),len(world1))
  // &world[0] 不允许取地址

2020062310470442.png

你可以访问world[0],但是不能访问world[0]的地址 &world[0],出于安全考虑。

原始字符串

双引号"识别转义字符,反引号`原生形式输出

  str3 := "我要换行\n换好啦:)\n"
  str4 := `我想换行\n换不了:(\n`

返回子串

类似Python的切片,没有步长,左闭右开,左右相等时为空,左默认为0,右默认为字符串长度

  fmt.Println("world[:3] world1[3:]:",world[:3],world1[3:])

返回子串

类似Python的切片,没有步长,左闭右开,左右相等时为空,左默认为0,右默认为字符串长度

  fmt.Println("world[:3] world1[3:]:",world[:3],world1[3:])

拼接

使用+,放不下时,+保留在上一行

  str5 := str1+world+
    str2+world1

修改

使用切片

1.  tmp := []byte(world)
  tmp[0] = 'W'
  world = string(tmp)
  fmt.Println("world &world",world,&world)

注意:地址相同,确实是修改了

遍历

for或for range

  for i:=0;i<len(world1);i=i+3{
    fmt.Print(world1[i:i+3])
  }
  for _,s := range world1{
    fmt.Printf("%c",s)
  }

注意:中文是3个取一次,否则没意义。推荐使用for range方式,有字符和中文时都可以。

strings包

比较

==

注意:严格区分大小写

EqualFold

func EqualFold(s, t string) bool

判断两个utf-8编码字符串(将unicode大写、小写、标题三种格式字符视为相同)是否相同。

  alpha := "abc"
  alpha2 := "Abc"
  fmt.Println("alpha==alpha2 strings.EqualFold(alpha,alpha2):", alpha==alpha2,strings.EqualFold(alpha,alpha2))

大小写转换

func ToLower(s string) string

返回将所有字母都转为对应的小写版本的拷贝

func ToUpper(s string) string

返回将所有字母都转为对应的大写版本的拷贝

  fmt.Println("",strings.ToUpper(alpha),strings.ToLower(alpha2))

去前后缀

func TrimSpace(s string) string

返回将s前后端所有空白(unicode.IsSpace指定)都去掉的字符串。

func Trim(s string, cutset string) string

返回将s前后端所有cutset包含的utf-8码值都去掉的字符串。

func TrimLeft(s string, cutset string) string

返回将s前端所有cutset包含的utf-8码值都去掉的字符串。

func TrimRight(s string, cutset string) string

返回将s后端所有cutset包含的utf-8码值都去掉的字符串。

  song := "  \n\t两只\t老虎\t爱跳舞\n   "
  fmt.Println("去空格 去空格和两只 去空格和两 去空格和跳舞:",strings.TrimSpace(song),strings.Trim(song," \n\t两只"),
    strings.TrimLeft(song," \n\t两"),strings.TrimRight(song," \n两跳舞"))

注意:TrimSpace将\t等也算为Space,指定时是字符集,在其中就算,直到左/右侧不在集合中停止。

判断前后缀

func HasPrefix(s, prefix string) bool

判断s是否有前缀字符串prefix。

func HasSuffix(s, suffix string) bool


判断s是否有后缀字符串suffix。

fmt.Println("song[4:]有两只前缀吗? song有爱跳舞后缀吗?",strings.HasPrefix(song[4:],"两只"),strings.HasSuffix(song,"爱跳舞"))

拆分与拼接

func Split(s, sep string) []string

用去掉s中出现的sep的方式进行分割,会分割到结尾,并返回生成的所有片段组成的切片(每一个sep都会进行一次切割,即使两个sep相邻,也会进行两次切割)。如果sep为空字符,Split会将s切分成每一个unicode码值一个字符串。

func Join(a []string, sep string) string

将一系列字符串连接为一个字符串,之间用sep来分隔。

  ip := "192.168.31.129"
  slice  := strings.Split(ip,".")
  newIp := strings.Join(slice,"?")

子串

包含

func Contains(s, substr string) bool

判断字符串s是否包含子串substr。

  fmt.Println("song包含老虎吗? ",strings.Contains(song,"老虎"))

统计

func Count(s, sep string) int

返回字符串s中有几个不重复的sep子串。

  fmt.Println("ip中有几个.? ",strings.Count(ip,"."))

查找

func Index(s, sep string) int

子串sep在字符串s中第一次出现的位置,不存在则返回-1。

func LastIndex(s, sep string) int


子串sep在字符串s中最后一次出现的位置,不存在则返回-1。

  fmt.Println("ip中第一个1的下标 ip中最后一个1的下标:",strings.Index(ip,"1"),strings.LastIndex(ip,"1"))

替换

func Replace(s, old, new string, n int) string

返回将s中前n个不重叠old子串都替换为new的新字符串,如果n<0会替换所有old子串。

  fmt.Println("将ip中的.替换为*",strings.Replace(ip,".","*",-1))

类型转换函数Atoi等在数据转换文章,更多方法,查看参考的包

bytes包和strings包的函数差不多,只不过参数由string变为了[]byte,可以看下参考的Go标准库,这里就不展示了。

查看源代码也经常能看到官方的骚操作,比如bytes.Equal

func Equal(a, b []byte) bool {
  return string(a) == string(b)
}

unicode包

此包主要针对字符rune类型

func IsDigit(r rune) bool

IsDigit报告一个字符是否是十进制数字字符。

  ok := unicode.IsDigit(rune(ip[0]))
  fmt.Printf("%c是十进制数字? %t\n",ip[0],ok)

是否是数字字符

func IsNumber(r rune) bool

IsNumber报告一个字符是否是数字字符

  ok = unicode.IsNumber(rune(ip[0]))
  fmt.Printf("%c是数字字符? %t\n",ip[0],ok)

是否是字母

func IsLetter(r rune) bool

IsLetter报告一个字符是否是字母

  ok = unicode.IsLetter(rune(alpha[0]))
  fmt.Printf("%c是字母? %t\n",alpha[0],ok)


是否是小写字母

func IsLower(r rune) bool

返回字符是否是小写字母

ok = unicode.IsLower(rune(ip[0]))
fmt.Printf("%c是小写字母? %t\n",ip[0],ok)

是否是大写字母

func IsUpper(r rune) bool

返回字符是否是大写字母。

ok = unicode.IsUpper(rune(alpha2[0]))
fmt.Printf("%c是大写字母? %t\n",alpha2[0],ok)

返回对应的大写字母

func ToUpper(r rune) rune

返回对应的大写字母,不是字母是返回原字符。

  fmt.Printf("%c转换为大写字母是%c\n",ip[0],unicode.ToUpper(rune(ip[0])),)

返回对应的小写字母

func ToLower(r rune) rune

返回对应的小写字母,不是字母是返回原字符。

fmt.Printf("%c转换为小写字母是%c\n",alpha2[0],unicode.ToLower(rune(alpha2[0])))

全部代码

package main
import (
  "fmt"
  "strings"
  "unicode"
  "unsafe"
)
func main() {
  //------------------字符型-------------------
  a := 'a'
  fmt.Printf("a的类型%T,a的值:%v,a对应的字符:%c,a的大小:%d\n",a,a,a,unsafe.Sizeof(a))
  you := '你'
  fmt.Printf("you的类型%T,you的值:%v,you对应的字符:%c,you的大小:%d\n",you,you,you,unsafe.Sizeof(you))
  //-----------------字符串--------------------
  str1 := "hello"
  str2 := "你好"
  fmt.Println("str1 str2:",str1,str2)
  //-----------------内存----------------------
  world := "world"
  world1 := "世界"
  fmt.Printf("world:%v world1:%v world:%T,world1:%T\n", world,world1,world,world1)
  fmt.Println("&world[0] &world1 len(world) len(world1):",&world,&world1,len(world),len(world1))
  // &world[0] 不允许取地址
  //-----------------原始字符串----------------
  str3 := "我要换行\n换好啦:)\n"
  str4 := `我想换行\n换不了:(\n`
  fmt.Printf("str3:%vstr4:%v\n",str3,str4)
  //----------------子串----------------------
  fmt.Println("world[:3] world1[3:]:",world[:3],world1[3:])
  //---------------拼接-----------------------
  str5 := str1+world+
    str2+world1
  fmt.Println("str5:",str5)
  //--------------修改(重新赋值)-------------
  tmp := []byte(world)
  tmp[0] = 'W'
  world = string(tmp)
  fmt.Println("world &world",world,&world)
  //-------------遍历------------------------
  for i:=0;i<len(world1);i=i+3{
    fmt.Print(world1[i:i+3])
  }
  for _,s := range world1{
    fmt.Printf("%c",s)
  }
    fmt.Println()
  //--------------比较-----------------------
  alpha := "abc"
  alpha2 := "Abc"
  fmt.Println("alpha==alpha2 strings.EqualFold(alpha,alpha2):", alpha==alpha2,strings.EqualFold(alpha,alpha2))
  //-------------大小写转换-------------------
  fmt.Println("",strings.ToUpper(alpha),strings.ToLower(alpha2))
  //------------去除空格--------------------
  song := "  \n\t两只\t老虎\t爱跳舞\n   "
  fmt.Println("去空格 去空格和两只 去空格和两 去空格和跳舞:",strings.TrimSpace(song),strings.Trim(song," \n\t两只"),
    strings.TrimLeft(song," \n\t两"),strings.TrimRight(song," \n两跳舞"))
  //------------判断前后缀----------------
  fmt.Println("song[4:]有两只前缀吗? song有爱跳舞后缀吗?",strings.HasPrefix(song[4:],"两只"),strings.HasSuffix(song,"爱跳舞"))
  //-------------拆分与拼接--------------
  ip := "192.168.31.129"
  slice  := strings.Split(ip,".")
  newIp := strings.Join(slice,"?")
  fmt.Println("ip newIP:",ip,newIp)
  //--------------------------------子串--------------------------------
  //-------------包含-------------------
  fmt.Println("song包含老虎吗? ",strings.Contains(song,"老虎"))
  //------------统计-------------------
  fmt.Println("ip中有几个.? ",strings.Count(ip,"."))
  //----------查找--------------------
  fmt.Println("ip中第一个1的下标 ip中最后一个1的下标:",strings.Index(ip,"1"),strings.LastIndex(ip,"1"))
  //----------替换-------------------
  fmt.Println("将ip中的.替换为*",strings.Replace(ip,".","*",-1))
  //----------------------------------判断-------------------------------
  ok := unicode.IsDigit(rune(ip[0]))
  fmt.Printf("%c是十进制数字? %t\n",ip[0],ok)
  ok = unicode.IsNumber(rune(ip[0]))
  fmt.Printf("%c是数字字符? %t\n",ip[0],ok)
  ok = unicode.IsLetter(rune(alpha[0]))
  fmt.Printf("%c是字母? %t\n",alpha[0],ok)
  ok = unicode.IsLower(rune(ip[0]))
  fmt.Printf("%c是小写字母? %t\n",ip[0],ok)
  ok = unicode.IsUpper(rune(alpha2[0]))
  fmt.Printf("%c是大写字母? %t\n",alpha2[0],ok)
  fmt.Printf("%c转换为小写字母是%c\n",alpha2[0],unicode.ToLower(rune(alpha2[0])))
  fmt.Printf("%c转换为大写字母是%c\n",ip[0],unicode.ToUpper(rune(ip[0])),)
}

截图

2020062310470442.png

参考

Go标准库-strings

Go标准库-bytes

Go标准库-unicode

补充

字符串内部存储与取出

  S := "ab"
  for i,s := range S{
    fmt.Printf("%T %T %T\n",i,s,S[i])
  }

int int32 uint8

int int32 uint8

取出的是rune,存储的是byte

思考题

以下代码会输出什么?

  sentence := "我是lady_killer9"
  for i :=0;i<len(sentence);i++{
    fmt.Printf("%c",sentence[i])
  }

答案见下一篇文章:Go-基本数据类型转换详解

更多Go相关内容:Go-Golang学习总结笔记

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。

相关文章
|
27天前
|
存储 Go 索引
go语言中遍历字符串
go语言中遍历字符串
42 5
|
19天前
|
Go
go语言for 遍历字符串
go语言for 遍历字符串
26 8
|
23天前
|
Go 索引
go语言遍历字符串
go语言遍历字符串
25 3
|
25天前
|
Go 索引
go语言按字符(Rune)遍历
go语言按字符(Rune)遍历
27 3
|
1月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
36 4
|
1月前
|
Go
go语言常量的类型
【10月更文挑战第20天】
26 2
|
3月前
|
Go
Go字节数组与字符串相互转换
Go字节数组与字符串相互转换
40 3
|
3月前
|
存储 Go
go语言字符串变小写
go语言字符串变小写
|
3月前
|
存储 Go
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
4月前
|
安全 Go