一.Lua理解

Lua可以被理解成为不用编译就能运行的语言,所以被广泛用于热更新.

 

二.环境安装

1.SciTE:包括Lua控制台和IDE集成工具.控制台无法保存,工具类似于记事本可以保存脚本,还能编译运行(虽然Lua不用编译,但可以选择只编译不运行,编译后其实是生成一个中间文件).

下载地址:GitHub https://github.com/rjpcomputing/luaforwindows/releases

附加笔记:因为1个汉字占两个字节,所以删除1个汉字需要删2次,只删掉或者选择1个字节时,会出现乱码.

2.LuaDist:虽是官方推荐,但是似乎没有IDE,所以不太常用,不过界面要高级许多,像Windows10原生的工具.

 

三.与C#的区别

1.分号

C#

print("Hello World");     //每句结尾必须加";"

Lua

print("Hello World")       --可以不加";"
print("Hello World");      --也可以加";",没区别

2.注释

C#

//单行注释
/*
多行注释
*/

Lua

--单行注释

--[[
多行注释
--]]

--取消多行注释小技巧:由多行注释转变成单行注释:在一开头或者结尾增加一个"-"
---[[单行注释
--]]单行注释

3.定义变量

C#

int i=10;    //需要给一个int定义其类型

print(a);    //报错"a为未知变量"

Lua

i=10          --不需要定义其类型,默认为全局变量

print(a)      --因为不用定义其类型,所以出现一个新的变量就相当于已声明,若没有赋值的话,其值和类型为nil(意思为空)
              --所以该行并不会像C#一样报错"a为未知变量",而是输出的打印值为nil

--关于表的定义与销毁
table={key0=0,key1=1}   --声明并定义表类型
print(table.key0)
table.key0=nil          --销毁key0
print(table.key0)       --打印值为nil
table=nil               --销毁table,释放table的内存
print(table.key0)       --报错Error
//销毁一个变量后还能使用其名字,但这是一个新的变量了,所以原来的变量类型和其子值都不存在,能不嫩用子值还是要看有没有给他又定义了有子值的类型.

4.字符串

C#

//定义字符串
string str="This is a string.";  //只能用双引号表示字符串
print("Print a string");

//转行:转行符
string str1="a\nb";              //"\n"为转行符,注意是\,不是/

//连接字符串
print(str1+"a");                 //"+"可以连接字符串,输出This is a string.a
print(1+2);                      //"+"还可以进行算术运算,输出3

//获得字符串长度:字符串.Length
print(str.Length);

Lua

--定义字符串
str1='This is string1'             --单引号/双引号都可以表示字符串
print('Print a string1')
str2="This is string2" 
print("Print a string2")

--转行:多行字符串
str1="abc"                         --单行字符串
str2=[[                            --多行字符串
First line.                        --第一行
Second line.                       --第二行
Third line.                        --第三行
]]

--连接字符串:..双点符号
print(str1..str2)                  --输出4行
print("a".."b")                    --输出ab

--运算符"+ - * /":会把数字字符转换成数字然后根据运算符进行运算(只限数字字符)
print("1"+"2")                     --输出3
print("1"+2)                       --输出3,支持混合运算,反正数字字符被当作数字来用
print("1"-2)                       --输出-1
print("2e2"*"6")                   --输出1200,2e2=200
print("2e2"/"10")                  --输出20

