Go中rune类型浅析
一、字符串简单遍历操作
在很多语言中,字符串都是不可变类型,golang也是。
1、访问字符串字符
如下代码,可以实现访问字符串的单个字符和单个字节
package main
import (
"fmt"
)
// 字符串每个字节十六进制打印
func printBytes(s string){
fmt.Printf("Bytes: ")
for i := 0; i < len(s); i++{
fmt.Printf("%x ", s[i])
}
fmt.Printf("\n")
}
// 打印字符串的每一个字符
func printChars(s string) {
fmt.Printf("Charaters: ")
for i := 0; i < len(s); i++{
fmt.Printf("%c ", s[i])
}
fmt.Printf("\n")
}
func main(){
var s1 = "golang"
fmt.Printf("s1: %s, len(s1)=%d\n", s1, len(s1))
printBytes(s1)
printChars(s1)
}
执行结果为:
s1: golang, len(s1)=6
Bytes: 67 6f 6c 61 6e 67
Charaters: g o l a n g
字符串golang长度为6,%x按照十六进制格式输出每一个字符的ASCII码,%c对应格式输出每一个字符。
2、查看中文字符存在问题
上述代码针对字符串s1=golang没有异常,看起来实现的两个函数也是访问字符串单个字符的合法方式,但这有一个严重的错误。上面的程序没有考虑字符串中一个字符占多字节的情况,例如 中文字符。来看下面代码:
package main
import (
"fmt"
)
// 字符串每个字节十六进制打印
func printBytes(s string){
fmt.Printf("Bytes: ")
for i := 0; i < len(s); i++{
fmt.Printf("%x ", s[i])
}
fmt.Printf("\n")
}
// 打印字符串的每一个字符
func printChars(s string) {
fmt.Printf("Charaters: ")
for i := 0; i < len(s); i++{
fmt.Printf("%c ", s[i])
}
fmt.Printf("\n")
}
func main(){
var s2 = "Go编程"
fmt.Printf("s2: %s, len(s1)=%d\n", s2, len(s2))
printBytes(s2)
printChars(s2)
}
执行结果为:
s2: Go编程, len(s1)=8
Bytes: 47 6f e7 bc 96 e7 a8 8b
Charaters: G o ç ¼ * _ ^ ~
按照想法,应该正常打印出Charaters: G o 编 程的字符,但是输出Charaters: G o ç ¼ *乱码,而明显的长度应该为4,这里显示len(s1)=8,长度为8。
3、原因
golang中string底层是通过byte数组实现的,所以直接求len,实际是在按字节长度计算。中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码正好是utf-8。所以一个汉字占3个字节算了3个长度。所以打印长度为8=2(Go)+3(编)+3(程)。
二、rune类型
1、使用rune类型遍历字符
如何按照预期一个包含中文字符的字符串长度,而非字节长度?代码如下:
package main
import (
"fmt"
"unicode/utf8"
)
func printChars(s string) {
fmt.Printf("Characters: ")
runes := []rune(s)
for i := 0; i < len(runes); i++ {
fmt.Printf("%c ", runes[i])
}
}
func main() {
var s = "Go编程"
fmt.Println("s :", s)
// 输出字符占用字节个数
fmt.Println("len(s):", len(s))
// 方案一
//golang中的unicode/utf8包提供了用utf-8获取长度的方法
fmt.Println("RuneCountInString:", utf8.RuneCountInString(str))
//方案二
//通过rune类型处理unicode字符
fmt.Println("rune:", len([]rune(str)))
printBytes(s)
}
执行结果:
s: Go编程
len(s): 8
RuneCountInString: 4
rune: 4
Characters: Go编程
可以通过rune类型转换可以正常输出每个中文字符,包括字符串中的字符个数。
说明:golang中rune是内置类型,是int32类型的别名,而byte数据类型等同于int8类型
- byte常用来处理ascii字符
- rune可以处理utf-8字符
2、 获取字节下标
为了更进一步看清楚每个字符占用的字节数,查看字符串中字符的字节下标
package main
import (
"fmt"
)
func charsIndex(s string) {
for index, r := range s {
fmt.Printf("字符 %c 从第 %d 个字节开始\n", r, index)
}
}
func main() {
s := "Go编程"
fmt.Println("s: ", s)
fmt.Println("len rune:", len([]rune(s)))
charsIndex(s)
}
执行结果如下
s: Go编程
len rune: 4
字符 G 从第 0 个字节开始
字符 o 从第 1 个字节开始
字符 编 从第 2 个字节开始
字符 程 从第 5 个字节开始
从上面输出可以看到,在utf-8编码下,每个英文字符占用1个字节,中文字符占用3个字节。
Go中rune类型浅析的更多相关文章
- go中rune和byte的用处
参考:https://www.jianshu.com/p/4fbf529926ca rune是用来区分字符值和整数值的 byte 等同于int8,即一个字节长度,常用来处理ascii字符 rune 等 ...
- Go语言中byte类型和rune类型(五)
本篇内容本来准备在上一篇写的,想了想还是拆开写. go语言中字符串需要使用用双引号,而单引号用来表示单个的字符,字符也是组成字符串的元素.go语言的字符有两种: uint8类型,或者叫 byte 型, ...
- 详解Java 8中Stream类型的“懒”加载
在进入正题之前,我们需要先引入Java 8中Stream类型的两个很重要的操作: 中间和终结操作(Intermediate and Terminal Operation) Stream类型有两种类型的 ...
- SQL 中不同类型的表连接
http://www.linuxidc.com/Linux/2012-08/68035.htm 1.简介 在关系型数据库中,join操作是将不同的表中的数据联合在一起时非常通用的一种做法.首先让我们看 ...
- Object-C中动态类型对象相关操作汇总
Object-C(以后简称OC)中有id类型,相对于明确定义类型的静态类型,称为动态类型. 使用动态类型,配合多态(不同类型拥有同名方法),动态绑定(运行时决定实际调用的方法)可以将很多判断延迟到运行 ...
- MYSQL中 ENUM 类型
MYSQL中 ENUM 类型的详细解释 ENUM类型 ENUM 是一个字符串对象,其值通常选自一个允许值列表中,该列表在表创建时的列规格说明中被明确地列举. 在下列某些情况下,值也可以是空串(&quo ...
- 第66课 C++中的类型识别
1. 类型识别 (1)在面向对象中可能出现下面的情况 ①基类指针指向子类对象 ②基类引用成为子类对象的别名 ▲静态类型——变量(对象)自身的类型(定义变量类型时类型或参数类型) ▲动态类型——指针(引 ...
- 【翻译自nikic大神】PHP中原生类型的方法
引言 第一次,翻译别人的文章,用四级英语的水平来翻译~~囧,可能有很多不太恰当的地方,尽管拍砖(有些地方实在想不到恰当的翻译,我同时贴出了原文和自己很low的翻译). 翻译这篇文章用了我3个晚上一个中 ...
- SQL批量更新数据库中所有用户数据表中字段类型为tinyint为int
--SQL批量更新数据库中所有用户数据表中字段类型为tinyint为int --关键说明:--1.从系统表syscolumns中的查询所有xtype='48'的记录得到类型为[tinyint]的字段- ...
随机推荐
- A Beginner’s Introduction to CSS Animation中文版
现在越来越多的网站正在使用动画,无论是以GIF,SVG,WebGL,背景视频等形式. 当正确使用时,网络上的动画带来生机和交互性,为用户增添了额外的反馈和体验. 在本教程中,我将向您介绍CSS动画; ...
- 两个echarts地图联动高亮区域
项目要求左右两张地图能够在鼠标悬浮的时候高亮部分联动,曾尝试了connect不好使,所以自己写了这段代码.代码思路为: 鼠标移入地图时,另一侧的地图根据鼠标悬浮获取到的区域name使该区域高亮: 鼠标 ...
- python-成绩转换
本题要求编写程序将一个百分制成绩转换为五分制成绩.转换规则: 大于等于90分为A: 小于90且大于等于80为B: 小于80且大于等于70为C: 小于70且大于等于60为D: 小于60为E. 输入样例: ...
- 【uniapp 开发】如何给边框添加阴影效果
css的box-shadow是用来添加边框阴影效果的. 属性值详解: 1.inset 可选值,默认阴影在盒子外 使用inset后,阴影在盒子内,即使指定边框或者透明边框,阴影依然存在. 2. 这是头两 ...
- java中如何使用接口继承(Extending Interfaces)
5.接口继承(Extending Interfaces)和通话talk的功能.而Moto888更为高级,除了照相和通话功能以外,还有mp3的功能.接口继承到底有什么意义呢?马克-to-win:1)通过 ...
- UML与面向对象程序设计原则
[实验任务一]:UML复习 阅读教材第一章复习UML,回答下述问题: 面向对象程序设计中类与类的关系都有哪几种?分别用类图实例说明. 1. 关联关系 (1) 双向关联 (2) 单向关联 (3) ...
- SQL语句总结---表操作
https://blog.csdn.net/hallomrzhang/article/details/85010014 表的操作 1.查看表结构 desc 表名 2.创建表结构的语法 create t ...
- 给一个非矩形数组(Nonrectangular Arrays)
Nonrectangular Arrays(非矩形数组) public class Test { public static void main(String[] args) { ...
- CentOS7 Network Setting
#display devices[root@localhost ~]# nmcli d #set ipv4 address[root@localhost ~]# nmcli c modify eth0 ...
- SSM实现个人博客-day01
1.需求分析 项目源码免费下载:SSM实现个人博客 有问题请询问vx:kht808