--Lua笔记-string
--转载请注明出处: yuliying的CSDN博客.

--第一部分: lua的string库函数

--1.string.byte
	--string.byte (s [, i [, j]])
	--取出字符串中的字节.i是起始位置,j是结束位置.
	--解析协议的时候经常用来将字符串中的某几个字节取出,然后重新组装为一个多字节的数字.
	print("------string.byte------")
	print( string.byte("hello world" , 1 , 3) )  --104(h)  101(e)  108(l)

--2.string.char
	--string.char (···)
	--接受若干数字,组成一个字符串,字符串的长度为参数个数.字符串内部的字节和数字对应.
	--解析协议的时候,经常用来将一个多字节的数字按字节存入字符串.
	print("------string.char------")
	print( string.char( 104 , 101 , 108) ) -- hel

--3.string.dump
	--string.dump (function)
	--将一个lua函数作为一个字符串返回.可以用load函数加载这个字符串,返回该函数的拷贝.
	print("------string.dump------")
	local function dump(str) print(str) end
	print( string.dump(dump) )

--4.string.find
	--string.find (s, pattern [, init [, plain]])
	--在字符串s中查找符合pattern的子串,如果找到了返回子串的开始位置和结束位置,否则返回nil
	--init参数为查找的起始位置,可以为负数.
	--plain参数为true的话会关闭模式匹配,只进行纯字符串匹配.
	--更多的模式匹配规则会在下面详细记录.
	print("------string.find------")
	print( string.find("hello world" , "llo") )
	print( string.find("hello world" , "llt?") )

--5.string.format
	--string.format (formatstring, ···)
	--类似c语言的sprintf函数.返回一个格式化的字符串.区别是string.format不支持 *, h, L, l, n, p 这些模式. 额外支持一个q模式.
	--q模式会转义字符串参数中的双引号.以便可以将字符串重新读回lua.
	--模式 A,a (when available), E, e, f, G, g 都对应一个数字参数.
	--模式 c, d, i, o, u, X, x 也对应一个数字参数, 但是数字所占字节数受限于底层c实现.
	--模式 o, u, X, x 对应的参数不能为负数.
	--模式 q 对应一个字符串.
	--模式 s 对应一个不含 \000 的字符串. 如果对应的不是一个字符串,则按照tostring来.
	print("------string.format------")
	print( string.format('%q', 'a string with "quotes" and \n new line') )

--6.string.gmatch
	--string.gmatch (s, pattern)
	--匹配字符串s中的pattern , 返回一个迭代器函数, 每次调用该迭代器函数,返回下一个子串.
	--pattern中捕获( 使用小括号() )了几个内容,则每次返回几个值. 如果没有捕获任何值,则返回整个子串.
	print("------string.gmatch------")
	s = "hello world from Lua"
	for w in string.gmatch(s, "%a+") do  --没有捕获,每次返回整个子串
    	print(w)
    end

    s = "from=world, to=Lua"
    for k, v in string.gmatch(s, "(%w+)=(%w+)") do  --捕获了key和value两个值
    	print( k , v )
    end

--7.string.gsub
	--string.gsub (s, pattern, repl [, n])
	--第一个返回值为字符串s的副本, 其中所有(或者前n个)符合模式pattern的子串都被替换为repl.
	--第二个返回值为替换的次数.
	--repl 可以为一个字符串,一个table 或者一个函数.
	--如果repl为一个字符串.则使用这个字符串来替换.repl中,字符%是一个转义字符.出现在repl中的( %d , 其中d的范围为1-9)对应符合pattern模式的字串中捕获的值.
		--%0代表整个字串. %%代表一个单独的%
	--如果repl为一个table. 则每次匹配到字串的时候都会查询这个table. 使用第一个捕获的值做为key.
	--如果repl为一个函数. 则每次匹配到字串的时候都会调用, 依次传入每个捕获的值.
	--如果repl所对应的table或者函数返回的值为一个字符串或者数字,则使用返回值来替换.
	--如果repl所对应的table或者函数返回的值为false或者nil,则不执行该字串的替换.
	print("------string.gsub------")
	print( string.gsub("hello world", "(%w+)", "%1 %1") )  -- hello hello world world 2
	print( string.gsub("hello world", "%w+", "%0 %0", 1) ) -- hello hello world 1
	print( string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") ) -- world hello Lua from 2
	print( string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) ) -- home = /home/roberto, user = roberto 2
	print( string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)return load(s)() end) ) -- 4+5 = 9 1
	print( string.gsub("$name-$version.tar.gz", "%$(%w+)", {name="lua", version="5.2"} )  ) -- lua-5.2.tar.gz 2

--8.string.len
	--string.len (s)
	--返回字符串的长度. \000 被算进长度 . 因此字符串  "a\000bc\000"  的长度为5
	print("------string.len------")
	print( string.len("") )
	print( string.len("a\000bc\000") )

--9.string.lower
	--string.lower (s)
	--将字符串中的大写字符转换为小写.
	print("------string.lower------")
	print(  string.lower("HeLlo WorLd") ) 

--10.string.match
	--string.match (s, pattern [, init])
	--匹配字符串s中的第一个符合pattern的子串 , 如果找到了 , 返回所有捕获的值。否则返回nil
	--如果没有捕获任何值,则返回整个字串.
	--init参数为匹配的起始位置,可以为负数.
	print("------string.match------")
	print( string.match( "love=you hate=me" , "(%w+)=(%w+)" ) )