--获得字符串长度:在字符串前面加#井号,就变成了number类型的长度
print(#str1)                       --输出3
print(#"abcde")                    --输出5
print(#"你好ab")                    --输出6,一个汉字占两个字节

5.布尔数据类型

C#

bool b1=true;
Boolean b2=false;   //Boolean数据类型依赖于命名空间"using System"

//一般用"关系运算符"或"逻辑运算符"连接起来的"关系表达式"或"逻辑表达式"都代表一个bool值,通常用来作为判断语句的条件
//关系运算符:> < == >= <= != 共6个
//逻辑运算符:|| && ! 共3个
if(b1==true) print("b1==true");          //b1==true就是关系表达式
b1=(1>0&&b2==false)?true:false;          //1>0&&b2==false就是逻辑表达式(包括逻辑运算符就是逻辑表达式)   

//除了"关系表达式"和"逻辑表达式",其他适用直接作判断条件的数据类型
if(0) print("0可以用来判断");              //报错,int类型0不能转换成bool类型
if(null) print("null可以用来判断");        //报错,null不能转换成bool类型

GameObject obj=null;                      //声明obj(未赋值)
if(obj) print("被赋值的物体可以用来判断");  //报错:obj为未赋值变量
obj=null;                                 //给obj赋值为null
if(!obj) print("被赋值的物体可以用来判断"); //打印改行:因为obj=null,所以!obj=true
//总结:除了bool类型以外的常量类型,都不能转换为bool类型(也不能强制转换),所以不能用来作判断条件.
//     而GameObject类型的必须赋值后,才能作判断条件,除了=null时作判断条件为false,=其他值时都为true.

Lua

b=true                                --boolean类型只包含true和false两个值
if nil or false then
 print('nil和false至少一个被当作true')
elsd
 print('nil和false都被当作false')      --false和nil被当作假
end

if 0 then
 print('0被当作true')                  --除了nil和false被看作假,其他值包括0都被当作真
end

6.获取变量的类型

C#

//使用GetType()方法获取变量类型
int i=0;
print(i.GetType());    //打印:System.Int32
print(0.GetType());    //打印:System.Int32,常量也可以用该方法获取类型

Lua

--使用"type(变量名)"的方法
print(type(false))        --打印boolean
print(type(nil))          --打印nil
print(type(10))           --打印number
print(type(1.1))          --打印number
print(type(print))        --打印function
print(type(x))            --打印nil,未赋值的变量都为nil类型

7.数字类型

C#

//数值类型包括整数型和浮点型,无符号整型在基本类型前加一个"u",其只有非负值
sbyte = -1;            //8位整形
short = -1;            //16位短整型
int i = -1;            //32位整形
long l = -1;           //64位长整形
float f = -1.0f;       //32位单精度浮点型,6~7位有效小数
double d = -1.0;       //64位双精度浮点型,15~6位有效小数

//给无符号型变量一个负值,C#会报错(只有无符号整形,没有无符号浮点型)
byte = 1;              //无符号8位整形
ushort = 1;  
uint i2 = 1;
ulong l = 1;
//附加:C语言里,用unsigned int定义,赋值给unsigned类型一个负值,不会报错,可以根据补码的算法得到其实际值

Lua

--只有number类型,包括整数型和浮点型,以下打印出来全为number类型
print(type(2))
print(type(2.2))
print(type(0.2))
print(type(2e+1))		--e+1=10的1次方,即10
print(type(0.2e-1))		--e-1=10的-1次方,即0.1
print(type(7.82647392e-06))	--e-06即10的-6次方,小数点向左移动6位

8.字典与数组

C#

//C#需要new初始化一下,索引从0开始,Lua从1开始

//数组,长度不可变,数据类型只限定义的类型,元素中间可以有空值
int[] i1=new int[3];
int[] i2={0,1,2};                 //数组长度为3,定义之后不能再这样批量赋值,例i1={7,8,9}是错误的
i1[0]=100;
Array.Copy(int[] array1,int[] array2,int length);//从array1的0索引元素开始,复制length个元素,然后从array2的0索引开始粘贴
Array.Copy(int[] array1,int index1,int[] array2,int index2,int length) 
                                 //从array1,index1索引元素开始,复制length个元素,然后从array2的index2索引开始粘贴

//字典,长度可变,数据类型只限定义的类型(关键字不能修改,只能修改值).
//需要"using System.Collections.Generic;"命名空间,"using System.Collections"不行
Dictionary<关键字的数据类型1,值的数据类型2> d=new Dictionary<数据类型1,数据类型2>();
Dictionary<string,int> d=new Dictionary<string,int>();
d.Values;                        //只包含字典的值的一维数组
d.Keys;                          //只包含字典的关键字的一维数组
d[关键字]=100;                    //关键字是string字符串类型
d.Add(关键字,值);                 //注意关键字和值的数据类型
d.ContainsKey(关键字);            //是否包含指定的键,返回bool值
d.ContainsValue(值);              //是否包含特定值,返回bool值            
d.GetEnumerator();               //返回循环访问 Dictionary的枚举数,具体看下面"11遍历方法"
d.TryGetValue(关键字,out result);//获取与指定的键相关联的值
...

//ArrayList列表,长度可变,数据类型可有多种,都装箱存储为object类型,所以只是用动态数组的话还是比较推荐下面的List
ArrayList aL=new ArrayList();
aL[0]=100;                          //修改                                      
aL.Add(要添加的对象);                //增加,在末尾位置
aL.RemoveAt(键值);                  //删除,键值=0则删除第1个元素,后面的元素自动补空
aL.Contains(要判断是否在列表里的对象);//检查是否存在
aL.Insert(插入位置键值,要插入的对象); //插入,从该位置起所有元素后移一位,在该键值处插入该对象
aL.Clear();                         //清空列表
aL.AddRange(批量对象);               //批量增加
aL.RemoveRange(批量对象);            //批量删除
aL.InsertRange(插入位置键值,批量对象);//批量插入
...

//列表,长度可变,数据类型只限定义的类型
List<int> l=new List<int>();
l[0]=100;                           //修改                                   
l.Add(要添加的对象);                 //增加
l.Remove(要删除的对象);              //删除,后面的元素自动补空
l.Contains(要判断是否在列表里的对象)  //检查是否存在
l.Clear();                          //清空列表
...

//Queue队列,先进先出,先不写占个位置

//.Length是他们的长度.Array是可以转换成数组的,但有限制;字典也可以转换成List,但GC较高.

Lua

--table表类型:可以当作字典使用,也可以当作数组使用,其长度不固定,大小也不确定.

--索引key数字类型的key和字符串类型的key混合存在.

--当key为数字类型的时候,是可以为负数的,例如arary[-1]=10.

--二维数组就是把一维数组的每个元素赋值为一维数组(表),多层以此类推

--第一种表:空表
tab1={}                                 --{}构造表的符号,表示tab1的类型为表
print(tab1[1])                          --可以用3种方法获得键值,但以为是空表所以值全是nil
print(tab1["key"])
print(tab1.key)

--第二种表:字典表,以(key=value)键值对的形式存储键值,key都是字符串类型的(不用加引号)
tab2={key1=100,key2="value2"}           --初始化
print(tab2["key"])                      --可以用2种方法获得键值
print(tab2.key)

--第三种表:数组表,只存储值,key(即关键字/索引)为数字类型默认值为1.2.3.4...(从1开始,C#从0开始),但是可以不连续
tab3={"apple",100,"orange","grade"}     --初始化
print(tab3[1])                          --可以用1种方法获得键值
tab3[1]=nil                             --销毁第一个键值对
                                        --若是遍历打印,就会发现从第二个键值对开始打印(并不会打印1:nil哦)
                                        --并且第二个键值对的key值还是2,不会变成1

--对表进行操作:
1.取值方法有3种(与空表一致):
  tab1[1])       //键值为number类型
  tab1["key"]    //键值为字符串类型
  tab1.key       //键值为字符串类型
2.修改值:直接用上面的取值直接再赋值就行,可以随便再赋值其他数据类型的值.

--多维数组有两种定义方法

--直接赋值为多维数组
array1={{"小明","小红"},{"小刘","小狼"}}

--一维数组中每个元素都可以被赋值为一个一维数组
array2={}
for i=1,3 do
    array2[i]={}
    for j=1,2 do
        array2[i][j]={}
        for k=1,2 do
            array2[i][j][k]=i*j*k
        end
    end
end

四.与C#面向对象的区别

C#

class c1                                      //类
{
    public static void main(string[] args)    //入口方法
    {
    }
}

Lua

--直接写,就可以运行,没有类的概念,但是也有其他方法来实现面向对象
--Lua是用table来实现类似于C#的类的

 

 

 

 

 

 

 

 

五.数据类型

数据类型

描述

nil

只有值nil属于该类,表示一个无效值,在条件表达式中相当于false,赋值为nil则表示销毁数据并释放所占内存

boolean

包括两个值:false和true.判断时,除了false和nil,其他值都被当作true处理(包括0).

number

表示双精度Double类型的实浮点数(包括整形和小数)

string

字符串由一对双引号或单引号来表示

function

由C或Lua编写的函数

userdata

表示任意存储在变量中的C数据结构

thread

表示执行的独立线路,用于执行协同程序

table

Lua中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串.在Lua里,table的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表.

 

 

 

 

 

 

 

 

 

 

 

 

1.thread(线程)

在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。

线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。

2.userdata(自定义类型):

userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。

 

六.函数

C#

int function(string str)             //需要定义函数返回的数据类型和参数的数据类型
{
    int i=0;
    print(int.TryParse(str,out i));  //int.TryParse返回true/false,若str是数字字符,则true,否则false
    return i;                        //函数返回的数据类型不为void,则必须有该返回语句
}

//引用function(string str)
int j=function("q");                 //j=0,打印false
int k=function("1");                 //k=1,打印true

Lua

函数的定义:

--Lua的函数()和方法都用end来控制范围(C#用花括号"{}"控制范围,Lua的花括号"{}"表示构造table表类型)

--函数类型/函数参数/变量都不用声明类型,返回值可有可没有

--格式:
[local]function 函数名(参数1,参数2...)
    执行语句1
    执行语句2
    ......
    return 返回值1,返回值2...
end

--[local]修饰符,如果是局部参数则加,否则不加.
--不需要定义函数返回的数据类型
--不需要定义参数的数据类型,return语句可以有可以没有,return语句可以同时返回1~多个返回值(示例看"八.多变量同时赋值").
--示例:
function func1(n)          --函数用"函数头+end"来控制函数范围
    print(n)                    
    if n>1 then            --判断:"if 判断条件 then 执行语句 end"
        return n
    end
end
--调用(func1(2)就是调用)
print(func1(2))            --输出两行2

 --函数作为值赋给其他的变量(函数是一种数据类型)

function func1(n)
    print(n)                    
    if n>1 then
        return n
    end
end
--赋值
func2=func1                --现在func2是和func1一样的函数
--调用
print(func2(2))            --输出两行2
print(func2(1))            --输出1,第二行输出空(不是nil,是啥都没有)
print(func2("a"))          --报错,因为上面用了与数字类型的比较,也体现了Lua数据使用方法的不安全性

--函数做参数(相当于C#里的委托和事件,具体看这篇).

tab={key2="val1",key="val2"}
function f1(k,v)
	print(k..":"..v)
end

function testFun(tab,fun)	--函数作参数
    for k,v in pairs(tab) do    --复习遍历方法:for 变量1,变量2 in pairs(表) do 执行语句 end
	fun(k,v)
    end
end

testFun(tab,f1)			--引用函数
                                --运行的时候,传入的实参不能有nil,所以函数testFun和其参数tab/f1都要在引用之前定义赋值.

--匿名函数:适合"只用一次"且"操作语句少"的函数.直接在引用里定义匿名函数.

--没有函数名所以不能被别的地方引用,但是可以把它赋值给新变量,就相当于有了函数变量名,就可以被--引用了.

tab={key2="val1",key="val2"}
function testFun(tab,fun)
    for k,v in pairs(tab) do
	fun(k,v)
    end
end

--匿名函数作参数
testFun(tab,                  --引用函数
function (k,v)                --直接在引用里定义匿名函数.
	print(k..":"..v)
end)

--匿名函数作为值赋给其他变量(相当于有了变量名)
myprint=function(param)
            print("这是我的打印函数"..param)
        end
myprint(100)                --调用函数

七.全局变量/局部变量,生命周期,制造语句块(控制局部变量生命周期)

C#

public int i_1;      //外部可访问的全局变量
private int i_2;     //本文件内可访问的全局变量
void Fucntion()
{
    int i_3;         //fuction内的局部变量
}
//这里先不罗列static变量了

Lua

--全局变量
a=5  			--默认全局
print(type(a))
a="Hello"		--可以随意赋值其他数据类型的值
print(type(a))
--局部变量:访问局部变量比全局变量快,更节约内存.
local b=10
print(b)

--在语句块内,如果你用系统自带的变量名字(自动接收数据),命名新的局部变量,则整个语句块内的该变量以你定义的局部变量为准
function test(...)                     --如果没有再定义arg的话,系统默认arg={...,n=参数数量}	
    for k,v in pairs(arg) do           --pairs()括号内不能为nil,且类型必须键值对
        print(k,v)
    end
    local arg={...}		       --这里再次定义arg变量(有等号就是重新定义)获取{...}(不包括n=参数数量了),那么上面的arg则是只声明但是没有定义的变量,所以导致pairs()内的值是nil然后报错.正确的做法是在语句块的开头"抢占"该名字.
    print(arg)
end
test(10)                               --调用函数
--生命周期(从创建到销毁,也可以称为有效范围)
--全局变量生命周期:全局
--局部变量生命周期:语句块内(若在文内定义局部变量,则全文内有效)
function test()
	c=5		--在函数内声明全局变量,在函数外也有效
	local d=6       --d的声明周期到该函数的语句块end位置结束
end
print(c,d)		--nil nil.若不调用函数,则函数语句块不执行
test()
print(c,d)		--5 nil

--制造语句块:do 执行语句块 end. (可用来控制局部变量生命周期)

--自创语句块:do 执行语句块 end.会自动执行
do
	local a=10	--局部变量与全局变量重名,语句块内以局部变量为准
	b=11
	print(a,b)	--10 11
end
print(a,b)              --Hello 11

八.多变量同时赋值

C#

//只能同种类型的变量,并且要赋相同的值时才能多变量一起赋值
int j,k;
j=k=1;
print(j+" "+k);         //打印要自己拼字符串

Lua

--多个值同时处理时,用","逗号隔开

a,b=10,20	        --不是a=10,b=20;而是先得到右边所有的值,然后一起赋给左边的值
a,b=b,a
print(a,b)	        --20 10(而不是20 20)

a,b,c=11,21,"Hello"	--可以赋不同类型的值
a,b=10,20,30            --30自动被省略
a,b,c=10,20             --c被赋值为nil

 --函数可以返回多个值(赋给多个变量)

function test()
    return 40,50        --返回多个值
end

a=test()
print(a)                --40
a,b=test()
print(a,b)              --40 50

九.循环

C#

包括while/foreach/for/do..while四种方法.可以互相嵌套.

//foreach遍历格式:
Dictionary<string,int> dic = new Dictionary<string,int>();
dic.Add("1",100);
foreach(KeyValuePair<string,int> pair in dic)
{
    print(pair);
}

//for方法:foreach会产生更多GC,所以还是推荐用for方法.
//for方法可以代替所有其他的方法,并且可以缩减代码量到for(初始设置;循环条件;执行内容)一行中.
for(int i;i<10;i++) print(i);
//while方法:
Dictionary<string,int> dic=new Dictionary<string,int>();
dic.Add("key1",0);
var enumerator=dic.GetEnumerator();
while(enumerator.MoveNext())              //MoveNext把enumerator指向下一个键值对
{
    print(enumerator.Current.Key);        //打印当前的key
    print(enumerator.Current.Value);      //打印当前的Value
}
//do..while方法:最后的";"分号别忘了
do
{
}while(循环条件);

Lua

包括while/数值for/泛型for/repeat until4中循环.可以互相嵌套.

--while循环:while(循环条件)do 执行语句 end
a=1
while(a<=20) 		  --()括号可加可不加,推荐加上
do			  --do也可以另起一行
	if(a%2==1) then   --加减乘除似乎和C#用法一样
	print(a)
	end
	a=a+1		  --没有自增自减方法++/--,因为--是注释嘛
end
--数值for循环:for i=start,end,step do 循环体 end
for i=1,10 do		--i从1自增到10,默认每次+1
	print(i)
end

for i=20,1,-3 do	--i从20自减到1,每次-3
	print(i)
end
--泛型for循环
tab1={key1="val1",key2="val2"}
for k,v in pairs(tab1) do            --相比C#,不是用foreach而是用for,少了()和{},多了do和and关键字
    print(k,v)
end

tab2={"apple","banana",1,2,3}
for k,v in pairs(tab2) do            --pairs()是一个方法,用来取一对儿值
    print(k,v)
end
--repeat until(相当于C#的do..while):repeat 循环体 until (停止循环条件).先执行一次再开始判断
a=1
repeat
    print(a)
    a=a+1
until(a>10)                           --不需要end

--循环嵌套例子:

--for/while嵌套
for i=1,10 do
    j=1
    while(j<=i)do
        print(i)
        j=j+1
    end
end

十.流程控制(if判断语句)

C#

//if(bool)...else if(bool)....else
int a=50;
if(a>50)
 print("a>50");
else if(a<50)
 print("a<50");
else
 print("a=50");

Lua

--if(布尔表达式)then...elseif(布尔表达式)then...else...end
--布尔表达式的"()"可加可不加,C#必须加,Lua还多了"then"和"end".
--elseif中间没有空格

if(not a)then                --C#的!/&&/||逻辑运算符在lua中为not/and/or
    print("a不存在")
elseif(a<=100)then
    print("a<=100")
elseif(0)then                --除了nil和false代表假,其他都代表真,0也代表真
    print("0被当作true")
else
    print("a>=100and0被当作false")
end

十一.可变参数(参数数量可变)

C#

C#的函数定义了几个参数就只能传入几个参数,参数数量不可变.若非要用不定数量的参数,只能借助于长度可变的List/ArrayList/Dictionary等数据类型.

Lua

--可变参数:指参数的数量可变
--例如print()函数,可以有任意个数参数,逗号隔开

--定义可变参数的函数:funcyion 函数名(...) 执行参数 end
function average(...)           --系统默认arg={...,n=参数数量}
    local arg={...}	        --加不加Local都可以,推荐加上.这步是重新定义(=)使arg不包括n=参数数量,以方便数值的批处理
    sum=0
    for k,v in pairs(arg) do
	sum=sum+v
    end
    print(sum/#arg)
end

--可以传入不同个参数
average(10)
average(10,30)
average(10,30,50,80)

十二.算术运算符,关系运算符,逻辑运算符

C#

数学运算符:+  -(减/负)  *  /  %5种,平方需要用数学库Mathf.Pow(底数,指数).

关系运算符:>  <  >=  <=  ==  !=6种,C#的~是按位取反符.

逻辑运算符:&&  ||  ! 3种.

其他运算符:连接字符串用 "+" 号 ,获取长度则是访问属性".Length" .

Lua

--数学运算符:+ - * / % ^,加 减(负) 乘 除 余 幂
a=6
b=2
print(a+b)
print(a-b)
print(-a)
print(a*b)
print(a%b)
print(a^b)
--关系运算符:== ~= >= <= > <,关系表达式的值为boolean类型的(C#的"非等于"是!=,Lua是~=)
a=3
b=4
print(a==b)
print(a~=b)
print(a>=b)
print(a<=b)
print(a>b)
print(a<b)
--逻辑关系符:and or not,并 或 非
a=true
b=false
print(a and b)
print(a or b)
print(not a)
--其他运算符:.. # ,连接字符串 获取长度
print("Hell".."o")  	--".."字符串连接运算符
print(#"12345")		--"#"获取字符串长度,还能获取表的最大的数字key(会把字符串key忽略掉)
tab={0,2}
tab[4]=2
tab.key1=4
tab.key2=5
print(#tab)		--打印4

十三.转义字符

C#

\n \\ \"  \',其他查看下面Lua的链接,基本上转义字符都差不多.

Lua

--常用转义字符
print("a\nb")	--\n 换行
print("D:\\UnityProjects\\Test")   --\\ 代表 \,一般写地址字符串时要用到
print("\"a\"")	--\" 代表 “
print('\'a\'')  --\' 代表 ‘
print("'a'")	--里外引号不同可以不用转义
print('"a"')
--其他转义字符查看https://www.runoob.com/lua/lua-strings.html

十四.字符串常用操作函数

C#

Lua

--其他格式字符可以查看菜鸟教程:https://www.runoob.com/lua/lua-strings.html的"字符串格式化"

--字符串操作:例如string.upper(字符串),string是个表(但实质上实现了面向对象更像C#中的类),upper为函数类型
str="Hello World"
print(string.upper(str))	        --返回都变大写的字符串
print(string.lower(str))		--返回都变小写的字符串
print(string.gsub(str,"or","123",3))    --返回替换了的字符串,把"or"替换成"123",最多替换3个(可以不指定),字母区分大小写
print(string.find(str,"l",6))		--返回第1个l“的索引位置,从第6个索引位置开始寻找(可以不指定),搜索不到就为nil
print(string.reverse(str))		--返回反转了的字符串
print(string.char(97,98,99,100))	--返回根据ASCII码转换数字成的字符,可接受多个数字逗号隔开
print(string.byte("abcd",4))		--返回第4个字符的数字类型的ASCII码,可以不指定4,则默认是第一个字符
print(string.len("abcd"))		--返回字符串长度,功能#"abcd"
print(string.rep("abcd",2))		--返回复制2次并连接成的新的字符串

str="year"
num1=987
print(string.format("%s=%04d",str,num1))
--格式化,组拼语句,%04d表示保留4位,前面的空位补0,若没有0则空着位置.与C语言的输出方法printf类似

print(string.match("Hello Lua user.","%a+"))
--返回第一个符合"%a+"的一串字符,正态表达式pattern除了可以是"%a+",也可以是单个的字符常量比如"a"

for word in string.gmatch("Hello Lua user.","%a+") do
	print(word)
end
--string.gmatch("Hello Lua user.","%a+")返回没有索引key的一维数组,每个元素都符合"%a+"(指一串连续的字母),这里返回一个个单词
--"%a+"是一个正态表达式pattern,表示一个规则,一般会在注册的时候检测输入内容格式是否正确
--要看更多关于正态表达式pattern的内容,可以查看菜鸟教程https://www.runoob.com/lua/lua-strings.html的"匹配模式"