GOOGLE搜索结果页面的抓取

Filed under: 程序开发 | No Comments »
Posted on

1.获取某关键词的结果页面的HTML代码
2.清除代码中的回车及换行(这个步骤很重要,否则无法采用第三步来获取正确的结果,我就是在这里被卡了很久)
3.正则表达式获取每个URL标题及摘要区域的HTML代码
4.正则表达式分别获取URL,标题及摘要

相关文章

要找一个和主业无关的业余爱好

Filed under: 生活感悟 | No Comments »
Posted on

前几日看报,在一块豆腐大的地方,标题我忘记了,内容我也忘记的差不多了,仿佛是列举了很多选择和主业无关的业余爱好的好处以及一些名人事例.惟独记得其中的一句话:"要找一个和主业无关的业余爱好,相差的越远越好,尽量去成为业余中的专家".
Read the rest of this entry »

相关文章

《Programming in Lua中文版》6.More about Functions

Filed under: 程序开发 | No Comments »
Posted on

Lua中的函数是带有词法定界(lexical scoping)的第一类值(first-class values).
第一类值指:在Lua中函数和其他值(数值,字符串)一样,函数可以被存放在变量中,也可以存放在表中,可以作为函数的参数,还可以作为函数的返回值.
词法定界指:被嵌套的函数可以访问他外部函数中的变量.这一特性给Lua提供了强大的编程能力.
Lua中关于函数稍微难以理解的是函数也可以没有名字,匿名的.当我们提到函数名(比如print),实际上是说一个指向函数的变量,像持有其他类型值的变量一样
a = {p = print}
a.p(”Hello World”) –> Hello World
print = math.sin — `print’ now refers to the sine function
a.p(print(1)) –> 0.841470
sin = a.p — `sin’ now refers to the print function
sin(10, 20) –> 10 20
既然函数是值,那么表达式也可以创建函数了,Lua中我们经常这样写:
function foo (x) return 2*x end
这实际上是利用Lua提供的”语法上的甜头”(syntactic sugar)的结果,下面是原本的函数:
foo = function (x) return 2*x end
函数定义实际上是一个赋值语句,将类型为function的变量赋给一个变量.我们使用function (x) … end 来定义一个函数和使用{}创建一个表一样.
table标准库提供一个排序函数,接受一个表作为输入参数并且排序表中的元素.这个函数必须能够对不同类型的值(字符串或者数值)按升序或者降序进行排序.Lua不是尽可能多地提供参数来满足这些情况的需要,而是接受一个排序函数作为参数(类似C++的函数对象),排序函数接受两个排序元素作为输入参数,并且返回两者的大小关系,例如:
network = {
{name = “grauna”, IP = “210.26.30.34″},
{name = “arraial”, IP = “210.26.30.23″},
{name = “”, IP = “210.26.23.12″},
{name = “derain”, IP = “210.26.23.20″},
}
如果我们想通过表的name域排序:
table.sort(network, function (a,b)
return (a.name > b.name)
end)
以其他函数作为参数的函数在Lua中被称作高级函数,高级函数在Lua中并没有特权,只是Lua把函数当作第一类函数处理的一个简单的结果.
下面给出一个绘图函数的例子:
function eraseTerminal ()
io.write(”\27[2J")
end

-- writes an `*' at column `x' , row `y'
function mark (x,y)
io.write(string.format("\27[%d;%dH*", y, x))
end

-- Terminal size
TermSize = {w = 80, h = 24}

-- plot a function
-- (assume that domain and image are in the range [-1,1])
function plot (f)
eraseTerminal()
for i=1,TermSize.w do
local x = (i/TermSize.w)*2 - 1
local y = (f(x) + 1)/2 * TermSize.h
mark(i, y)
end
io.read() — wait before spoiling the screen
end
要想让这个例子正确的运行,你必须调整你的终端类型和代码中的控制符一致
plot(function (x) return math.sin(x*2*math.pi) end)
将在屏幕上输出一个正弦曲线.
将第一类值函数应用在表中是Lua实现面向对象和包机制的关键,这部分内容在后面章节介绍
6.1 闭包
当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界.虽然这看起来很清楚,事实并非如此,词法定界加上第一类函数在编程语言里是一个功能强大的概念,很少语言提供这种支持.
下面看一个简单的例子,假定有一个学生姓名的列表和一个学生名和成绩对应的表;现在想根据学生的成绩从高到低对学生进行排序,可以这样做:
names = {”Peter”, “Paul”, “Mary”}
grades = {Mary = 10, Paul = 7, Peter = 8}
table.sort(names, function (n1, n2)
return grades[n1] > grades[n2] — compare the grades
end)
假定创建一个函数实现此功能:
function sortbygrade (names, grades)
table.sort(names, function (n1, n2)
return grades[n1] > grades[n2] — compare the grades
end)
end
例子中包含在sortbygrade函数内部的sort中的匿名函数可以访问sortbygrade的参数grades,在匿名函数内部grades不是全局变量也不是局部变量,我们称作外部的局部变量(external local variable)或者upvalue.(upvalue意思有些误导,然而在Lua中他的存在有历史的根源,还有他比起external local variable简短).
看下面的代码 :
function newCounter ()
local i = 0
return function () — anonymous function
i = i + 1
return i
end
end

c1 = newCounter()
print(c1()) –> 1
print(c1()) –> 2
匿名函数使用upvalue i保存他的计数,当我们调用匿名函数的时候i已经超出了作用范围,因为创建i的函数newCounter已经返回了.然而Lua用闭包的思想正确处理了这种情况.简单的说闭包是一个函数加上它可以正确访问的upvalues.如果我们再次调用newCounter,将创建一个新的局部变量i,因此我们得到了一个作用在新的变量i上的新闭包.
c2 = newCounter()
print(c2()) –> 1
print(c1()) –> 3
print(c2()) –> 2
c1,c2是建立在同一个函数上,但作用在同一个局部变量的不同实例上的两个不同的闭包.
技术上来讲,闭包指值而不是指函数,函数仅仅是闭包的一个原型声明;尽管如此,在不会导致混淆的情况下我们继续使用术语函数代指闭包.
闭包在上下文环境中提供很有用的功能,如前面我们见到的可以作为高级函数(sort)的参数;作为函数嵌套的函数(newCounter).这一机制使得我们可以在Lua的函数世界里组合出奇幻的编程技术.闭包也可用在回调函数中,比如在GUI环境中你需要创建一系列button,但用户按下button时回调函数被调用,可能不同的按钮被按下时需要处理的任务有点区别.具体来讲,一个十进制计算器需要10个相似的按钮,每个按钮对应一个数字,可以使用下面的函数创建他们:
function digitButton (digit)
return Button{ label = digit,
action = function ()
add_to_display(digit)
end
}
end
这个例子中我们假定Button是一个用来创建新按钮的工具,label是按钮的标签,action是按钮被按下时调用的回调函数.(实际上是一个闭包,因为他访问upvalue digit).digitButton完成任务返回后,局部变量digit超出范围,回调函数仍然可以被调用并且可以访问局部变量digit.
闭包在完全不同的上下文中也是很有用途的.因为函数被存储在普通的变量内我们可以很方便的重定义或者预定义函数.通常当你需要原始函数有一个新的实现时可以重定义函数.例如你可以重定义sin使其接受一个度数而不是弧度作为参数:
oldSin = math.sin
math.sin = function (x)
return oldSin(x*math.pi/180)
end
更清楚的方式:
do
local oldSin = math.sin
local k = math.pi/180
math.sin = function (x)
return oldSin(x*k)
end
end
这样我们把原始版本放在一个局部变量内,访问sin的唯一方式是通过新版本的函数.
利用同样的特征我们可以创建一个安全的环境(也称作沙箱,和java里的沙箱一样),当我们运行一段不信任的代码(比如我们运行网络服务器上获取的代码)时安全的环境是需要的,比如我们可以使用闭包重定义io库的open函数来限制程序打开的文件.
do
local oldOpen = io.open
io.open = function (filename, mode)
if access_OK(filename, mode) then
return oldOpen(filename, mode)
else
return nil, “access denied”
end
end
end
6.2 非全局函数
Lua中函数可以作为全局变量也可以作为局部变量,我们已经看到一些例子:函数作为table的域(大部分Lua标准库使用这种机制来实现的比如io.read;math.sin).这种情况下,必须注意函数和表语法:
1.表和函数放在一起
Lib = {}
Lib.foo = function (x,y) return x + y end
Lib.goo = function (x,y) return x - y end
2.使用表构造函数
Lib = {
foo = function (x,y) return x + y end,
goo = function (x,y) return x - y end
}
3.Lua提供另一种语法方式
Lib = {}
function Lib.foo (x,y)
return x + y
end
function Lib.goo (x,y)
return x - y
end
当我们将函数保存在一个局部变量内时,我们得到一个局部函数,也就是说局部函数像局部变量一样在一定范围内有效.这种定义在包中是非常有用的:因为Lua把chunk当作函数处理,在chunk内可以声明局部函数(仅仅在chunk内可见),词法定界保证了包内的其他函数可以调用此函数.下面是声明局部函数的两种方式:
1.方式一
local f = function (…)

end

local g = function (…)

f() — external local `f’ is visible here

end
2.方式二
local function f (…)

end
有一点需要注意的是在声明递归局部函数的方式:
local fact = function (n)
if n == 0 then return 1
else return n*fact(n-1) — buggy
end
end
上面这种方式导致Lua编译时遇到fact(n-1)并不知道他是局部函数fact,Lua会去查找是否有这样的全局函数fact.为了解决这个问题我们必须在定义函数以前先声明:
local fact
fact = function (n)
if n == 0 then return 1
else return n*fact(n-1)
end
end
这样在fact内部fact(n-1)调用是一个局部函数调用,运行时fact就可以获取正确的值了.
但是Lua扩展了他的语法使得可以在直接递归函数定义时使用两种方式都可以.
在定义非直接递归局部函数时要先声明然后定义才可以:
local f, g — `forward’ declarations

function g ()
… f() …
end

function f ()
… g() …
end
6.3 正确的尾调用(Proper Tail Calls)
Lua中函数的另一个有趣的特征是可以正确的处理尾调用.(一些作者使用术语尾递归[原文:proper tail recursion],虽然并未涉及到递归的概念) .
尾调用是一种类似在函数结尾的goto调用,当函数最后一个动作是调用另外一个函数时,我们称这种调用尾调用.例如:
function f (x)
return g(x)
end
g的调用是尾调用.
例子中f调用g后不会再做任何事情,这种情况下当被调用函数g结束时程序不需要返回到调用者f;所以尾调用之后程序不需要在栈中保留关于调用者的任何信息.一些编译器比如Lua解释器利用这种特性在处理尾调用时不使用额外的栈,我们称这种语言支持正确的尾调用.
由于尾调用不需要使用栈空间,那么尾调用递归的层次可以无限制的.例如下面调用不论n为何值不会导致栈溢出.
function foo (n)
if n > 0 then return foo(n - 1) end
end
需要注意的是:必须明确什么是尾调用.
一些调用者函数调用其他函数后也没有做其他的事情但不属于尾调用.比如:
function f (x)
g(x)
return
end
上面这个例子中f在调用g后,不得不丢弃g地返回值,所以不是尾调用,同样的下面几个例子也不时尾调用:
return g(x) + 1 — must do the addition
return x or g(x) — must adjust to 1 result
return (g(x)) — must adjust to 1 result
Lua中类似return g(…) 这种格式的调用是尾调用.但是g和g的参数都可以是复杂表达式,因为Lua会在调用之前计算表达式的值.例如下面的调用是尾调用:
return x[i].foo(x[j] + a*b, i + j)
可以将尾调用理解成一种goto, 在状态机的编程领域尾调用是非常有用的.状态机的应用要求函数记住每一个状态,改变状态只需要goto(or call)一个特定的函数.我们考虑一个迷宫游戏作为例子:迷宫有很多个房间,每个房间有东西南北四个门,每一步输入一个移动的方向,如果该方向存在即到达该方向对应的房间,否则程序打印警告信息.目标是:从开始的房间到达目的房间.
这个迷宫游戏是典型的状态机,每个当前的房间是一个状态.我们可以对每个房间写一个函数实现这个迷宫游戏,我们使用尾调用从一个房间移动到另外一个房间.一个四个房间的迷宫代码如下:
function room1 ()
local move = io.read()
if move == “south” then return room3()
elseif move == “east” then return room2()
else print(”invalid move”)
return room1() — stay in the same room
end
end

function room2 ()
local move = io.read()
if move == “south” then return room4()
elseif move == “west” then return room1()
else print(”invalid move”)
return room2()
end
end

function room3 ()
local move = io.read()
if move == “north” then return room1()
elseif move == “east” then return room4()
else print(”invalid move”)
return room3()
end
end

function room4 ()
print(”congratilations!”)
end
我们可以调用room1()开始这个游戏.
如果没有正确的尾调用,每次移动都要创建一个栈,多次移动后可能导致栈溢出.但正确的尾调用可以无限制的尾调用,因为每次尾调用只是一个goto到另外一个函数并不是传统的函数调用.
—–

相关文章

Tags :

《Programming in Lua中文版》5.Functions

Filed under: 程序开发 | No Comments »
Posted on

函数有两种用途:1.完成指定的任务,这种情况下函数作为调用语句使用2.计算并返回值,这种情况下函数作为赋值语句的表达式使用.
语法:
function func_name (arguments-list)
statements-list;
end;
调用函数的时候,如果参数列表为空,必须使用()表明是函数调用.
print(8*9, 9/8)
a = math.sin(3) + math.cos(10)
print(os.date())
上述规则有一个例外,当函数只有一个参数并且这个参数是字符串或者表构造的时候,()是可选的:
print “Hello World” print(”Hello World”)
dofile ‘a.’ dofile (’a.’)
print [[a multi-line print([[a multi-line
message]] message]])
f{x=10, y=20} f({x=10, y=20})
type{} type({})
Lua也提供了面向对象方式调用函数的语法,比如o:foo(x)与o.foo(o, x)是等价的,后面的章节会详细介绍面向对象内容.
Lua使用的函数可以是Lua编写也可以是其他语言编写,对于Lua程序员来说用什么语言实现的函数使用起来都一样.
Lua函数实参和形参的匹配与赋值语句类似,多余部分被忽略,缺少部分用nil补足.
function f(a, b) return a or b end

CALL PARAMETERS

f(3) a=3, b=nil
f(3, 4) a=3, b=4
f(3, 4, 5) a=3, b=4 (5 is discarded)
5.1 返回多个结果值
Lua函数可以返回多个结果值,一些预定义的函数返回多值比如string.find,他返回匹配串的开始和结束下标(如果不存在匹配串返回nil).
s, e = string.find(”hello users”, “”)

print(s, e) –> 7 9
Lua函数中,在return后列出要返回的值得列表即可返回多值,如:
function maximum (a)
local mi = 1 — maximum index
local m = a[mi] — maximum value
for i,val in ipairs(a) do
if val > m then
mi = i
m = val
end
end
return m, mi
end

print(maximum({8,10,23,12,5})) –> 23 3
Lua总是调整函数返回值的个数去适用调用环境,当作为一个语句调用函数时,所有返回值被忽略.
function foo0 () end — returns no results
function foo1 () return ‘a’ end — returns 1 result
function foo2 () return ‘a’,'b’ end — returns 2 results
第一,当作为表达式调用函数时:有以下几种情况:
1.当调用作为表达式最后一个参数或者仅有一个参数时,根据变量个数函数尽可能多地返回多个值,不足补nil,超出舍去.
2.其他情况下,函数调用仅返回第一个值(如果没有返回值为nil)
x,y = foo2() — x=’a', y=’b’
x = foo2() — x=’a', ‘b’ is discarded
x,y,z = 10,foo2() — x=10, y=’a', z=’b’

x,y = foo0() — x=nil, y=nil
x,y = foo1() — x=’a', y=nil
x,y,z = foo2() — x=’a', y=’b', z=nil

x,y = foo2(), 20 — x=’a', y=20
x,y = foo0(), 20, 30 — x=’nil’, y=20, 30 is discarded
第二,函数调用作为函数参数被调用时,和多值赋值是相同.
print(foo0()) –>
print(foo1()) –> a
print(foo2()) –> a b
print(foo2(), 1) –> a 1
print(foo2() .. “x”) –> ax
第三,函数调用在表构造函数中初始化时,和多值赋值时相同.
a = {foo0()} — a = {} (an empty table)
a = {foo1()} — a = {’a'}
a = {foo2()} — a = {’a', ‘b’}

a = {foo0(), foo2(), 4} — a[1] = nil, a[2] = ‘a’, a[3] = 4
另外,return f()这种类型的返回f()返回的所有值
function foo (i)
if i == 0 then return foo0()
elseif i == 1 then return foo1()
elseif i == 2 then return foo2()
end
end

print(foo(1)) –> a
print(foo(2)) –> a b
print(foo(0)) — (no results)
print(foo(3)) — (no results)
可以使用圆括号强制使调用返回一个值.
print((foo0())) –> nil
print((foo1())) –> a
print((foo2())) –> a
一个return语句如果使用圆括号将返回值括起来也将导致返回一个值.
函数多值返回的特殊函数unpack,接受一个数组作为输入参数,返回数组的所有元素.unpack被用来实现范型调用机制,在C语言中可以使用函数指针调用可变的函数,可以声明参数可变的函数,但不能两者同时可变.在Lua中如果你想调用可变参数的可变函数只需要这样:
f(unpack(a))
unpack返回a所有的元素作为f()的参数
f = string.find
a = {”hello”, “ll”}
print(f(unpack(a))) –>3 4
预定义的unpack函数是用C语言实现的,我们也可以用Lua来完成:
function unpack (t, i)
i = i or 1
if t[i] then
return t[i], unpack(t, i + 1)
end
end
5.2 可变参数
Lua函数可以接受可变数目的参数,和C语言类似在函数参数列表中使用三点(…)表示函数有可变的参数.Lua将函数的参数放在一个叫arg的表中,除了参数以外,arg表中还有一个域n表示参数的个数.
例如,我们可以重写print函数:
printResult = “”

function print (…)
for i,v in ipairs(arg) do
printResult = printResult .. tostring(v) .. “\t”
end
printResult = printResult .. “\n”
end
有时候我们可能需要几个固定参数加上可变参数
function g (a, b, …) end

CALL PARAMETERS

g(3) a=3, b=nil, arg={n=0}
g(3, 4) a=3, b=4, arg={n=0}
g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2}
如上面所示,Lua会将前面的实参传给函数的固定参数,后面的实参放在arg表中.
举个具体的例子,如果我们只想要string.find返回的第二个值:
一个典型的方法是使用虚变量(下划线)
local _, x = string.find(s, p)
– now use `x’

还可以利用可变参数声明一个select函数:
function select (n, …)
return arg[n]
end
print(string.find(”hello hello”, ” hel”)) –> 6 9
print(select(1, string.find(”hello hello”, ” hel”))) –> 6
print(select(2, string.find(”hello hello”, ” hel”))) –> 9
有时候需要将函数的可变参数传递给另外的函数调用,可以使用前面我们说过的unpack(arg)返回arg表所有的可变参数,Lua提供了一个文本格式化的函数string.format(类似C语言的sprintf函数):
function fwrite (fmt, …)
return io.write(string.format(fmt, unpack(arg)))
end
这个例子将文本格式化操作和写操作组合为一个函数.
5.3 命名参数
Lua的函数参数是和位置相关的,调用时实参会按顺序依次传给形参.有时候用名字指定参数是很有用的,比如rename函数用来给一个文件重命名,有时候我们我们记不清命名前后两个参数的顺序了:
– invalid code
rename(old=”temp.”, new=”temp1.”)
上面这段代码是无效的,Lua可以通过将所有的参数放在一个表中,把表作为函数的唯一参数来实现上面这段伪代码的功能.因为Lua语法支持函数调用时实参可以是表的构造.
rename{old=”temp.”, new=”temp1.”}
根据这个想法我们重定义了rename:
function rename (arg)
return os.rename(arg.old, arg.new)
end
当函数的参数很多的时候,这种函数参数的传递方式很方便的.例如GUI库中创建窗体的函数有很多参数并且大部分参数是可选的,可以用下面这种方式:
w = Window{ x=0, y=0, width=300, height=200,
title = “”, background=”blue”,
border = true
}

function Window (options)
– check mandatory options
if type(options.title) ~= “string” then
error(”no title”)
elseif type(options.width) ~= “number” then
error(”no width”)
elseif type(options.height) ~= “number” then
error(”no height”)
end

– everything else is optional
_Window(options.title,
options.x or 0, — default value
options.y or 0, — default value
options.width, options.height,
options.background or “white”, — default
options.border — default is false (nil)
)
end
—–

相关文章

Tags :

《Programming in Lua中文版》4.Statements

Filed under: 程序开发 | No Comments »
Posted on

Lua像C和PASCAL几乎支持所有的传统语句:赋值语句,控制结构语句,函数调用等,同时也支持非传统的多变量赋值,局部变量声明.
4.1 赋值语句
赋值是改变一个变量的值和改变表域的最基本的方法.
a = “hello” .. “world”
t.n = t.n + 1
Lua可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量. a, b = 10, 2*x
表示,a=10 并且b=2*x
遇到赋值语句Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以这样进行交换变量的值:
x, y = y, x — swap ‘x’ for ‘y’
a[i], a[j] = a[j], a[i] — swap ‘a[i]‘ for ‘a[i]‘
当变量个数和值的个数不一致时,Lua会一直以变量个数为基础采取以下策略,:
a.变量个数>值的个数 按变量个数补足nil
b.变量个数 0 1 nil
a, b = a+1, b+1, b+2 — value of b+2 is ignored
print(a,b) –> 1 2
a, b, c = 0
print(a,b,c) –> 0 nil nil
上面最后一个例子是一个常见的错误情况,注意:如果要对多个变量赋值必须依次对每个变量赋值 .
a, b, c = 0, 0, 0
print(a,b,c) –> 0 0 0
多值赋值经常用来交换变量或者将函数调用返回给变量:
a, b = f()
f()返回两个值,第一个赋给a,第二个赋给b.
4.2 局部变量与代码块(block)
使用local创建一个局部变量,与全局变量不同,局部变量只在被声明的那个代码块内有效.代码块:指一个控制结构内,一个函数体,或者一个chunk(变量被声明的那个文件或者文本串).
x = 10
local i = 1 — local to the chunk

while i 2, 4, 6, 8, …
i = i + 1
end

if i > 20 then
local x — local to the “then” body
x = 20
print(x + 2)
else
print(x) –> 10 (the global one)
end

print(x) –> 10 (the global one)
注意,如果在交互模式下上面的例子可能不能输出期望的结果,因为第二句local i=1是一个完整的chunk,在交互模式下执行完这一句后,Lua将开始一个新的chunk,这样第二句的i已经超出了他的有效范围.可以将这段代码放在do..end(相当于c/c++的{})块中.
应该尽可能的使用局部变量,有两个好处:1.避免命名冲突2.访问局部变量的速度比全局变量更快.
我们给block划定一个明确的界限:do..end内的部分.当你想更好的控制局部变量的作用范围的时候这是很有用的.
do
local a2 = 2*a
local d = sqrt(b^2 - 4*a*c)
x1 = (-b + d)/a2
x2 = (-b - d)/a2
end — scope of ‘a2′ and ‘d’ ends here
print(x1, x2)
4.3 控制结构语句
控制结构的条件表达式结果可以是任何值,Lua认为false和nil为假,其他值为真.
if语句,有三种形式:
if conditions then
then-part
end;

if conditions then
then-part
else
else-part
end;

if conditions then
then-part
elseif conditions then
elseif-part
.. —>多个elseif
else
else-part
end;
while语句:
while condition do
statements;
end;
repeat-until语句:
repeat
statements;
until conditions;
for语句有两大类:
第一,数值for循环:
for var=exp1,exp2,exp3 do
loop-part
end
for将用exp3作为step从exp1(初始值)到exp2(终止值),执行loop-part;exp3可以省略,默认step=1
有几点需要注意:
1.三个表达式只会被计算一次,并且是在循环开始前.
for i=1,f(x) do print(i) end
for i=10,1,-1 do print(i) end
第一个例子f(x)只会在循环前被调用一次
2.控制变量var是局部变量自动被声明,并且只在循环内有效.
for i=1,10 do print(i) end
max = i — probably wrong! ‘i’ here is global
如果需要保留控制变量的值,需要在循环中将其保存
– find a value in a list
local found = nil
for i=1,a.n do
if a[i] == value then
found = i — save value of ‘i’
break
end
end
print(found)
3.循环过程中不要改变控制变量的值,那样做的结果是不可预知的.
如果要退出循环,使用break语句.
第二,范型for循环:
前面已经见过一个例子:
– print all values of array ‘a’
for i,v in ipairs(a) do print(v) end
范型for遍历迭代子函数返回的每一个值.
再看一个遍历表key的例子:
– print all keys of table ‘t’
for k in pairs(t) do print(k) end
范型for和数值for有两点相同:1.控制变量是局部变量,2.不要修改控制变量的值
再看一个例子,假定有一个表:
days = {”Sunday”, “Monday”, “Tuesday”, “Wednesday”,
“Thursday”, “Friday”, “Saturday”}

现在想把对应的名字转换成星期几,一个有效地解决问题的方式是构造一个反向表:
revDays = {["Sunday"] = 1, ["Monday"] = 2,
["Tuesday"] = 3, ["Wednesday"] = 4,
["Thursday"] = 5, ["Friday"] = 6,
["Saturday"] = 7}
下面就可以很容易获取问题的答案了:
x = “Tuesday”
print(revDays[x]) –> 3
我们不需要手工,可以自动构造反向表
revDays = {}
for i,v in ipairs(days) do
revDays[v] = i
end
如果你对范型for还有些不清楚在后面的章节我们会继续来学习.
4.4 break和return语句
break语句用来退出当前循环(for,repeat,while).在循环外部不可以使用.
return用来从函数返回结果,当一个函数自然结束结尾会有一个默认的return.(这种函数类似pascal的过程)
Lua语法要求break和return只能出现在block的结尾一句(也就是说:作为chunk的最后一句,或者在end之前,或者else前,或者until前),例如:
local i = 1
while a[i] do
if a[i] == v then break end
i = i + 1
end
有时候为了调试或者其他目的需要在block的中间使用return或者break,可以显式的使用do..end来实现:
function foo ()
return –

相关文章

Tags :

《Programming in Lua中文版》3.Expressions表达式

Filed under: 程序开发 | No Comments »
Posted on

Lua中的表达式包括数字常量,字符串常量,变量,一元和二元运算符,函数调用.还可以是非传统的函数定义和表构造.
3.1 算术运算符
二元运算符:+ - * / ^ (加减乘除幂)
一元运算符:- (负值)
这些运算符的操作数都是实数.
3.2 关系运算符
= == ~=
这些操作符返回结果为false或者true;==和~=比较两个值,如果两个值类型不同,Lua认为两者不同;nil只和自己相等.Lua通过引用比较tables,userdata,functions.也就是说当且仅当两者表示同一个对象时相等.
a = {}; a.x = 1; a.y = 0
b = {}; b.x = 1; b.y = 0
c = a

a==c but a~=b
Lua比较数字按传统的数字大小进行,比较字符串按字母的顺序进行,但是字母顺序依赖于本地环境.
当比较不同类型的值的时候要特别注意:
“0″==0 is false
2 5
print(nil and 13) –> nil
print(false and 13) –> false
print(4 or 5) –> 4
print(false or 5) –> 5
一个很实用的技巧:如果x为false或者nil则给x赋初始值v
x = x or v 等价于 if not x then x = v end
and的优先级比or高;
C语言中的三元运算符a ? b : c 在Lua中可以这样实现:(a and b) or c
not的结果一直返回false或者true
print(not nil) –> true
print(not false) –> true
print(not 0) –> false
print(not not nil) –> false
3.4 连接运算符
..字符串连接,如果操作数为数字,Lua将数字转成字符串.
print(”Hello ” .. “World”) –> Hello World
print(0 .. 1) –> 01
3.5 优先级
从高到低的顺序:
^
not - (unary)
* /
+ -
..
= ~= ==
and
or
除了^和..外所有的二元运算符都是左连接的.
a+i (a+i) 5+((x^2)*8)
a (a -(x^2)
x^y^z x^(y^z)
3.6 表的构造
构造器是创建和初始化表的表达式.表是Lua特有的功能强大的东西.最简单的构造函数是{},用来创建一个空表.可以直接初始化数组:
days = {”Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”}
Lua将用string “Sunday”初始化days[1](第一个元素索引为1),用”Monday”初始化days[2]…
print(days[4]) –> Wednesday
构造函数可以使用任何表达式初始化:
tab = {sin(1), sin(2), sin(3), sin(4),
sin(5), sin(6), sin(7), sin(8)}
如果想初始化一个表作为record使用可以这样:
a = {x=0, y=0} 和 a = {}; a.x=0; a.y=0等价
不管用何种方式创建table,我们都可以向表中添加或者删除任何类型的域,构造函数仅仅影响表的初始化.
w = {x=0, y=0, label=”console”}
x = {sin(0), sin(1), sin(2)}
w[1] = “another field”
x.f = w
print(w["x"]) –> 0
print(w[1]) –> another field
print(x.f[1]) –> another field
w.x = nil — remove field “x”
每次调用构造函数,Lua都会创建一个新的table,可以使用table构造一个list:
list = nil
for line in io.lines() do
list = {next=list, value=line}
end
这段代码从标准输入读进每行,然后反序形成链表.下面的代码打印链表的内容:
l = list
while l do
print(l.value)
l = l.next
end
在同一个构造函数中可以混合列表风格和record风格进行初始化,如:
polyline = {color=”blue”, thickness=2, npoints=4,
{x=0, y=0},
{x=-10, y=0},
{x=-10, y=1},
{x=0, y=1}
}
这个例子也表明我们可以嵌套构造函数来表示复杂的数据结构.
print(polyline[2].x) –> -10
上面两种构造函数的初始化方式还有限制,比如你不能使用负索引初始化一个表中元素,字符串索引也不能被恰当的表示,下面介绍一种更一般的初始化方式,我们用[expression]显示的表示将被初始化的索引:
opnames = {["+"] = “add”, ["-"] = “sub”,
["*"] = “mul”, ["/"] = “div”}
i = 20; s = “-”
a = {[i+0] = s, [i+1] = s..s, [i+2] = s..s..s}
print(opnames[s]) –> sub
print(a[22]) –> —
list风格初始化和record风格初始化是这种一般初始化的特例:
{x=0, y=0} {["x"]=0, ["y"]=0}
{”red”, “green”, “blue”} {[1]=”red”, [2]=”green”, [3]=”blue”}
如果真的想要数组下标从0开始:
days = {[0]=”Sunday”, “Monday”, “Tuesday”, “Wednesday”,
“Thursday”, “Friday”, “Saturday”}
注意:不推荐数组下标从0开始,否则很多标准库不能使用.
在构造函数的最后的”,”是可选的,可以方便以后的扩展.
a = {[1]=”red”, [2]=”green”, [3]=”blue”,}
在构造函数中域分隔符逗号(”,”)可以用分号(”;”)替代,通常我们使用分号用来分割不同类型的表元素.
{x=10, y=45; “one”, “two”, “three”}
—–

相关文章

Tags :

《Programming in Lua中文版》2.Types and Values类型和值

Filed under: 程序开发 | 2 Comments »
Posted on

Lua是动态类型语言,变量不要类型定义.Lua中有8个基本类型分别为:nil, boolean, number, string, userdata, function, thread, and table. 函数type可以测试给定变量或者值的类型。
print(type(”Hello world”)) –> string
print(type(10.4*3)) –> number
print(type(print)) –> function
print(type(type)) –> function
print(type(true)) –> boolean
print(type(nil)) –> nil
print(type(type(X))) –> string
变量没有预定义的类型,每一个变量都可能包含任一种类型的值.
print(type(a)) –> nil (`a’ is not initialized)
a = 10
print(type(a)) –> number
a = “a string!!”
print(type(a)) –> string
a = print — yes, this is valid!
a(type(a)) –> function
注意上面最后两行,我们可以使用function像使用其他值一样使用(更多的介绍参考第六章).一般情况下同一变量代表不同类型的值会造成混乱,最好不要用,但是特殊情况下可以带来便利,比如nil.
2.1 nil:
Lua中特殊的类型,他只有一个值:nil;一个全局变量没有被赋值以前默认值为nil;给全局变量负nil可以删除该变量。
2.2 booleans:
两个取值false和true.但要注意Lua中所有的值都可以作为条件.在控制结构的条件中除了false和nil为假,其他值都为真.所以Lua认为0和空串都是真.
2.3 numbers:
表示实数,Lua中没有整数.一般有个错误的看法CPU运算浮点数比整数慢.事实不是如此,用实数代替整数不会有什么误差(除非数字大于100,000,000,000,000).Lua的numbers可以处理任何长整数不用担心误差.你也可以在编译Lua的时候使用长整型或者单精度浮点型代替numbers,在一些平台硬件不支持浮点数的情况下这个特性是非常有用的,具体的情况请参考Lua发布版所附的详细说明.和其他语言类似,数字常量的小数部分和指数部分都是可选的,数字常量的例子:
4 0.4 4.57e-3 0.3e12 5e+20
2.4 Strings:
Strings指字符的序列. 是8位字节,所以字符串可以包含任何数值字符,包括嵌入的0。 这意味着你可以存储任意的二进制数据在一个字符串里.Lua中字符串是不可以修改的,你可以创建一个新的变量存放你要的字符串,如下:
a = “one string”
b = string.gsub(a, “one”, “another”) — change string parts
print(a) –> one string
print(b) –> another string
string和其他对象一样,Lua自动进行内存分配和释放,一个string可以只包含一个字母也可以包含一本书,Lua可以高效的处理长字符串,1M的string在Lua中是很常见的.
可以使用单引号或者双引号表示字符串
a = “a line”
b = ‘another line’
为了风格统一,最好使用一种,除非两种引号嵌套情况.对于字符串中含有引号的情况还可以使用转义符\来表示.Lua中的转义序列有:
\a bell
\b back space –后退
\f form feed –换页
\n newline –换行
\r carriage return –回车
\t horizontal tab –制表
\v vertical tab
\\ backslash –“\”
\” double quote 双引号
\’ single quote 单引号
\[ left square bracket 左中括号
\] right square bracket 右中括号
例子:
> print(”one line\nnext line\n\”in quotes\”, ‘in quotes’”)
one line
next line
“in quotes”, ‘in quotes’
> print(’a backslash inside quotes: \’\\\”)
a backslash inside quotes: ‘\’
> print(”a simpler way: ‘\\’”)
a simpler way: ‘\’
还可以在字符串中使用\ddd(ddd为三位十进制数字)方式表示字母.
“alo\n123\”" 和 ‘\97lo\104923″‘是相同的
还可以使用[[...]]表示字符串.这种形式的字符串可以包含多行也,可以嵌套且不会解释转义序列,如果第一个字符是换行符会被自动忽略掉.这种形式的字符串用来包含一段代码是非常方便的.
page = [[


[[a text between double brackets]]

]]

io.write(page)
运行时,Lua会自动在string和numbers之间自动进行类型转换,当一个字符串使用算术操作符时,string就会被转成数字.
print(”10″ + 1) –> 11
print(”10 + 1″) –> 10 + 1
print(”-5.3e - 10″*”2″) –> -1.06e-09
print(”hello” + 1) — ERROR (cannot convert “hello”)
反过来,当Lua期望一个string而碰到数字时,会将数字转成string .
print(10 .. 20) –> 1020
..在Lua中是字符串连接符,当在一个数字后面写..时必须加上空格以防止被解释错.
尽管字符串和数字可以自动转换,但两者是不同的,像 10 == “10″这样的比较永远都是错的.如果需要显式将string转成数字可以使用函数tonumber(),如果string不是正确的数字该函数将返回nil.
line = io.read() — read a line
n = tonumber(line) — try to convert it to a number
if n == nil then
error(line .. ” is not a valid number”)
else
print(n*2)
end
反之,可以调用tostring()将数字转成字符串,这种转换一直有效:
print(tostring(10) == “10″) –> true
print(10 .. “” == “10″) –> true
2.5 tables
Lua的tables实现了关联数组,关联数组指不仅可以通过数字下标检索数据,还可以通过别的类型的值检索数据.Lua中除了nil以外的类型都可以作为tables的索引下标.另外tables没有固定的大小,你可以根据需要动态的调整他的大小.tables是Lua主要的也是唯一的数据结构,我们可以通过他实现传统数组, 符号表, 集合, 记录(pascal), 队列, 以及其他的数据结构.Lua的包也是使用tables来描述的,io.read意味着调用io包中的read函数,对Lua而言意味着使用字符串read作为key访问io表.
Lua中tables不是变量也不是值而是对象.你可以把tables当作自动分配的对象,在程序中只需要操纵表的引用(指针)即可.Lua中不需要声明表,仅使用最简单的{}表达式语句即可创建表.
a = {} — create a table and store its reference in `a’
k = “x”
a[k] = 10 — new entry, with key=”x” and value=10
a[20] = “great” — new entry, with key=20 and value=”great”
print(a["x"]) –> 10
k = 20
print(a[k]) –> “great”
a["x"] = a["x"] + 1 — increments entry “x”
print(a["x"]) –> 11
表是匿名的,这就意味着表和持有表的变量没有必然的关系.
a = {}
a["x"] = 10
b = a — `b’ refers to the same table as `a’
print(b["x"]) –> 10
b["x"] = 20
print(a["x"]) –> 20
a = nil — now only `b’ still refers to the table
b = nil — now there are no references left to the table
当程序中不再引用表时,这个表将被删除,内存便可以重新被利用.表可以使用不同的索引类型存储值.索引大小随着表中元素个数的增加而增加.
a = {} — empty table
– create 1000 new entries
for i=1,1000 do a[i] = i*2 end
print(a[9]) –> 18
a["x"] = 10
print(a["x"]) –> 10
print(a["y"]) –> nil
最后一行,表对应的域没有被初始化所以为nil,和全局变量一样,Lua的全局变量存储正是使用表来存储的.
可以使用域名作为索引下表访问表中元素,Lua也支持a.name代替a["name"],所以我们可以用更清晰的方式重写上面的例子:
a.x = 10 — same as a["x"] = 10
print(a.x) — same as print(a["x"])
print(a.y) — same as print(a["y"])
两种方式可以混合使用,对于Lua来说,两种方式相同,但对于读者来说单一的风格更易理解.
常见的错误:混淆a.x 和a[x];第一种表示a["x"],即访问域为字符串”x”的表中元素,第二种表示使用变量x作为索引下标访问表中元素.
a = {}
x = “y”
a[x] = 10 — put 10 in field “y”
print(a[x]) –> 10 — value of field “y”
print(a.x) –> nil — value of field “x” (undefined)
print(a.y) –> 10 — value of field “y”
只要使用整数作为索引下标就可以表示传统的数组了,不需要指定数组大小:
– read 10 lines storing them in a table
a = {}
for i=1,10 do
a[i] = io.read()
end
当遍历数组元素时,第一个没有初始化的元素返回nil,可以用这个当作数组下标的边界标志.可以用下面的代码打印出上个例子读入的行:
– print the lines
for i,line in ipairs(a) do
print(line)
end
既然可以使用任意值作为表的下标,你可以以任何数字作为数组下标的开始,但是Lua中一般以1开始而不是0(c语言).Lua标准库也是以这个设计的.
有一点需要特别注意,否则你的代码中可能会引入很多难以发现的bug.因为我们可以使用任意类型的值作为索引下标,因此要注意:number 0 和string “0″是不同的,同样strings “+1″, “01″, and “1″也是不同的.
i = 10; j = “10″; k = “+10″
a = {}
a[i] = “one value”
a[j] = “another value”
a[k] = “yet another value”
print(a[j]) –> another value
print(a[k]) –> yet another value
print(a[tonumber(j)]) –> one value
print(a[tonumber(k)]) –> one value
当对你检索的类型有疑问时,请使用显示类型转换.
2.6 Functions
函数是第一类值(和其他变量相同),意味着函数可以存储在变量中,可以作为函数的参数,也可以作为函数的返回值.这个特性给了语言很大的灵活性:一个程序可以重新定义函数增加新的功能或者为了避免运行不可靠代码创建安全运行环境而隐藏函数,此外这特性在Lua实现面向对象中也起了重要作用(在第16章详细讲述).
Lua可以调用lua或者C实现的函数,Lua所有标准库都是用C实现的.标准库包括string库,table库,I/O库,OS库,算术库,debug库.
2.7 Userdata and Threads
userdata 可以将C数据存放在Lua变量中,userdata 在Lua中除了赋值和相等比较外没有预定义的操作.userdata 用来描述应用程序或者使用C实现的库创建的新类型.例如:用标准I/O库来描述文件.下面在C API章节中我们将详细讨论.
在第九章讨论协同操作的时候,我们介绍线程.
—–

相关文章

Tags :

WOW UI制作入门

Filed under: 程序开发 | 1 Comment »
Posted on

1.  准备开始

A.  可以选用的工具

第一步必须明白将要做些什么,但是为了能够正确的开始,我们必须选择一些编写脚本的工具。我想首先重要的一点是编辑器(用专业术语来说就是IDE- integrated development evironment), 这可能有许多种选择。由于我们编写脚本的语言是LUA(译注:一种脚本语言,参见:http://www..org),我们需要的编辑器应当是针对这种语言的,以下十供选择的列表:

http://blua.sourceforge.net/ (译注:sourceforge.net是一个著名的开源项目网站)
B: – 这是首当其充的脚本编辑工具之一,它提供了强大的IDE所提供的功能,足够用来编辑WOW的UI。而且它是用Java语言编写的,不论在何种操作系统中尼都能运行它。

http://www.ideais.com.br/luaeclipse/ (译注:一个运用于Eclipse IDE下的插件,建议使用过Java语言的专业人士使用。)
Eclipse – 这是另外一个Java环境的IDE,我没有用过这个IDE(译注:本文中的我不代表译者),它基于Eclipse 平台(译注:请参见http://www.eclipse.org),它是一个有着多种功能的插件,我确信这是一个很好的工具。

http://editplus.com/ (译注:editPlus是类似于UltraEdit的文本编辑器)
EditPlus – 这是替代记事本程序的有效工具,这也是我编辑LUA的工具。它有着多种你所需的功能,而且它有着LUA语言的Schema(译注:Schema可以理解为一种模板,它规定者文件如何定义等内容)。但是它有着30天的评估期,你得注册拥有它。

这只是3种建议,我认为一旦掌握了B:Lua后,你就能够更好地使用其它工具了。

B.目标:WOW文件

你拥有了编辑器后,一切只是刚刚开始,我们需要一些工具来编辑WOW。首选的工具是WinMPQ,下载地址:http://shadowflare.gameproc.com/dwnload.html#WinMPQ
你需要运行库(VB4运行库)来运行它(译注:一般windows都安装了),有了它你就可以打开游戏目录中的MPQ文件或者MoPaO 文件。MPQ是暴雪公司存储游戏资料的文件格式,如果你有兴趣研究的话,请参阅:http: //www.campaigncreations.org/starcraft/inside_mopaq/index.htm

有了WinMPQ,你就可以解开文件内容,并且打包到游戏安装目录。

Interface.mpq文件里面有基本的界面数据,并且有着大量柯作为例子的文件。Patch.mpq文件里有着所有的补丁内容,在游戏运行时将覆盖所有基础的文件。打开WinMpq,我们将所有基础界面文件作为例子来使用。下面还将示范如何保证数据与最新的补丁保持一致。使用“Open”选项打开 interface.mpq文件(该文件在游戏安装目录下),找到一个叫FrameXML的文件夹(还有一个叫glueXML的文件夹,不去管它),选中目录下所有文件并且解压到游戏安装以外的目录下。同样,打开Patch.mpq,其中不仅仅有界面文件,还有许多更新文件。打开Interface\ FrameXML目录,将其中的内容解压到刚才interface.mpq文件的解压目录中,并覆盖已有的文件。这样我们就有了一份最新的游戏界面 FrameXML目录数据作为参考。(你也可以用WinMPQ 解压其他的文件,例如音乐文件等)。

2.有了目标之后

一切准备就绪,让我们开始制作第一个插件吧!

首先你的知道具体文件的安排,哪个文件是做什么的。让我们看以下魔兽世界的安装吧。其中有许多目录,我们将要操作的目录是Interface目录(若不存在请创建)。在该目录下有3个主要的目录:
FrameXML: 有所有暴雪提供的界面,你将打交道的文件都在这。
GlueXML: 包含“游戏之外”的界面,例如登入界面,服务器选择,角色创建等。你不太需要关心这些文件。
AddOns: 所有游戏角色的模型。
在AddOns目录下每个角色都有其所有的目录并且有一个内容表。

3.开动!

A.  初始化

我们要开始创建“Hello world”啦!(译注:“Hello world”常指第一个程序),创建1个叫hello_world的目录在AddOns下,即 Warcraft/Interface/AddOns/hello_world。在目录中建立1个叫hello_world.toc的文件,这就是内容表了,它定义了WOW该如何装载插件内容。例如以下就是文件内容:
## Interface: 4114
## Title: Hello World
## Notes: The obligatory hello world script – -style!
## OptionalDeps:
## Dependencies:
hello_world.xml
作一下解释,第一行表示新的代码段的开始。事实上每次暴雪更新补丁后,当前的版本号都会更新。如果你的脚本没有最新的版本号,那么这段脚本将“不会”装载入游戏。这就是为什么版本更新导致插件无法使用的原因。你可以通过打开Interface\FrameXML\FrameXML.toc文件来知道当前的版本号。接下来两行的Title和Nodes就不必解释了吧(译注:分别为标题和注解,可选)。在下一行,OptionalDeps中你可以列出所有你的插件的名称(你可以列出其他插件,用空格分隔)。Dependencies也是同样的,但它不是可选的,我不太确定如果没有这一行你的插件是否会装载。最好所有的都写,不管它是不是可选的,这样所有人都能更好阅读你的代码。
在开始的声明之后,你将写入一些XML文件的名称(次序未定),一行写一个文件的名称。你也可以将XML文件写在子目录中,例如“core/hello_world.xml”,这样能使文件夹里看起来更简洁。

Interface.mpq文件里面有基本的界面数据,并且有着大量柯作为例子的文件。Patch.mpq文件里有着所有的补丁内容,在游戏运行时将覆盖所有基础的文件。打开WinMpq,我们将所有基础界面文件作为例子来使用。下面还将示范如何保证数据与最新的补丁保持一致。使用“Open”选项打开 interface.mpq文件(该文件在游戏安装目录下),找到一个叫FrameXML的文件夹(还有一个叫glueXML的文件夹,不去管它),选中目录下所有文件并且解压到游戏安装以外的目录下。同样,打开Patch.mpq,其中不仅仅有界面文件,还有许多更新文件。打开Interface\ FrameXML目录,将其中的内容解压到刚才interface.mpq文件的解压目录中,并覆盖已有的文件。这样我们就有了一份最新的游戏界面 FrameXML目录数据作为参考。(你也可以用WinMPQ 解压其他的文件,例如音乐文件等)。

2.有了目标之后

一切准备就绪,让我们开始制作第一个插件吧!

首先你的知道具体文件的安排,哪个文件是做什么的。让我们看以下魔兽世界的安装吧。其中有许多目录,我们将要操作的目录是Interface目录(若不存在请创建)。在该目录下有3个主要的目录:
FrameXML: 有所有暴雪提供的界面,你将打交道的文件都在这。
GlueXML: 包含“游戏之外”的界面,例如登入界面,服务器选择,角色创建等。你不太需要关心这些文件。
AddOns: 所有游戏角色的模型。
在AddOns目录下每个角色都有其所有的目录并且有一个内容表。

3.开动!

A.  初始化

我们要开始创建“Hello world”啦!(译注:“Hello world”常指第一个程序),创建1个叫hello_world的目录在AddOns下,即 Warcraft/Interface/AddOns/hello_world。在目录中建立1个叫hello_world.toc的文件,这就是内容表了,它定义了WOW该如何装载插件内容。例如以下就是文件内容:
## Interface: 4114
## Title: Hello World
## Notes: The obligatory hello world script – -style!
## OptionalDeps:
## Dependencies:
hello_world.xml
作一下解释,第一行表示新的代码段的开始。事实上每次暴雪更新补丁后,当前的版本号都会更新。如果你的脚本没有最新的版本号,那么这段脚本将“不会”装载入游戏。这就是为什么版本更新导致插件无法使用的原因。你可以通过打开Interface\FrameXML\FrameXML.toc文件来知道当前的版本号。接下来两行的Title和Nodes就不必解释了吧(译注:分别为标题和注解,可选)。在下一行,OptionalDeps中你可以列出所有你的插件的名称(你可以列出其他插件,用空格分隔)。Dependencies也是同样的,但它不是可选的,我不太确定如果没有这一行你的插件是否会装载。最好所有的都写,不管它是不是可选的,这样所有人都能更好阅读你的代码。
在开始的声明之后,你将写入一些XML文件的名称(次序未定),一行写一个文件的名称。你也可以将XML文件写在子目录中,例如“core/hello_world.xml”,这样能使文件夹里看起来更简洁。

B.加入内容
下面将是最有意思的部分,让我们从简单的开始。在目录中创建hello_world.xml文件(该文件名应写在了FrameXML.toc中),内容如下:

this:RegisterEvent(”VARIABLES_LOADED”);

if (event == “VARIABLES_LOADED”) then
hello_world_initialize();
end

哦。有些复杂了是么?其他不用管先看这一行,它告诉游戏 hello_world. 是脚本文件,也就是插件运行的脚本所在。每个界面都用的标签(Tag)扩起来。这里我们使用了一个Frame标签来简单地把所有事件脚本包进来,你也可以将所有的界面上的按钮,窗口等定义在Frame标签里面。在标签里,可以定义其一个叫name的属性(如:)
注意里面的值必须在整个文件里是唯一的。建议你用你的插件模块名称作为前缀开始,后接下划线,再接上Frame真正意义的名称。在上面的例子里,我们把它叫做core,因而组成了上述名字。
在标签里有个标签,其中是真正脚本的内容。在这里有许多事件(译注:即魔兽世界游戏程序在某阶段将做的某个动作),其中 和是最常用的2个。其中是当你选择了角色进入游戏时而角色Laoding画面开始之前的将响应的事件(换句话说,你的插件在登入画面时是不会被装载的)。在我们的代码中,我们注册了this给了一个叫“VARIABLES_LOADED”的事件(译注:看不懂代码的朋友还是先看看一些脚本语言的介绍书籍),this代表了当前的Frame,即这个名字叫hello_world_core的 Frame,this就是指向该Frame的对象/变量(指向该Frame对象的实例),这里的“:”相当于引用方法的表达符(像其他某些脚本语言中的”.” 号),而RegisterEvent函数的作用是告诉游戏程序在VARIABLES_LOADED事件发生时(VARIABLES_LOADED是游戏内定义的事件)通知你定义的Frame。说到这里又得说说这个标签了,在其中有一个默认的变量event,它的值就是当前游戏里产生的事件的名称(就好比上面的VARIABLES_LOADED)。
(译注: 真的是要了解编程的了哦。 这里处理事件就类似Win32处理事件的代码模式,可以用if(event=事件名称){操作代码}else if(event=事件名称2){操作代码}…..或者 switch case的方式来完成。)
现在,暴雪提供了存储变量的方法,你可以用RegisterForSave(“variable_name”)的方法来定义一个变量在游戏过程中。
在我们的例子中,当VARIABLES_LOADED发生后,将调用hello_world_initialize()函数来处理。对啦,这个hello_world_initialize()函数还没定义呢,下面就介绍如何定义函数。

C. 补完 (译注:写代码的部分,会写脚本的人一定看得懂,不会写的需要学习:

相关文章

Tags : ,

wow宏命令教程

Filed under: 程序开发 | No Comments »
Posted on

【转帖】宏命令教程

1.什么是宏命令?
  玩过EQ的都知道一点宏的知识,比如组队时用来告诉队友你的行动,告诉目标等。最简单的比如puller 常用的: /v %t过来了,大家集中火力。 法师常用的: /v 我要催眠%t,大家不要打醒他 这些宏个性鲜明,是EQ的一大乐趣之一。

  然而EQ毕竟是N年前的游戏,宏也比较简单,和它比起来。WOW的宏就复杂和强大的多了。它的函数就有上千种,如果都掌握,能实现许多匪夷所思的功能。

  一个宏可以完成一个相对比较复杂的命令.比如战斗中发布命令,如果打字当然不算麻烦,但在战斗中却很要命.浪费了时间和生命.一个简单的宏便可以用一个键来完成这一切.

  2.宏命令的设置流程:
  首先,回车,再敲/MACRO。看见了吧?会弹出一个窗口,上面有New(新建宏命令)和Complete(完成宏命令)两个按键。点New,又会弹出一个窗口,哇,花花绿绿的,里面包括了WOW几乎所有的技能图标,随你喜欢,随便选一个!它就是你设置的宏命令的图标了,给它取个名字吧!方便你用的时候好找。然后回到第一个窗口,在它上面有一个输入菜单(别告诉我找不到…它可是占了这个窗口的一半多…)在里面输入特定的内容,然后点Complete。接下来你要做的就是把这个代表你宏命令的图标用鼠标左键拉到快捷栏里,想怎么用就怎么用…

  3.下面就是怎样设置宏的内容了,简单的设置大家可以看我们网站上”基础”篇的宏介绍.

  相信很多人都知道WOW中的斜杠”/”和表情命令.宏可以将这些命令按照自己对条件的设置串联起来,比如:/Kneel是让你跪下来的动作而/say就是最基础的对话动作
  我们现在用一个宏把他们串起来:

  第一行内容:“/Kneel”
  第二行内容:“/say 如果你不嫁给我,那么我就一辈子不起来…” ”
  这样你的人物就会先下跪再说:”如果你不嫁给我,那么我就一辈子不起来…”

  宏可以应用所有WOW中已经定义了的斜杠”/”和表情命令,更要命的是,宏甚至可以应用人物的魔法和技能,

  只需要在宏的定义过程中应用”/cast”命令,下面是已知的一些常用命令:

  /Assist 这是个援助进攻的命令。当你的队伍同时面对几个敌人时,只要点击自己的队友(一般是队伍中的战士),然后使用这个命令,你的目标就会变成战士所选中的目标。大家集中火力消灭一个起!

  /Cast 这是个使用技能的命令。当你在宏命令里输入/Cast 技能名(技能等级)或者只要按住Shift同时用鼠标点击一下你想要输入的技能的图标。例如当你是一个战士,想制作一个使用战斗怒吼的宏时,你可以输入 /Cast Battle Shout(Rank 1)或者是直接按住Shift点击Battle Shout这个技能的图标。当然你可以在一个宏的不同行上输入几个技能,那么当你使用这个宏时,几个技能就会一起释放出来,再用不着你像章鱼一样同时按下几个键了 。

  %t 这个符号也许会经常出现在你的宏命令里,它是一个代码,代表你当前所选中的人名。例如,你在宏里写下这么一句。(注意:后面要加一空格。) “/g %t ,今天天气真好,有没兴趣和我一起上山采蘑菇…”
  如果你点中一位名叫苯笨的玩家,那么当你按下这个宏时,你就会说:“笨笨,今天天气真好,有没兴趣和我一起上山采蘑菇…”

  /Target 这是一个自动选择目标的命令,你可以在宏里输入/Target (xxx),那么当你按下这个宏时,你将自动选定这个叫xxx的目标。

  /in 这是一个延时命令,时间以秒为单位.同时它不支持攻击指令.格式:/in 3 dance 三秒后跳舞,如/in 3 dance,就是在3秒后跳舞,
  /say start!
  /in 3 say 3s later
  /in 6 say 6s later

  二:进阶教程

  一些有用的 Macro

  1。允许你在窗口和全屏状态之间切换

  /script SetCVar(”gxWindow”, 1 - GetCVar(”gxWindow”));
  /console gxRestart

  2。对于法师,必须要有的:将“X”换为你目前的变形术等级(下同);用它替换掉变形术技能。当你在队伍之外时使用它会得到“你不在队伍中。”的信息,但在队伍中的时候其它同伴会了解到你将释放的变形术目标。

  /p Sheeping >>> %t 20) then CastSpellByName(”Drain Life(Rank X)”) else

  CastSpellByName(”Drain Soul(Rank 2)”) end;

  2)虚弱诅咒版本
  /script if (UnitMana(”target”)>0) then CastSpellByName(”Curse of Tongues(Rank X)”) else

  CastSpellByName(”Curse of Weakness(Rank X)”) end;

  17.先治疗自己,然后自动选中上次的敌人
  /target Pugar //选择自己,假设自己的名字是Pugar
  /cast Lesser Heal (Rank 1) //施展次级治疗rank1
  /script TargetLastEnemy(); //重新选择刚刚选择的敌人
  /script AttackTarget(); //攻击,等同于右键点击敌人

  18.对于一个术士很有用的宏:首先将目标转为拖怪手或者坦克正在攻击的目标,然后命令宠物向前攻击

  ,跟着一个虚弱诅咒。
  /assist 队伍中的拖怪手或者坦克的名字
  /script PetAttack();
  /cast Curse of Weakness (Rank X)

  19.等治疗完之后提醒别人注意下自己有可能被怪打,不加延时的话,就没这个效果了。
  /p healing %T, need 3s, don”t run away
  /cast heal (rank 1)
  /in 4 p cured %T 300HP,please notice the enemies turn on me^_^

  20.在路上自动护送朋友做任务。

  /assist [player name]
  /cast 法术(Rank X)
  /target [player name]
  /follow [player name]

  三:高级教程

  WOW的宏函数库可以去这两个地方查:

  http://www.cosmosui.org/texts/BlizzardCommands.xml

  http://www.wowwiki.com/index.php/World_of_Warcraft_API

  函数的使用比较简单,学习过编程的都比较容易上手,基本的用法是在函数前加/script 来使用。比如
  /script CURRENT_ACTIONBAR_PAGE = X;
  /script ChangeActionBarPage();
  就是将你的快捷栏翻到第X页。

  函数库中有许多函数都是非常有用和方便的,比如一次打开所有包包:

  /script OpenAllBags();

  配合关闭包包的函数,一次关闭所有包的宏也可以实现:

  /script CloseBag(0);
  /script CloseBag(1);
  /script CloseBag(2);
  /script CloseBag(3);
  /script CloseBag(4);

  怎么样,下次你卖东西的时候不会一个个开包关包了吧?

  使用函数还不是最恐怖的,恐怖的是WOW的宏是可以用条件判断的,看下面这两个:
  /script if ( GetComboPoints() >= 3 ) then CastSpellByName(”Rip(Rank 2)”); else if (

  UnitMana(”player”) >= 40 ) then CastSpellByName(”Rake(Rank 1)”); end end

  据说这个包含if,then的宏可以让盗贼实现自动根据combo点数来使用技能(未测试),其中还使用了角

  色MANA值的调用,恐怖吧?还有这个查找spell的宏:
  function GetSpellIdByItsName(myWantedSpell, myWantedRank)
  local spellId = 1;
  local spellBook = “spell”;
  local spellName, rankName;
  spellName, rankName = GetSpellName(spellId, spellBook);
  while (spellName ) do
  if ( ( spellName == myWantedSpell ) and ( ( not myWantedRank ) or ( rankName = myWantedRank

  ) ) ) then return spellId; end
  spellName, rankName = GetSpellName(spellId, spellBook);
  end
  return -1;
  end

  里面可以自己定义function,还使用了while,do这样的循环,是不是让你想到了N种应用的可能呢?

  遗憾的是,目前官方似乎没有提供延时的宏,所以在战斗中使用多种有延时的技能是无法实现的(无延时的技能可以实现同时使用),类似换其他武器-使用技能或法术-换回武器这样的功能也无法实现,

  (所谓用宏实现剑盾战士换双手武器MS再换回来是行不通的),不过使用COSMOS的朋友可以用/in 来实现非战斗指令的延时,比如
  /in 3 say hi 就会在3秒后说句hi。

  /in 6 /script MoveForwardStart(arg1);
  就会在6秒后向前跑。

  虽然法术和技能无法用/in指令来延时,但这样已经很强大了,比如,你可以编出各种运动的宏,如兜后,转身等。PVP时估计是必不可少的。

  下面是一个玩家写的双手武器战士自动逃跑的宏:
  /script UseContainerItem(0, 2);ActionButtonDown(11);ActionButtonUp(11);ActionButtonDown

  (12);ActionButtonUp(12);
  /cast Thunder Clap(Rank 1);
  /script TurnLeftStart(arg1);
  /in 1 /script TurnLeftStop(arg1);ToggleAutoRun();

  使用这个宏的条件:在大包包第二格放了回复药,快捷栏第11,12分别是一单手一盾的快捷方式。

  使用这个宏后,角色自动喝回复药,装备上盾,使用Thunder Clap(这三个动作同时进行),向后转180度后开自动跑步键逃走。其中技能等可以根据需要自己改。怎么样,是不是很夸张啊,哈哈。

  还有一些有用的宏:

  切换装备,

  双手切换单手并换第二个快捷栏,快捷栏第11,12分别是一单手一盾的快捷方式
  /script ActionButtonDown(11);ActionButtonUp(11);ActionButtonDown(12);ActionButtonUp(12);
  /script CURRENT_ACTIONBAR_PAGE = 2;
  /script ChangeActionBarPage();
  单手切换双手并换回第一快捷栏,快捷栏12是一双手武器快捷方式
  /script ActionButtonDown(12);ActionButtonUp(12);
  /script CURRENT_ACTIONBAR_PAGE = 1;
  /script ChangeActionBarPage();
———————————————–转自艾斯拉泽国家地理—————————————–
—–

相关文章

Tags :

《Programming in Lua中文版》1.Getting Started起点

Filed under: 程序开发 | No Comments »
Posted on

1.1 Hello world 程序
print(”Hello World”)
假定你把上面这句保存在hello.lua文件中,你在命令行只需要:
prompt> hello.
看到结果了吗?
让我们来看一个稍微复杂点的例子:
– defines a factorial function
function fact (n)
if n == 0 then
return 1
else
return n * fact(n-1)
end
end

print(”enter a number:”)
a = io.read(”*number”) — read a number
print(fact(a))
这个例子定义了一个函数,计算输入参数n的阶乘;本例要求用户输入一个数字n,然后打印n的阶乘。
1.2 Chunks
Chunk是一系列语句,Lua执行的每一块语句,比如一个文件或者交互模式下的每一行都是一个Chunk.
每个语句结尾的分号(;)是可选的,但如果同一行有多个语句最好用;分开
a = 1 b = a*2 — ugly, but valid
一个Chunk可以是一个语句,也可以是一系列语句的组合,还可以是函数,Chunk可以很大,在Lua中几个MByte的Chunk是很常见的。
你还可以以交互模式运行,不带参数运行:
5.0 Copyright ? 1994-2003 Tecgraf, PUC-Rio
>
你键入的每个命令(比如:”Hello World”)在你键入回车之后立即被执行,键入文件结束符可以退出交互模式(ctrl-D in Unix, ctrl-Z in DOS/Windows),或者调用OS库的os.exit()函数也可以退出.
在交互模式下,Lua通常把每一个行当作一个chunk,但如果Lua一行不是一个完整的chunk时,他会等待继续输入直到得到一个完整的chunk.在Lua等待续行时,显示不同的提示符(一般是>>).
可以通过指定参数让Lua执行一系列chunk.例如:假定一个文件a内有单个语句x=1;另一个文件b有语句 print(x)
prompt> -la -lb
命令首先在一个chunk内先运行a然后运行b.(注意:-l选项会调用require,将会在指定的目录下搜索文件,如果环境变量没有设好,上面的命令可能不能正确运行.我们将在8.1节详细更详细的讨论the require function)
-i选项要求Lua运行指定chunk后进入交互模式.
prompt> -i -la -lb
将在一个chunk内先运行a然后运行b, 最后直接进入交互模式.
另一个连接外部chunk的方式是使用dofile函数,dofile函数加载文件并执行它.假设有一个文件:
– file ‘lib1.

function norm (x, y)
local n2 = x^2 + y^2
return math.sqrt(n2)
end

function twice (x)
return 2*x
end
在交互模式下:
> dofile(”lib1.”) — load your library
> n = norm(3.4, 1.0)
> print(twice(n)) –> 7.0880180586677
-i和dofile在调试或者测试Lua代码时是很方便的.

1.2 全局变量
全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil.
print(b) –> nil
b = 10
print(b) –> 10
如果你想删除一个全局变量,只需要将变量负值为nil
b = nil
print(b) –> nil
这样变量b就好像从没被使用过一样.换句话说, 当且仅当一个变量不等于nil时,这个变量存在。
1.3 词法约定
标示符:字母(letter)或者下划线开头的字母、下划线、数字序列.最好不要使用下划线加大写字母的标示符,因为Lua的保留字也是这样的.Lua中,letter的含义是依赖于本地环境的.
保留字:不能当作标示符
以下字符为Lua的保留字,不能当作标识符。
and break do else elseif
end false for function if
in local nil not or
repeat return then true until
while
注意:Lua是大小写敏感的.
注释:单行注释:–
多行注释:–[[ --]]
–[[
print(10) -- no action (comment)
--]]
1.4 命令行方式
[options] [script [args]]
-e:直接将命令传入
prompt> -e “print(math.sin(12))” –> -0.53657291800043
-l:加载一个文件.
-i:进入交互模式.
_PROMPT内置变量作为交互模式的提示符
prompt> -i -e “_PROMPT=’ > ‘”
>
Lua的运行过程,在运行参数之前,Lua会查找环境变量LUA_INIT的值,如果变量存在并且值为@filename,Lua将加载指定文件.如果变量存在但不是以@开头,Lua假定filename为Lua代码文件并且运行他.利用这个特性,我们可以通过配置,灵活的设置交互模式的环境.可以加载包,修改提示符和路径,定义自己的函数,修改或者重名名函数等.
全局变量arg存放Lua的命令行参数.
prompt> script a b c
在运行以前,Lua使用所有参数构造arg表.脚本名索引为0,脚本的参数从1开始增加.脚本前面的参数从-1开始减少.
prompt> -e “sin=math.sin” script a b
arg表如下:
arg[-3] = “
arg[-2] = “-e”
arg[-1] = “sin=math.sin”
arg[0] = “script”
arg[1] = “a”
arg[2] = “b”

相关文章

Tags :