Programming in Lua, 2Nd Edition - Chapter 10: Complete Examples

 

 

Chapter 10: Complete Examples

 

最后,我们以两个展示Lua 的不同特性的完整示例程序来结束关于语言的介绍。第一个示例展示了Lua 作为一种数据描述语言来使用。第二个例子是一个马尔可夫链的实现,由Kernighan & Pike 的《Practice of Programming (Addison-Wesley, 1999) 一书描述。

 

 

10.1 Data Description

 

生成HTML

 

--[=[

db.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.]]

}

--]=]

 

function fwrite (fmt, ...)

       return io.write(string.format(fmt, ...))

end

 

function writeheader()

       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>.

<br>

       ]])

end

 

function entry1 (o)

       count = count + 1

       local title = o.title or '(no title)'

       fwrite('<li><a href="#%d">%s</a>/n', count, title)

end

 

function writetail ()

       fwrite('</body></html>/n')

end

 

 

function entry2 (o)

       count = count + 1

       fwrite('<hr>/n<h3>/n')

       local href = o.url and string.format(' href="%s"', o.url) or ''

       local title = o.title or o.org or 'org'

       fwrite('<a name="%d"%s>%s</a>/n', count, href, title)

       if o.title and o.org then

              fwrite('<br>/n<small><em>%s</em></small>', o.org)

       end

       fwrite('/n</h3>/n')

       if o.description then

              fwrite('%s<p>/n',

              string.gsub(o.description, '/n/n+', '<p>/n'))

       end

       if o.email then

              fwrite('Contact: <a href="mailto:%s">%s</a>/n',

              o.email, o.contact or o.email)

       elseif o.contact then

              fwrite('Contact: %s/n', o.contact)

       end

end

 

 

local inputfile = 'db.lua'

writeheader()

count = 0

f = loadfile(inputfile) -- loads data file

entry = entry1 -- defines 'entry'

fwrite('<ul>/n')

f() -- runs data file

fwrite('</ul>/n')

count = 0

entry = entry2 -- redefines 'entry'

f() -- runs data file again

writetail()

 

 

10.2 Markov Chain Algorithm

 

我们的第二个例子是马尔可夫链算法的实现。程序生成随机文本,规则是基于原文中什么单词跟在n 个连续的单词后面。这个例子我们假定n 的值是2

 

程序的第一部分读取原文,然后基于这个文本创建一个表,对每个两单词前缀,给定一个单词的列表,它们是跟在前缀后面的单词。建完表后,程序使用这个表来生成随机文本,每个单词跟在两个前缀单词后面,并且它们在文本中等概率出现。结果是,我们得到非常,但不完全随机的文本。

 

我们将前缀编码为两个单词中间连接一个空格:

 

function prefix (w1, w2)

         return w1 .. " " .. w2

end

 


 

我们使用NOWORD (“/n”) 作为初始前缀,并且也用它来标记文本的结束(生成的文本最后一个单词是“/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"},

}

 

因为原文中的"the" 没有前缀,所以用"/n /n" 作为初始前缀。这一项后面["try the"] = {"more"}

为什么不是["the more "] = {"we"} ?因为前缀"the more " 前面已经出现过了。同理,"more we" 也出现过了,所以下一项直接是"we do",后面已经没有文本,所以后面接"/n" 作为结束。

 

程序用变量statetab 来保存前缀表。在前缀表中插入新单词,我们使用下面的函数:

 

function insert (index, value)

       local list = statetab[index]

       if list == nil then

              statetab[index] = {value}

       else

              list[#list + 1] = value

       end

end

 

 

马尔可夫链算法

 

function allwords (f)

       local line = f:read("*line")    -- current line

       local pos = 1                           -- current position in the line

       return function ()

                            while line do

                                   local s, e = string.find(line, "%w+", pos)

                                   if s then -- found a word?

                                          pos = e + 1

                                          return string.sub(line, s, e)

                                   else

                                          line = f:read("*line")

                                          pos = 1

                                   end

                            end

                            return nil

                end

end

 

 

 

function prefix (w1, w2)

       return w1 .. " " .. w2

end

 

local statetab = {}

 

function insert (index, value)

       local list = statetab[index]

       if list == nil then

              statetab[index] = {value}

       else

              list[#list + 1] = value

       end

end

 

f = io.open("c://input.txt","r") -- open input file

assert(f)

 

local N = 2

local MAXGEN = 10000

local NOWORD = "/n"

 

-- build table

local w1, w2 = NOWORD, NOWORD

for w in allwords(f) 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(#list)   -- Bug,这里的随机数是不随机的。

       local nextword = list[r]

 

       if nextword == NOWORD then return end

       io.write(nextword, " ")

       w1 = w2; w2 = nextword

end

 

f:close()

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值