--11.string.rep
	--string.rep (s, n [, sep])
	--将n个字符串s拼起来, 重复n次 , sep是他们之间的间隔.
	print("------string.rep------")
	print( string.rep("fish" , 3 , "-") )
--12.string.reverse
	--string.reverse (s)
	--翻转字符串
	print("------string.reverse------")
	print( string.reverse("hello") )
--13.string.sub
	--string.sub (s, i [, j])
	--截取子串.参数i为开始位置,j为结束位置.
	--i和j都可以为负数. 字符串的起始位置为1,字符串的末尾为-1.
	--如果经过转换后,i小于1,i被修正为1. (例如字符串长度为3,i为-4,则实际i到了字符串起始位置之前)
	--如果经过转换后,j大于字符串长度,j被修正为字符串长度.
	--如果经过转换后,i大于j.则返回一个空串.
	print("------string.sub------")
	print( string.sub("hello" , 1 , 3 ) )
	print( string.sub("hello" , -2 ) )
	print( string.sub("hello" , -100 , 100 ) )

--14.string.upper
	--string.lower (s)
	--将字符串中的小写字符转换为大写.
	print("------string.upper------")
	print( string.upper("HeLlo WorLd") )


--第二部分: lua中string的模式匹配


----------- 	  字符集合      ------------------------
--    X:  X为不包含在特殊字符中的字符,属于一个普通字符. 代表字符X本身
--    .:  代表所有字符
--    %a: 代表所有字母
--    %c: 代表所有控制字符
--    %d: 代表所有数字(0-9)
--    %g: 代表除了空格外的所有可打印字符
--    %l: 代表所有小写字母
--    %p: 代表所有标点字符
--    %s: 代表所有空白字符
--    %u: 代表所有大写字母
--    %w: 代表所有包含字母或者数子的字符
--    %x: 代表所有16进制数字(0-F)
--    %X: X为所有非字母和数字的字符,代表字符X本身.可以用来转义特殊字符.所有标点字符(即使不是特殊字符)之前都可以加一个%,代表这个标点本身.
--    [set]: 代表[]之间所有字符或者模式的集合. '-'可以用来表示前后两个字符之间的范围. 例如 [%w_] 代表所有数字,字母和下划线.
--    		[0-7] 代表数字0到7 . [0-7%l%-] 代表0到7的数字,所有小写字母,还有'-', 其中'-'为特殊字符,必须转义.
--    [^set]: 代表[set]的补集

-----------  	  模式         --------------------------

--      * : 匹配0个或多个字符集合中的字符. 匹配尽可能多的字符
--	    + : 匹配1个或多个字符集合中的字符. 匹配尽可能多的字符
--      - : 匹配0个或多个字符集合中的字符. 匹配尽可能少的字符
--      ? : 匹配0个或1个字符集合中的字符.
--	    %n: 1<=n<=9 , 对应匹配的字串中捕获的字符串.
--    %bxy: 其中x和y是两个指定的字符. 匹配一个以x开头,并以y结尾的字符串. x和y是成对匹配的.
-- %f[set]: 一种边界模式,匹配一个空字符,这个空字符的下一个字符属于集合set,它的前一个字符不属于集合set.
--      ^ : ^在一个pattern的开头匹配字符串的开始.在pattern的其他位置代表该字符本身.
--      $ : $在一个pattern的结尾匹配字符串的结尾.在pattern的其他位置代表该字符本身.


-----------       捕获         -----------------------------

-- 一个模式可以包含用括号包含起来的子模式,叫做捕获.
-- 当一个模式被匹配时,捕获的内容被储存起来,用作更多用途.
-- 捕获是按照先后来排序的. 例如在模式 "(a*(.)%w(%s*))" 中, "a*(.)%w(%s*)"是捕获的第一个子模式,"."是第二个,"%s*"是第三个.
-- 空捕获() , 捕获的是当前子串的开始位置和结束位置的下一个位置, 如果我们在字符串"flaaap"中使用"()aa()"模式来匹配, 那么捕获的值分别为3和5.

	print("------------pattern----------------")
	print( string.match("flaaap" , "()aa()")  )   --捕获匹配子串的位置.
	print( string.match("fflaaap" , "^f+")  )     --匹配开头的n个f.
	print( string.match("flaaappp" , "p+$")  )    --匹配结尾的n个p
	print( string.match("xw_2" , "^[%l%d_]+$" ) ) --匹配整个字符串,这个字符串只包含小写字母,数字,下划线
	print( string.match("ynEF8" , "%x+" ) )       --相当于pattern "[a-fA-F0-9]+"

	--  + 和 - 的区别
	print( string.match("hello" , "hel+o" ) )  --都匹配两个l
	print( string.match("hello" , "hel-o" ) )  --都匹配两个l
	print( string.match("hello" , "hel+" ) )   --匹配两个l
	print( string.match("hello" , "hel-" ) )   --匹配0个l
	--在后面的模式可以匹配更多的时候, - 选择匹配更少
	print( string.match("he3_llo" , "^(%l+)([3_]-)([%l_]+)$" ) )  -- he      3       _llo
	print( string.match("he3_llo" , "^(%l+)([3_]+)([%l_]+)$" ) )  -- he      3_      llo