栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

第5关 字符串的基本操作

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

第5关 字符串的基本操作

需求=过去困惑+当下渴望+未来希望 ——实干《实干日记》

第5关 字符串的基本操作
  • 5-1 为什么len函数获取中文字符串长度有问题?

5-1 为什么len函数获取中文字符串长度有问题?

我们将讲解go语言的字符串相关的操作。
因为字符串本身是非常重要,而且它相对的方法也比较多,所以说我们这里边单独拿一个关卡出来专门讲解字符串。

字符串不管在任何语言当中,它的使用都是非常频繁的。

在Python当中基本上采用的字符串操作,在go当中基本上也是这么回事,它也是这些基本操作。

1.求解字符串的长度。

它有一个内置的函数叫len,名字跟Python是一样的。

比如说这里边我们定义一个字符串,字符串的定义我们可以直接这样来定义,比如说name,然后它是有类型的叫string,然后赋值赋值跟Python是一样的。
注意一下,这里不能用单引号,单引号 引起来/包裹起来 的单个符号是字符。

那就引出了一个问题:
在go语言中,字符和字符串有啥区别?

2.字符和字符串有啥区别
我们通过代码来说明,就不用文字来表述了。
文件位置:c06/demo1.go

package main

import "fmt"

var global int = 1024
func main(){
	str := "keegan"
	fmt.Printf("%T,%v,%sn",str,str,str)

	var ch1 rune = 'A'
	fmt.Printf("%T,%v,%cn",ch1,ch1,ch1)

	var ch2 byte = 'B'
	fmt.Printf("%T,%v,%cn",ch2,ch2,ch2)

	var ch3 int32 = 'C'
	fmt.Printf("%T,%v,%cn",ch3,ch3,ch3)

	var (
		name string = "程咬铁"
		age int32 = 18
		salary float32 = 12580
	)
	fmt.Printf("name=%s,age=%d,salary=%fn",name,age,salary)

	fmt.Printf("global=%dn",global)
	global += 1024
	fmt.Printf("global=%dn",global)
}

解读代码信息:

 

回答开始的问题:字符和字符串有啥区别?
字符定义:
形如 var ch3 int32 = 'C'
字符变量 ch3 的值是 用单引号 括起来的 大写的 C

字符串定义:
形如 str := "keegan"
字符串变量 str 的值 使用双引号 括起来的 keegan 这 6个字符。
字符串 是 一连串字符的集合。
特别地还有 空白字符的字符串【空字符串】,单个字符的字符串。
可以这样定义:

到这里,处理完问题2之后,再继续看 1.求解字符串的长度

3.继续看 1.求解字符串的长度
我们先定义以下字符串:
部分代码如下:

var name string = "keegan:写博客" // 一共由10个字符组成
fmt.Println(len(name)) // 16

这里面怎么求它的长度呢?
用len函数。跟Python中的求字符串的长度用的函数都是len函数。
前置信息铺垫:
存储空间的基本单位是 字节。
比如
在go中,1个英文的字符占用1个字节,1个中文的字符占用3个字节。【自己写字符串测试结果】

对于len函数:
用途:用来获取字符串的字节长度,返回的是字节的长度。
处理方法:在go的字符串中,1个英文的字符占用1个字节,1个中文的字符占用3个字节。【自己写字符串测试结果】

我们直接来打印一下,它返回的是16。

为什么是16呢?这里面的逻辑是什么?
用Python来打印:

print(len("keegan:写博客")) # 10

这里又引出了一个问题:
在go语言中,英文字符和中文字符计算长度的方法是怎样的?
在go中,1个英文的字符占用1个字节,1个中文的字符占用3个字节。【自己写字符串测试结果】

我们要知道这个英文字符和中文字符它们的编码规则是不一样的,我们如果把中文内容 写博客 给它去掉,只要是英文加上特殊符号,它的长度就是准确的:

 var name string = "keegan:"
 fmt.Println(len(name)) // 7

我们只要不是中文,然后这里边当然其他国家的语言也不行,一旦涉及到中文或其他国家的语言例如日文,韩文就不准确了。

对于英文来说,英文它实际上是ASCII码来做的,ASCII是一套编码标准,用于显示英文的。128个字符


通过上图,我们知道了,不同的语言,用的编码标准是不一样的,计算语言符号占用的字节也不一样。
我们这里简化问题一下:
英文在计算机里用的是ASCII编码标准,1个英文字符占用1个字节。
中文在go语言中采用的是Unicode,1个汉字占用3个字节。
Unicode实现方式又包括UTF-8、UTF-16、UTF-32。

以上编码标准有啥意义?
就告诉了计算机 汉字/英文字符 用什么数字代替的?
因为计算机的存储单位是位(bit),每1位的状态用0或1表示。
英文字符 用数字表示:
A:65 B:66 C:67 …依次递增
a:97 b:98 c:99 …依次递增

汉字的话:

首先,计算机存储的是用二进制来实现的。
把所有国家的字符(英文,中文等)跟数字做好了映射,统一了标准之后,就不存在语言的编码冲突了【一说65对应的啥字母你就能根据标准计算出是A,一说97对应的啥字母你就能根据标准计算出是a】,计算机会根据这套标准帮我们实现了跨语言,跨平台进行的文本转换和处理,这样,在电脑屏幕下,就能显示任何语言的内容了。

