Lua使用完整示例

文章目录

    • Lua 作为数据描述语言使用
    • 马尔可夫链算法

我们看两个完整的例子来阐明 Lua 语言的使用。
第一个例子来自于 Lua 网站,他展示了 Lua 作为数据描述语言的使用。
第二个例子讲解了马尔可夫链算法的实现,这个算法在 Kernighan & Pike 著作的 Practice of Programming 书中也有描述。这两个完整的例子之后,Lua 语言方面的介绍便到此结束。后面将继续介绍 table 和面向对象的内容以及标准库、C-API 等。

Lua 作为数据描述语言使用

Lua 网站保留一个包含世界各地使用 Lua 创建的工程的例子的数据库。在数据库中我们用一个构造器以自动归档的方式表示每一个工程入口点,代码如下:

entry{ 
title = "Tecgraf", 
org = "Computer Graphics Technology Group, PUC-Rio", 
url = "http://www.tecgraf.puc-rio.br/", 
contact = "Waldemar Celes", 
description = [[ 
TeCGraf is the result of a partnership between PUC-Rio, 
the Pontifical Catholic University of Rio de Janeiro, 
and <A HREF="http://www.petrobras.com.br/">PETROBRAS</A>, 
the Brazilian Oil Company. TeCGraf is Lua's birthplace, 
and the language has been used there since 1993. 
Currently, more than thirty programmers in TeCGraf use Lua regularly; 
they have written more than two hundred thousand lines of code,
 distributed among dozens of final products.]] 
} 

有趣的是,工程入口的列表是存放在一个 Lua 文件中的,每个工程入口以 table 的形式作为参数去调用 entry 函数。我们的目的是写一个程序将这些数据以 html 格式展示出来。由于工程太多,我们首先列出工程的标题,然后显示每个工程的明细。结果如下:

<HTML> 
<HEAD><TITLE>Projects using Lua</TITLE></HEAD> 
<BODY BGCOLOR="#FFFFFF"> 
Here are brief descriptions of some projects around the world that use <A HREF="home.html">Lua</A>. 
<UL> 
<LI><A HREF="#1">TeCGraf</A> 
<LI> ... 
</UL> 
<H3> 
<A NAME="1" 
 HREF="http://www.tecgraf.puc-rio.br/">TeCGraf</A> 
<SMALL><EM>Computer Graphics Technology Group, 
PUC-Rio</EM></SMALL> 
</H3> 
TeCGraf is the result of a partnership between 
... 
distributed among dozens of final products.<P> 
Contact: Waldemar Celes 
<A NAME="2"></A><HR> 
... 
</BODY></HTML> 

为了读取数据,我们需要做的是正确的定义函数 entry,然后使用 dofile 直接运行数据文件即可(db.lua)。注意,我们需要遍历入口列表两次,第一次为了获取标题,第二次为了获取每个工程的表述。一种方法是:使用相同的 entry 函数运行数据文件一次将所有的入口放在一个数组内;另一种方法:使用不同的 entry 函数运行数据文件两次。因为 Lua 编译文件是很快的,这里我们选用第二种方法。

首先,我们定义一个辅助函数用来格式化文本的输出(参见 5.2 函数部分内容)

function fwrite (fmt, ...) 
return io.write(string.format(fmt, unpack(arg))) 
end 

第二,我们定义一个 BEGIN 函数用来写 html 页面的头部

function BEGIN() 
io.write([[ 
<HTML> 
<HEAD><TITLE>Projects using Lua</TITLE></HEAD> 
<BODY BGCOLOR="#FFFFFF"> 
Here are brief descriptions of some projects around the 
world that use <A HREF="home.html">Lua</A>. 
]]) 
end 

第三,定义 entry 函数
a. 第一个entry函数,将每个工程一列表方式写出,entry的参数o是描述工程的table。

function entry0 (o) 
 N=N + 1 
