1、简介编码方式

计算机的视角,世间万物不过是一串又一串的二进制字节流,以人类认识的字符为例,每一个字符串就必须有与之对应一个二进制码,这就叫做编码。然而在发明计算机时,发明者们只考虑到计算机处理的是小写字母和大写字母,以及一些特殊字符,这些加起来不超过128个,所以采用1字节(0-255)空间大小来编码绰绰有余,这就是经常听到的ASCII码;‘a’对应的ASCII码为97,‘b’对应的ASCII为65。

随着计算机的普及,计算机要处理不单单是英文字母,中国人也要使用计算机,对于那么多的中文汉字,ASCII码显然不够使用,于是后续就有了中国人为中文提出GBK,BG2312等编码,这些编码现在还有在使用。为了兼容任何国家的所有字符,国际上提出了Unicode编码:一个字符,不管是英文字母,还是中文汉字,还是其他,都统一用2字节来表示,2字节的大小已经能让计算机处理世界上的任何字符了。

但是对于一个只需要1字节空间大小就可以描述的英文字母来说,使用2字节(没用到的位填0)实在浪费,当时计算机硬件又比较珍贵,所以后续又提出基于Unicode的变换编码,UTF-8或UTF-16等,其中UTF-8是最为普及的。UTF-8是一种可变长的字符编码方式:对于英文字母还是采用1个字节表示,对于中文汉字则采用3字节。这里可能有人会问,Unicode编码表示中文才2字节,为什么UTF-8反而需要占据3字节?这是因为编码算法,UTF-8需要一些额外数据位记录以作区分,详细的UTF-8这里不做过多介绍,详细网上资料很多。

2、字符串常量和字符串标准库

我们知道c/c++中字符串有字符串常量和变量两种形式:

const char *str = "hello"; //字符串常量
char str2[] = "world";     //字符串变量

字符串变量str2是可通过数组下标或者指针的方式修改字符的,Lua语言则不同,它只有字符串常量,是不可变值。Lua中可以使用一对双引号或单引号来定义字符串常量:

str1 = “Lua: hello”
str2 = ‘Lua: world’

单引号和双引号是等价的,使用时注意配对即可。

因为Lua的字符串是不可变值,所以对字符串的任何修改、拼接操作都只能通过创建新字符串的方式实现。

Lua语言解析器本身处理字符串的能力十分有限:创建字符串,连接字符串和比较字符串、获取字符串长度:

(1) …用于实现字符串连接,如果操作数中存在数值类型,Lua会先将数值转为字符串;
(2) #操作符用于获取字符串长度,该操作符返回字符串占用的字节数。

Lua处理其他字符串的操作则依赖于Lua字符串标准库。字符串标准库默认处理的是占据1字节空间的字符,所以它仅适用于ASCII编码和部分UTF-8编码,不适用于Unicode编码;下面是标准库中常用的函数。

> str="abcd"
> print(string.len(str))  --获取字符串长度4
> string.rep("123", 4)    --创建由4个"123"组成的字符串123123123123
> string.reverse("abcd")  --字符串翻转dcba
> string.lower("AbCd")    --将字符串转为小写abcd
> string.upper("AbCd")    --将字符串转为大写ABCD

使用Lua字符串标准库的gsub()函数作字符串替换:

> str1 = "hello Shanghai"
> str2 = string.gsub(str1, "Shanghai", "Shenzhen")
> print(str1)
hello Shanghai
> print(str2)
hello Shenzhen

注意,调用字符串标准库的gsub()函数的调用需要指定作用域string。

string.sub(s, i, j)实现从字符串s中提取第i个到第j个字符(包括第i个和第j个,且字符串的第一个字符为索引值为1);该函数也支持负数索引,负数索引是从字符串的结尾开始计数,-1表示字符串的最后一个字符,-2表示倒数第二个字符,以此类推。如:

> string.sub(str, 2, -2)
hello lua
> string.sub(str, 1, 1)
[
> string.sub(str, -1, -1)
]
> print(str)
[hello lua]
>

string.char()和string.byte()函数实现字符和编码数值之间的转换:
string.char()接收零个或者多个整数作为参数,实现将每个整数转换成对应的字符,返回这些字符连接而成的字符串。

函数string.byte(s, i)返回字符串s中的第i个字符的编码数值,参数i是可选的,不指定i时返回字符串s中的第一个字符。该函数还支持string.byte(s, i, j)形式以返回索引i到j之间(包括i和j)的所有字符的数值表示:

> print(string.char(65))
A
> i = 65; print(string.char(i, i + 1, i+ 3))
ABD
> print(string.byte("abc"))
97
> print(string.byte("abc", 2))
98
> print(string.byte("abc", -1))
99
> print(string.byte("abcd", 2, 4))
98  99  100

string.byte(s, i, j)常见的用法为:

{ string.byte(str, 1, -1) }

