4week-3字符串和字符

一.十六进制,十进制,在ASCII中的表示对应关系

1. 0

十进制 十六进制 字符
0 0 NULL

  0x01    //数值表达方式
'\x00'    //十六进制字符表达
"\x00"    //十六进制字符串

2.tab

* 字符表示 
  十六进制  '\x09'  
  或者       '\t' 

* 字符串表达
  "\x09\t"  2个字符 

3.\n 换行符,新的一行

* 字符表示 
  '\n'  或者十六进制  'x0a'

4. \r 回车

也支持换行.看在哪种操作系统上

* 字符表达
      或者 '\r'  或者十六进制  '\x0d'
* 字符串表达
      windows  回车换行
        "\r\n"  2个字符,必须用字符串
        或者
        十六进制表达 "\x0d\x0a"

      linux
        '\n'  //换行
      
      mac
        '\r'  //换行

二.字符的宽度不是展示的宽度

  • 我们看到的字符和字符之间的宽度和,存储在磁盘的宽度是2回事
  • 比如内存中存储的是0x61 0A 61 编辑器打开后,把0x61翻译成a,把0A翻译成tab,把61翻译成b----> a换行b

1. "a\tb" 字节问题

len3,占用都是3个字节
"a空格b"    内存中 "0x61 20 61 "
"atabb"     内存中 "0x61 0A 61 " 
"a\tb"      内存中  "0x61 0A 61 "  \t是一个字节

2.有的编辑器不支持键盘上的"tab键"编程时候保险的方式 用\t

func main() {
s1 := "a b" //a和b中间按的是键盘上的"tab键".有的编辑器不支持
s2 := "a\tb" //保险做法:\t
s3 := "a\x09b" //不要看表面,要看内存
s4 := "a\tb" //如果要显示"",用\转义
fmt.Println(s1, s2, s3, s4)
}

3.明确长度,换行符要,写清楚,由于编辑器的问题,否则不准确

s4 := "a\nb"
fmt.Println(s4, len(s4), []byte(s4))

}

三.字符串笔记大小

*字符串笔记,比较的是ascii

	//字符串比较大小.比较的是ascii里的十六进制
	fmt.Println('A' > 'a')
	fmt.Println("a" > "A")
	fmt.Println("AA" > "Aa")
	fmt.Println("AAa" > "AaA")

四.字符

1.字符定义:

func main() {
	s := 'a'          //默认:rune 4byte 查unicode
	var s1 byte = 'a' //字节.查ascii 1个byte
	fmt.Printf("%T %T", s, s1)
}

五.字符串

1.字符串定义

func main() {
	s := '测'
	//1.rune 4byte unicode 不是容器,不能len
	fmt.Println(s)

	s1 := "abc"
	//1.3byte 616263
	//2.字节是怎么读出来的: utf-8兼容ASCII码.3x1=3个byte
	fmt.Println(len(s1))

	s2 := "测试"
	//1.s2是字符串.utf-8,每个中文3个字节长度6byte;
	//2.字节是怎么读出来的: "测试"在内存中展开成utf-8的2个字符,2x3=6个byte
	fmt.Println(len(s2)) //len只看字节数,其他语言是看字符数的,len只能用在内建

	s3 := "测"
	//1.一个的字符串,utf-8.一个汉字占3byte
	fmt.Println(len(s3))
}

2.string 转切片

  • 线性数据结构,类似slice,有header,有底层字符数组,但是用起来为了不增加go的难度,go设计者把它的使用方式和其他语言统一了,使用上感觉和int类型一样

1. 把字符串强制转为 ---> 1字节的字符串转byte和rune切片

func main() {
  s1 := "abc"
  t1 := []byte(s1)
  fmt.Println(t1, len(t1), cap(t1), &t1[0], &t1[1]) //[97 98 99] 3 8 0xc000128058 0xc000128059 偏移1个byte

  t2 := []rune(s1)
  fmt.Println(t2, len(t2), cap(t2), &t2[0], &t2[1]) //[97 98 99] 3 4 0xc0001280a0 0xc0001280a4 偏移4个byte
}
  • 结果

2. 把多字符串转为byte和rune切片

func main() {
  t3 := []byte(s2)  //utf8的字节序列
    //把s2 := "测试" 拆成`字节`放入byte切片
  fmt.Println(t3, len(t3))     //[230 181 139 232 175 149] 6  //像是utf-8编码字符序列 是utf-8编码

  t4 := []rune(s2) //s2是 [230 181 139 232 175 149] 6 是utf-8编码
    //把 utf8转成unicode双字节2byte unicode是4字节,前2个字节空着,用后2个字节测字
  fmt.Println(t4, len(t4))     
    //2个rune类型 [27979 35797] 2    //牵扯到utf-8映射成unicode// [230 181 139 232 175 149 utf8]把2个3字节转成2个字节双字节
    //utf8的字节序列-->unicode序列
}
  • 结果

为什么是2个字节呢?

3.把rune序列转为字符串

func main() {
	fmt.Println(string([]rune{27979}))              //unicode序列转为utf-8 string
	fmt.Println(string([]byte{0x61, '\x62', 0x63})) //byte sequence 转为 utf-8 string sequence
	fmt.Println(string([]byte{230, 181, 139, 232, 175, 149}))
}
  • 结果

4.println直接打印索引

func main() {
s1 := "abc"
s2 := "测试"
fmt.Println(s1[0], s1[1], s1[2]) //通过索引取值,是字符序列,如同放在[]byte里一样,其中的1个byte uint8,所以显示是整数
fmt.Println(s2[0], s2[1], s2[2]) //通过索引取值,是字符序列,如同放在[]byte里一样,其中的1个byte uint8,所以显示是整数
}
  • 结果:

3.字符串遍历

1.按照字节遍历

	s1 := "abc"
	for i := 0; i < len(s1); i++ {   //len 把abc拆成字节
		fmt.Println(i, s1[i])
	}

2.按照字符遍历

          	s2 := "abc测试"
	for i, v := range s2 {
		fmt.Printf("%d  %[2]c\n", i, v) //这里的v是rune
	}
  • 结果

3.按照字符遍历.但是按照字节显示

	for i, v := range s2 {
		fmt.Printf("%[3]c\n", i, v, s2[i])//由于%c是用字符显示,而s2[i]取的是字节,那么就把字符串拆成了字节,相当于把测字拆成了3份,显示其中的一个,就会乱码
	}
  • 结果
posted @ 2023-01-08 23:25  john5的博客  阅读(33)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css