快速掌握Lua 5.3 —— 字符串库 (3)
来源:互联网 发布:淘宝试用报告哪里看 编辑:程序博客网 时间:2024/06/07 14:17
Q:什么情况下”pattern”会匹配空串?
A:要小心的使用*
和-
,因为它们可以匹配零次。
-- 如果你打算用"%a*"匹配单词,你会发现到处都是单词。print(string.find(";$% **#$hello13", "%a*")) --> 1 0print(string.find(";$% **#$hello13", "%a*", 6)) --> 6 5-- 使用"%a+"才能正常的完成工作。print(string.find(";$% **#$hello13", "%a+")) --> 10 14
Q:如何使用Lua生成”pattern”?
A:使用Lua可以帮我们生成一些繁琐的”pattern”,
--[[ 查找一个文本中行字符大于70个的行,也就是匹配一个非换行符之前有70个字符的行。 重复匹配单个字符70次,后面跟着一个匹配单个字符0次或多次。]]pattern = string.rep("[^\n]", 70) .. "[^\n]*"-- 对于单词进行大小写无关的查找。function nocase (s) -- 每找到一个子母,就将其转换为"[xX]"的形式。 s = string.gsub(s, "%a", function (c) return string.format("[%s%s]", string.lower(c), string.upper(c)) end) return sendpattern = nocase("Hi there!")print(pattern) --> [hH][iI] [tT][hH][eE][rR][eE]!
Q:如何对目标串进行预处理?
A:预处理的意义在于排除特殊字符对匹配的影响。
第一个例子,将字符串中双引号内的字符串转换为大写,双引号之间可以包含转义的双引号\"
,
-- 将转义的双引号转换为"\ddd"的形式,其中"ddd"是双引号ASCII码的十进制表示。function code (s) return (string.gsub(s, "\\(.)", function (x) return string.format("\\%03d", string.byte(x)) end))end-- 将"\ddd"恢复为转义的双引号。function decode (s) return (string.gsub(s, "\\(%d%d%d)", function (d) return "\\" .. string.char(d) end))ends = [[follows a typical string: "This is \"great\"!".]]--[[ 省去这步预处理,"great"将不会被转换为大写。 因为"This is \"是第一次匹配,"!"是第二次匹配。]]s = code(s)-- 使用"string.upper()"转换为大写。s = string.gsub(s, '(".-")', string.upper)s = decode(s) -- 将预处理的部分复原。print(s) --> follows a typical string: "THIS IS \"GREAT\"!".
第二个例子,我们来扩展“快速掌握Lua 5.3 —— 字符串库 (2)”中提到的”LaTeX”格式转为”XML”格式的例子。这一次的”LaTeX”格式中可以包含转义字符\
,也就是说可以使用\\
、 \{
和\}
,分别表示 \
、{
和}
,
--[[ 为了避免"\emph"和"\command"与"\{a\\b\}"混淆在一起, 我们首先应该将"\{"、"\\"和"\}"转换为特殊的编码, 然而与此同时不能将"\emph"和"\command"转换, 所以仅当"\"后面不是子母的时候才进行转换。 与上一个例子相同,转换为他们的"\ddd"的十进制形式。]]function code (s) return (string.gsub(s, '\\(%A)', function (x) return string.format("\\%03d", string.byte(x)) end))end-- 与上个例子相比,解码的时候不需要"\"了,所以可以直接调用"string.char()"。function decode (s) return (string.gsub(s, '\\(%d%d%d)', string.char))ends = [[a \emph{command} is written as \command{text\{a\\b\}}.]]s = code(s)s = string.gsub(s, "\\(%a+){(.-)}", "<%1>%2</%1>")print(decode(s))--> a <emph>command</emph> is written as <command>text{a\b}</command>.
第三个例子是个稍微复杂的例子,我们来编解码”CSV”文件。
1、”CSV”文件的每一行表示一条记录,每一条记录由多个域组成,每一个域之间使用,
分隔。
2、每一个域中的任何空格字符都是有效字符,不能被忽略。
3、如果域中包含,
,那么整个域需要用""
引起来,如果此时域中还包含"
,那么每一个"
使用""
代替。
4、不包含,
的域也可以选择性的使用""
引起来。但只要是使用""
引起来的域,如果其中包含"
,那么每一个"
都必须使用""
代替。
根据以上规则,如若有表 t = {'a b', 'a,b', '', ' a,"b"c', 'hello "world"!'}
其中的元素转换为”CSV”文件格式应为, a b,"a,b"," a,""b""c",,hello "world"!
print("Encode: ")function escapeCSV (s) if string.find(s, ',') then -- 如果域中有逗号,则整个域需要用双引号引起来。 -- 如果此时域中还有双引号,则每个双引号都应使用两个连续的双引号代替。 s = '"' .. string.gsub(s, '"', '""') .. '"' end return sendfunction toCSV (t) local s = "" for _,p in pairs(t) do s = s .. "," .. escapeCSV(p) -- 每个域使用","分隔。 end return string.sub(s, 2) -- remove first commaendt = {'a b', 'a,b', ' a,"b"c', '', 'hello "world"!'}s = toCSV(t)print(s) --> a b,"a,b"," a,""b""c",,hello "world"!print()print("Decode: ")function fromCSV (s) s = s .. ',' -- 在字符串末尾添加",",为了方便查找最后一个域。 local t = {} -- table to collect fields local fieldstart = 1 -- 域在字符串中的起始索引。 -- 循环的找出一条记录中的每一个域。 repeat -- 如果域的起始位置是一个双引号,那么说明整个域被双引号引了起来。 if string.find(s, '^"', fieldstart) then local a, c local i = fieldstart repeat --[[ 查找域尾的双引号。 因为如果被双引号引起来的域中含有双引号字符的话, 每个双引号都会使用连续的两个双引号代替。 那么当找到连续的两个双引号时,"c"得到的是后面的那个双引号, "i"得到的是该双引号的索引位置,所以从"i+1"处继续寻找, 即跳过了这两个连续的双引号继续寻找。 而当找到一个双引号跟着一个非双引号字符时,此时找到了域尾的双引号。 "c"得到的是个空字符串,"i"得到了双引号的索引位置。此时,完成查找。]] a, i, c = string.find(s, '"("?)', i+1) until c ~= '"' -- quote not followed by quote? if not i then error('unmatched "') end -- 取出该域,舍弃域首尾的双引号。 local f = string.sub(s, fieldstart+1, i-1) --[[ 因为已经舍弃了域首尾的双引号, 所以域中所有连续的两个双引号恢复为单个双引号。 将域的内容存入"table"中。]] table.insert(t, (string.gsub(f, '""', '"'))) --[[ "i"是域尾双引号的索引位置,从此处寻找与下一个域之间的逗号, 并更新下一个域的起始索引位置。 因为在函数开始时,将最后一个域的末尾也加上了逗号, 所以按照规范的写法,域尾双引号之后的字符就应该是逗号, 所以此处实际可以写成"fieldstart = i + 2", 而以下这种写法是为了防止不规范的写法, 即域尾双引号与域间逗号之间有空格字符。]] fieldstart = string.find(s, ',', i) + 1 else -- 如果域的起始位置不是一个双引号,那么说明整个域未被双引号引起来。 -- 直接寻找下一个域间的逗号。 local nexti = string.find(s, ',', fieldstart) -- 将域的内容存入"table"中。 table.insert(t, string.sub(s, fieldstart, nexti-1)) fieldstart = nexti + 1 -- 更新下一个域的起始索引位置。 end until fieldstart > string.len(s) return tendt = fromCSV(s)for i, s in ipairs(t) do print(i, s) end--[[ result: 1 a b 2 a,b 3 a,"b"c 4 5 hello "world"!]]print()--[[ 测试两个连续的双引号的不同作用。 每个域的内容依次为: 1、hello,空格,双引号,空格,hello。 2、空格,双引号,双引号。 3、无。]]t = fromCSV('"hello "" hello", "",""')for i, s in ipairs(t) do print(i, s) end--[[ result: 1 hello " hello 2 "" 3 ]]
0 0
- 快速掌握Lua 5.3 —— 字符串库 (3)
- 快速掌握Lua 5.3 —— 字符串库 (1)
- 快速掌握Lua 5.3 —— 字符串库 (2)
- 快速掌握Lua 5.3 —— 函数
- 快速掌握Lua 5.3 —— Coroutines
- 快速掌握Lua 5.3 —— 数据结构
- 快速掌握Lua 5.3 —— 环境
- 快速掌握Lua 5.3 —— packages
- 快速掌握Lua 5.3 —— 资源管理
- 快速掌握Lua 5.3 —— "table"库
- 快速掌握Lua 5.3 —— I/O库 (1)
- 快速掌握Lua 5.3 —— I/O库 (2)
- 快速掌握Lua 5.3 —— 操作系统库
- 快速掌握Lua 5.3 —— 调试库 (1)
- 快速掌握Lua 5.3 —— 调试库 (2)
- 快速掌握Lua 5.3 —— 让我们开始吧
- 快速掌握Lua 5.3 —— 各种变量和值
- 快速掌握Lua 5.3 —— "Iterators"和"Generic for"
- ZOJ1076
- 《匠人精神》读书笔记要点记录及自我剖析
- static关键字
- 数论_1
- 尝试向分析类转型2--工具使用
- 快速掌握Lua 5.3 —— 字符串库 (3)
- xml之CDATA
- STM32中GPIO的8种工作模式详解
- dfs
- java 注解的基本原理和编程实现
- Hive 初识
- Ubunut No apport report written because the error message indicates its a followup error from a prev
- ubuntu14.04 安装搜狗输入法
- Iteratee概念