这样将创建一个表,表中的成员对应字符串s每个字符对应的编码数值。由于Lua限制了栈的大小,所以该表的成员个数最多1百万个,对应的字符串大小不超过1MB。

string.format()函数是字符串的格式化和将数值格式化为字符串的强大工具,其返回值是格式化后的字符串的副本。格式化字符串中的指示符(如%s、%c、%d)跟c语言中的print()函数规则类似。

> print(string.format("hello %s", "lua"))
hello lua
> string.format("x=%d, y=%x, z=%f", 12, 200, 16)
x=12, y=c8, z=16.000000
> string.format("x=%04d, y=%#x, z=%.2f", 12, 200, 16)
x=0012, y=0xc8, z=16.00

基于模式匹配的函数,如string.find()用在指定的字符串中进行搜索:

> string.find("hello lua", "lua")
7  9
> string.find("hello lua", "python")
nil

string.find()在指定字符串中到匹配的模式则返回该模式的开始和结束位置的索引,否则返回nil。

3、 utf-8字符串标准库

Lua字符串标准库只部分支持utf-8字符串:reverse()/upper()/lower()/byte()和char()针对的操作对象是1字节大小的字符,不可适用于utf-8编码的全部字符(比如一个中文字符的大小是3个字节);函数string.format()和string.rep()适用于utf-8字符串但是格式化选项不可以是“%c”,其索引并非以字符为单位而是以字节为单位。

Lua 5.3引入了用于操作utf-8编码的Unicode字符串的标准库,我们称之为utf-8字符串标准库。函数utf8.len()返回字符串中utf8字符(代码点。比如“编程”二字占据6个字节,其代码点为2,代码点计算的是真正的字符数而非字节数)的个数。

> string.len("编程")
6
> utf8.len("编程")
2

函数utf8.char()和utf.codepoint()等价于string.char()和string.byte():

> utf8.char(32534, 31243)
编程
> utf8.codepoint("编程")
32534
> utf8.codepoint("编程", 1)
32534

通过utf8.codepoint()打印“编程”中的“程”的utf编码:

> utf8.codepoint("编程", 2)
stdin:1: invalid UTF-8 code
stack traceback:[C]: in function 'utf8.codepoint'stdin:1: in main chunk[C]: in ?
> utf8.codepoint("编程", 4)
31243

从运行结果可看,不可通过索引2去获取“编程”中的“程”,而是要用4,这是因为utf8库中大多数函数使用字节作为索引,“编”字占据3字节,“程”的索引值是4。如果想要字符位置作为索引,可借助utf8.offset()将字符位置转为字节位置,也就是将字符索引转为字节索引:

> utf8.codepoint("编程", utf8.offset("编程", 2))
31243

utf8.codes()函数用于遍历utf8字符串中的每一个字符:

> for k, v in utf8.codes("池塘的水满了雨也停了") do
>> print(k, v)
>> end
1  27744
4  22616
7  30340
10  27700
13  28385
16  20102
19  38632
22  20063
25  20572
28  20102

Lua语言追求精简,所以没有再为Unicode编码提供更多机制。

4、Lua字符串其他特性

4.1、转义

Lua语言字符串支持c语言风格的转移字符,如:

\b: 退格
\n: 换行
\r: 回车
\t: 水平制表符
\v: 垂直制表符
\\: 反斜杠
\”: 双引号
\’: 单引号

另外,通过\ddd和\xhh声明字符,ddd是由最多3个十进制数字组成的序列,hh是由两个且必须是十六进制数字组成的序列,如:

> print("\065")
A
> print("\x41")
A
>

4.2、多行字符串

Lua的多行注释是用“–[[ 注释 --]]”的形式表示的,多行字符串的表示方式跟注释类似:

> html_str = [[
>> <html>
>> <head>
>> ...
>> </html>
>> ]]
>

4.3、强制类型转换

Lua语言在运行时会在数值和字符串之间自动转换,注意这种转换时不会出现在比较运算符的。

> a1 = "1"
> a2 = "3"
> print(a1 + a2)
4.0
> print(10 .. 24)
1024

注意,Lua中两个操作数都为整型值时进行算数运算才为整型,由于字符串不是整型值所以代码中a1加a2为浮点型;
函数tostring()和tonumber()可以显式地将数值转为字符串和将字符串转为数值。当操作数不能被正确转换时函数返回nil:

> print(tostring(100) == "100")
true
> tonumber("a")
nil
> tonumber("12")
12

默认情况下tonumber()转换后的数值为十进制,我们也可以指定为二进制到三十六进制之间的任意进制:

> tonumber("12", 16)
18
> tonumber("12", 2)
nil
> tonumber("10", 2)
2

比较操作符则不会进行类型转换,0和“0”不同,“2”<“16”为false(根据字母顺序比较),2<“16”比较时Lua语言会抛出异常:

> 0 == "0"
false
> 2 < 16
true
> "2" < "16"
false
> 2 < "16"
stdin:1: attempt to compare number with string
stack traceback:stdin:1: in main chunk[C]: in ?