local title = o.title or '(no title)'
 fwrite('
  • %s\n', N, title) end
  • 如果 o.title 为 nil 表明 table 中的域 title 没有提供,我们用固定的"no title"替换。
    b. 第二个 entry 函数,写出工程所有的相关信息,稍微有些复杂,因为所有项都是可选的。

    function entry1 (o) 
     N=N + 1 
    local title = o.title or o.org or 'org'
     fwrite('
    \n

    \n') local href = '' if o.url then href = string.format(' HREF="%s"', o.url) end fwrite('%s\n', N, href, title) if o.title and o.org then fwrite('\n%s', o.org) end fwrite('\n

    \n'
    ) if o.description then fwrite('%s', string.gsub(o.description, '\n\n\n*', '

    \n')) fwrite('

    \n') end if o.email then fwrite('Contact: %s\n', o.email, o.contact or o.email) elseif o.contact then fwrite('Contact: %s\n', o.contact) end end

    由于 html 中使用双引号,为了避免冲突我们这里使用单引号表示串。
    第四,定义 END 函数,写 html 的尾部

    function END() 
    fwrite('\n') 
    end 
    

    在主程序中,我们首先使用第一个 entry 运行数据文件输出工程名称的列表,然后再以第二个 entry 运行数据文件输出工程相关信息。

    BEGIN() 
    N = 0 
    entry = entry0 
    fwrite('
      \n') dofile('db.lua') fwrite('
    \n'
    ) N = 0 entry = entry1 dofile('db.lua') END()

    马尔可夫链算法

    我们第二个例子是马尔可夫链算法的实现,我们的程序以前 n(n=2)个单词串为基础随机产生一个文本串。

    程序的第一部分读出原文,并且对没两个单词的前缀建立一个表,这个表给出了具有那些前缀的单词的一个顺序。建表完成后,这个程序利用这张表生成一个随机的文本。

    在此文本中,每个单词都跟随着它的的前两个单词,这两个单词在文本中有相同的概率。这样,我们就产生了一个非常随机,但并不完全随机的文本。例如,当应用这个程序的输出结果会出现“构造器也可以通过表构造器,那么一下几行的插入语对于整个文件来说,不是来存储每个功能的内容,而是来展示它的结构。”如果你想在队列里找到最大元素并返回最大值,接着显示提示和运行代码。下面的单词是保留单词,不能用在度和弧度之间转换。

    我们编写一个函数用来将两个单词中间加上空个连接起来:

    function prefix (w1, w2) 
    return w1 .. ' ' .. w2 
    end 
    

    我们用 NOWORD(即\n)表示文件的结尾并且初始化前缀单词,例如,下面的文本:the more we try the more we do
    初始化构造的表为:

    { 
     ["\n \n"] = {"the"}, 
     ["\n the"] = {"more"}, 
     ["the more"] = {"we", "we"}, 
     ["more we"] = {"try", "do"}, 
     ["we try"] = {"the"}, 
     ["try the"] = {"more"}, 
     ["we do"] = {"\n"}, 
    } 
    

    我们使用全局变量 statetab 来保存这个表,下面我们完成一个插入函数用来在这个statetab 中插入新的单词。

    function insert (index, value) 
    if not statetab[index] then
     statetab[index] = {value} 
    else 
     table.insert(statetab[index], value) 
    end 
    end 
    

    这个函数中首先检查指定的前缀是否存在,如果不存在则创建一个新的并赋上新值。

    如果已经存在则调用 table.insert 将新值插入到列表尾部。
    我们使用两个变量 w1 和 w2 来保存最后读入的两个单词的值,对于每一个前缀,我们保存紧跟其后的单词的列表。例如上面例子中初始化构造的表。

    初始化表之后,下面来看看如何生成一个 MAXGEN(=1000)个单词的文本。首先,重新初始化 w1 和 w2,然后对于每一个前缀,在其 next 单词的列表中随机选择一个,打印此单词并更新 w1 和 w2,完整的代码如下:

    -- Markov Chain Program in Lua 
    function allwords () 
    local line = io.read() -- current line 
    local pos = 1 -- current position in the line 
    return function () -- iterator function 
     while line do -- repeat while there are lines 
     local s, e = string.find(line, "%w+", pos) 
     if s then -- found a word? 
     pos = e + 1 -- update next position 
     return string.sub(line, s, e) -- return the word 
     else 
     line = io.read() -- word not found; try next line 
     pos = 1 -- restart from first position 
     end 
     end 
     return nil -- no more lines: end of traversal 
    end 
    end 
    function prefix (w1, w2) 
    return w1 .. ' ' .. w2 
    end 
    local statetab 
    function insert (index, value) 
    if not statetab[index] then
     statetab[index] = {n=0} 
    end 
     table.insert(statetab[index], value) 
    end 
    local N = 2 
    local MAXGEN = 10000 
    local NOWORD = "\n"
    -- build table 
    statetab = {} 
    local w1, w2 = NOWORD, NOWORD 
    for w in allwords() do
     insert(prefix(w1, w2), w) 
     w1 = w2; w2 = w; 
    end 
    insert(prefix(w1, w2), NOWORD) 
    -- generate text 
    w1 = NOWORD; w2 = NOWORD -- reinitialize 
    for i=1,MAXGEN do
    local list = statetab[prefix(w1, w2)] 
    -- choose a random item from list 
    local r = math.random(table.getn(list)) 
    local nextword = list[r] 
    if nextword == NOWORD then return end
     io.write(nextword, " ") 
     w1 = w2; w2 = nextword 
    end
    

    你可能感兴趣的:(lua技术)