回归正文:
到这里,我们知道了:
英文在计算机里用的是ASCII编码标准,1个英文字符占用1个字节。
中文在go语言中采用的是Unicode字符集,1个汉字占用3个字节。

1字节 = 8 位

一共有 2的8次方 种组合方式,即256种组合方式。

对于中文来说,一个字节肯定是不能够把所有中文编进来的,因为一个字节的存储上限是256,所以说对于中文来说,它要用3个字节才能够把所有的汉字全部包括进来,或者说是在Unicode中文的数字区域内,它用3个字节才能把所有的中文的汉字给囊括进来。

所以说我们就要知道UTF-8编码,它实际上是用来保存Unicode的这种字符集的一种实现方式。【上文提到过还有UTF-16】

对于go语言来说,go语言对于字符串它采用了UTF-8编码,那UTF-8编码除了能够用三个字节表示一个中文之外,它还能够用一个字节表示英文,这什么意思呢?

实际上很简单,对于英文字符来说它的数字区域,大家可以去看一下Unicode的字符集或查看上文内容,用一个字节就已经能够存储英文字符了,而且是绰绰有余。

对于utf8编码来说,utf8又是一个动态编码,也就是说它不是说所有的字符全部采用等长的这种直接占用,那这样的话会浪费空间,所以说对于英文的编码来说,因为英文的它的编号正好是小于256的,所以说它就用一个字节来表示,就够了。

到这里,就知道了在go语言当做计算英文和中文的算法原因。

再看代码:

var name string = "keegan:写博客" // 一共由10个字符组成
fmt.Println(len(name)) // 16

为什么是7*1 + 3*3 = 16?而不是10 * 3 = 30?
我们可以试想一下,如果说每一个字符它都占3个字节的话,那这里边总共有10个字符,那它整个就应该占用10 * 3 = 30个对不对?

但是输出结果是16个,这说明后边3个中文总共占用9个字节,前边7个字符它总共占用7个字节,
总共加起来就是16个对吧?我们也可以只使用中文来验证一下。

 var name string = "写博客"
 fmt.Println(len(name))  //9

然后再一点一点地加点东西:

 var name string = ":写博客"
 fmt.Println(len(name))  //10
 
 var name string = "n写博客"  //转义字符也是一个字符,占用1个字节
 fmt.Println(len(name))  //10

好了,那对于我们来说这个问题它就产生了一个需求,怎么能得到它真正的长度呢?
这实际上就要涉及到类型转换。

我们可以将name给它转换一下,把它转换成什么类型呢?

把它转换成我们的数组的类型,数组的类型我们在后边也会介绍到。这个数组和我们平时写的数组也有很大的差异,我们把它转成什么数组?
rune

rune它实际上本质上是int32,那是因为它对于这种字符的处理,它主要用于字符的处理,所以说对于int32,我们专门又给它命了个别名rune,专门用于这种字符的处理。
int32是4个字节,int64是8个字节

实际上我们把rune写成int32也是一样的。
看代码:

 var name string = "keegan:写博客"
 fmt.Println(len(name))  // 16
 name_arr := []int32(name)
 fmt.Println(len(name_arr ))  // 10

在这里边什么意思呢?
这里边的意思就是将你的每一个字符,注意一下,每一个字符都转换成一个rune。
对于这种只有占用一个字节的字符的情况,即英文字符,它也会转成一个rune。

对于汉字这种来说,本身你占用3个字节,现在把你转化成int32了,已经占4个字节了,那这样的话大家看看你的中文,我全部都能包含进来对不对?无非多浪费一个空间。【4-3=1】

对于英文字符这种只占用1个字节来说,我给它又加了3个字节,但是它们加起来是一个rune。
对于这种只有3个字节的中文来说,我再给它加1个字节,让它凑够4个字节,也就是1个rune。

这样的话总共有多少个rune呢?
10个。因为这里是10个字符,每个字符都转化成rune了。

我们通过将字符串进行类型转换,转换成rune,再借用len函数计算出rune的长度,这个长度就字符串的长度。
即 rune的长度 = 字符串的长度
其实就是通过类型转换将求字符串长度转化成求rune的长度的问题。
rune的长度就像求数组的长度一样,里面有几个字符rune的长度就是几。

对于len来说,它能够求出数组的元素的个数,就能得到数组的长度。跟Python很相似。

再来看代码:

 var name string = "keegan:写博客"
 fmt.Println(len(name))  // 16
 name_arr := []rune(name) // []int32(name)
 fmt.Println(len(name_arr ))  // 10

现在我们就能够得到它的长度是10个了,对不对?
通过这样的类型转化,我们做到了可以从数字符串有几个字符/元素就能准确计算出字符串的长度就是几了。
即通过这样的类型转化, 字符串的个数 = 字符串的长度

但是我们也知道了这样做它实际上是浪费空间,你本身占的字节没有那么多,因为转成rune的话它占用的空间会多很多。
int32是4个字节,int64是8个字节。

以上是求长度的问题。

多说一点:
字符串可以看成字符数组,用索引取值:

 var name string = "keegan:写博客"
 fmt.Println(len(name))  // 16
 name_arr := []rune(name)
 fmt.Println(len(name_arr ))  // 10
 fmt.Printf("%T,%cn",name_arr,name_arr[9]) // []int32,客
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/357097.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号