字符串操作比较简单,但却是在使用实际开发的工作重心之一。

参考书籍:programming in Lua(fourth edition)

本文摘自公众号Linux开发者札记。如果觉得本文对你有点用处,欢迎关注。

字符串和字符串标准库相关推荐

  1. python字符串库函数_Python标准库概览(1):string

    Python的 string 标准库保留了一些有用的函数和用于处理文本对象的类,现在我们来一起看一下Python的string标准库还有哪些我们不知道的有趣用法? 01.capwords()函数:将字 ...

  2. 中英文数字字符串排序(标准库)

    需求 对ui显示的表格进行排序,需支持中文字母排序,但是sqlite数据库不支持中文的拼音和笔画排序,这样就会导致排序中文显示顺序无规律.这个时候,就需要自己写一个排序功能,且排序支持中文拼音排序. ...

  3. c++学习笔记--C++Primer第4版--标准库类型string

    string类型 一.概述 定义:支持长度可变的字符串,C++标准库将负责管理与存储字符相关的的内存,以及提供各种有用的操作. 目的:满足对字符串的一般应用. 需要导入string类库头文件,声明标准 ...

  4. 从零开始学C++之标准库类型(一):string 类简介和例程

    一.标准库string类型 string类型支持长度可变的字符串,C++标准库将负责管理与存储字符相关的内存,以及提供各种有用的操作 ,在VC中直接F1查看 template <class Ch ...

  5. C++primer 第 3 章 字符串、向量和数组 3 . 3 标准库类型vector

    标准库类型vector表示对象的集合,其中所有对象的类型都相同.集合中的每个对象都有一个与之对应的索引,索引用于访问对象.因为vector"容纳着"其他对象,所以它也常被称作容器( ...

  6. C++primer 第 3 章 字符串、向量和数组 3.1 命名空间的using声明 3.2标准库类型string

    引言 除了第2章介绍的内置类型之外,C++语言还定义了 -个内容丰富的抽象数据类型库.其中,string和 vector是两种最重耍的标准库类型,前者支持可变长字符串,后者则 表示可变长的集合.还有- ...

  7. 不属于python标准库的是_《Python Cookbook(第2版)中文版》——1.10 过滤字符串中不属于指定集合的字符-阿里云开发者社区...

    本节书摘来自异步社区<Python Cookbook(第2版)中文版>一书中的第1章,第1.10节,作者[美]Alex Martelli , Anna Martelli Ravenscro ...

  8. python中的字符串文本必须用什么括起来_Python标准库---18、文本处理服务:string 常见的字符串操作...

    字符串常量 此模块中定义的常量为: string.ascii_letters 下文所述 ascii_lowercase 和 ascii_uppercase 常量的拼连. 该值不依赖于语言区域. str ...

  9. Python输入一个字符串,输出其中每个字符的出现次数。要求使用标准库collotections中的Counter类...

    一.题目: 1.输入一个字符串,输出其中每个字符的出现次数.要求使用标准库collotections中的Counter类. 2.输入一个字符串,输出其中只出现了一次的字符及其下标. 3.输入一个字符串 ...

最新文章

  1. shell编程--case判断
  2. Gradle系列教程之依赖管理
  3. SSM框架之关于使用JSP作为视图展示问题解决方案
  4. SQL Server查询正在执行的存储过程并停止
  5. C#中的表达式和运算符
  6. Java h264起始码_h.264 – 使用H264视频的起始码
  7. 微信小程序 - 基础 - 003 - WEUI - 基本表单组件 - form - 页面数据提交和获取 - 01
  8. [转]详细易懂的Linux makefile教程(7)
  9. Win7批量压缩照片
  10. 自动化运维工具SaltStack
  11. 多线程编程之二——MFC中的多线程开发(收藏)
  12. 纯js代码-实战轮播图
  13. Scrapy网络爬虫系统
  14. ppt大小如何压缩,ppt压缩方法
  15. Latex如何写参考文献及修改顺序
  16. 太上玄门日诵早晚功课经序
  17. 网络表示学习简单总结(一)
  18. 怎么解决运行时输入错误,请重新输入以及专业无法输入的问题
  19. 计算机应用专业需要6g显卡吗,4G、6G、8G显卡的显存容量有什么用?来看科普
  20. C20_OC10-内存管理

热门文章

  1. 日志工具类——Log
  2. 文字检测与识别1-MSER
  3. 【2022年9月】237条微信内置浏览器UA
  4. C语言书籍阅读-读书笔记--高质量程序设计指南》--C/C++,林锐
  5. 最难毕业季,会Python简直可以开挂!!
  6. Roblox剑九之剑二
  7. 哪些实时翻译的软件好用?分享这三款好用的软件
  8. 浪漫又务实的华为自研之路: 始于情怀,终于智能
  9. 【应用场景】智能定位胸牌帮你识别高质量月嫂
  10. C++ operator 简单使用