简介

Smart Text是一个文本生成工具.
使用它可以帮助你用极少的时间快速生成大量文本(比如代码,报表,配置文件等等,本帮助文件就是使用SmartText生成的).
它内置了一个名为LuaTextTemplate的文本模板引擎(类似Velocity), 并提供了一个漂亮,简单易用的GUI让你更好地使用它.



主要特点:


开始

Smart Text需要运行在Windows XP/Vista/7及以上的操作系统.
并需要安装.Net Framework 4.0及以上.
双击SmartText.exe即可运行.


界面还算漂亮吧?好,那么让我们用一个简单的例子来看看Smart Text能干些什么.

怎么样,聪明的你应该能猜到Smart Text大概的本领了吧?




模板

SmartText的模板是生成文本的框架.
模板中使用一些特殊的标记来区分哪些是普通文本,哪些是要特殊处理的内容.
SmartText主要使用Lua语法做为模板的控制语法,
所以如果你熟悉Lua的话,你会非常容易的就能掌握SmartText的模板文件
如果不太熟悉Lua的话也不要紧,只需要学习几种非常简单的结构就能做出符合自己要求的模板文件来.

变量

通过开始中的例子,你应该已经知道了SmartText的模板使用变量的语法:

${表达式}

只要是一个合法的Lua表达式,SmartText就会计算该表达式的结果,并用结果替换变量出现的位置.
利用Lua的特性,可以很容易为一个变量设置一个默认值,比如:

${person.name or 'somebody'}

当person.name为nil(Lua中表示空值)时,则使用or后面的值(一个字符串somebody).
另外Lua中使用字符串,既可以使用双引号("),也可以使用单引号(').

之前的例子都展示了一个很重要的用法,即使用点(.)来表示参数的层级结构.
参数中我们还会详细讲解

流程控制语句

模板中可以使用判断语句(if)或者是循环语句(for)来控制文本生成的方式.
因为SmartText内部使用Lua(最终模板会被解析成Lua代码),所以流程控制语句都是使用标准的Lua语法.
唯一特别的是,需要使用#{...}的方式:

#{Lua语句}

if

看下面的例子:

#{if person.age < 18 then}
${person.name} is a child.
#{else}
${person.name} is an adult.
#{end}

该例子中,使用if语句根据年龄在child和adult中做出判断.
使用之前的xml参数的话,该示例的输出结果为:

WAKU is an adult.

Lua中if语句完整的语法是这样:

stat ::= if exp then block {elseif exp then block} [else block] end

当然在判断条件中也可以使用Lua中的运算符,下面是运算符的一个表格:

运算符 含义
== 相等
~= 不等
< 小于
> 大于
<= 小于等于
>= 大于等于
and
or
not

for

使用for语句,可循环输出模板中的一部分,在输出重复内容,列表等文本时极为有用.
Lua中的for有两种,我们先看第一种:数值型for

#{for i = 1, 5 do}
i = ${i}
#{end}

这个模板是如此简单甚至都不需要使用参数文件就能输出结果:

i = 1
i = 2
i = 3
i = 4
i = 5

数值型for的语法是这样:

stat ::= for Name `=´ exp1 `,´ exp2 [`,´ exp3] do block end
其中exp1是初始值,exp2是终止值,exp3是步进值,省略时默认值为1

然而在实际工作中,我们经常使用的是另一种for:范型for
演示范型for之前我们需要先扩展我们的参数文件:

<list>
    <person>
        <name>WAKU</name>
        <age>29</age>
    </person>
    <person>
        <name>Joey</name>
        <age>2</age>
    </person>
</list>

然后在模板中像下面这样使用范型for:

#{for p in enum(list.person) do}
NAME: ${p.name} AGE: ${p.age}
#{end}

输出结果为:

NAME: WAKU AGE: 29
NAME: Joey AGE: 2

SmartText将XML参数的解析成Lua代码,(将在参数中详细讲解)其中的person是一个Table(可做为数组),通过list.person来引用它.
SmartText提供了一个非常方便的函数enum,用来枚举Table中的元素,
所以enum(list.peronson)就是枚举数组中所有person,每次的枚举结果用p表示.


最后,提供范型for的语法:

stat ::= for namelist in explist do block end

以上就是关于流程控制的讲解,主要是if和for,但是SmartText与Lua结合的非常灵活,
实际上你可以在#{...}中插入任意有效的Lua语句,它们都将成为Lua代码并被执行.
你可以在#{...}中定义全局变量,并在模板的其它位置使用它.
你甚至可以定义函数,以此实现类似velocity中的宏.




参数

SmartText可以使用三种类型的参数文件(CSV XML LUA),虽然它们作用类似(都是向模板提供数据),
但是每种类型都有各自的优缺点,应当在不同场合使用合适的参数文件类型.
SmartText把CSV和XML参数文件都解析为Lua代码,但是不需要掌握解析的细节,只需要知道如何在模板中正确的使用数据即可.

CSV参数文件

CSV参数文件是最简单的参数文件,数据关系简单明了.可以使用EXCEL编辑CSV文件.
行列格式也和数据库中的表对应,所以如果想以数据库中的一个表做为参数的话,CSV参数文件是最合适不过的了.
但是CSV参数文件不能表示有层级关系的数据结构,这时就需要考虑使用XML和LUA形式的参数文件了.

示例:

模板文件:

${parameter[1].name} is ${parameter[1].age} years old.
${parameter[2].name} is ${parameter[2].age} years old.

参数文件 "parameter.csv":

name,age
WAKU,29
Joey,2

输出结果:

WAKU is 29 years old.
Joey is 2 years old.

因为CSV文件没有类似XML文件的根元素,所以SmartText将CSV参数文件的文件名做为每个变量的前缀.
示例中,因为CSV参数文件的文件名是parameter,所以前缀的名称也是parameter
使用下标方式访问CSV文件第一行的方式就变成了parameter[1](Lua的数组下标从1开始),
而访问该行name列中的内容就变成了parameter[1].name,很简单.

上面的示例虽然能很好的工作,但是模板却略显笨拙,
使用范型for,你完全可以使用以下的模板形式得到完全一样的输出结果:

#{for p in enum(parameter) do}
${p.name} is ${p.age} years old.
#{end}

值得一提的是,SmartText使用LumenWorks解析CSV文件,LumenWorks是我认为.Net中最棒的CSV解析器.


XML参数文件

XML文件是非常流行的文件格式,有着良好的兼容性,树状的关系最适合表现具有层级关系的数据结构.
.Net中对XML也有非常完善的支持,你可以将一个.Net对象序列化为XML文件,可以将DataSet对象直接写入XML文件等等.
XML参数文件的缺点可能是文件内容有些冗长,没有合适的工具的话编辑也有些麻烦.
同CSV参数文件一样,SmartText把XML参数文件也解析为Lua代码.

示例:

模板文件:

#{for p in enum(list.person) do}
${p.name} is ${p.age} years old.
${p.name} likes ${join(p.favourite_food.food)}.
#{end}

参数文件 "parameter.xml":

<list>
    <person name="WAKU" age="29">
        <favourite_food>
            <food>rice</food>
            <food>chicken</food>
        </favourite_food>
    </person>
    <person name="Joey" age="2">
        <favourite_food>
            <food>milk</food>
            <food>juice</food>
            <food>candy</food>
        </favourite_food>
    </person>
</list>

输出结果:

WAKU is 29 years old.
WAKU likes rice,chicken.
Joey is 2 years old.
Joey likes milk,juice,candy.

这个示例演示了如何正确的在模板中引用XML参数中的内容.
只需记住几个简单的规则:
1.变量从根节点开始(示例中根节点为list)
2.使用点(.)引用Attribute(示例中的name和age)
3.同样使用点(.)引用子节点
4.如果一个节点出现多次,则它就是一个数组,可以使用enum函数枚举(示例中的person和food)

示例的模板中出现了一个新函数join,和enum一样它也是由SmartText提供的.
作用是将一个数组中的字符串元素拼接起来,调用时第一个参数与enum一样(.Net的数组,集合或者Lua的Table);第二个参数可选,即拼接时的分隔符,默认是一个逗号(,).

LUA参数文件

Lua参数文件在三种参数文件中效率最高(因为CSV和XML都需要先解析为Lua代码),而且也是最灵活的一个.
它的缺点是没有CSV和XML那么流行,并且使用它需要掌握一定的Lua知识.
使用Lua参数文件完全可以实现之前CSV和XML的示例(直接使用技术细节中的Lua代码做为参数文件即可)
而Lua参数文件有些东西却是CSV和XML做不到的.

示例:

模板文件:

a = ${a}
b = ${b}
c = ${c}
a + b + c = ${a + b + c}

参数文件 "parameter.lua":

a = 1
b = 2
c = 3

输出结果:

a = 1
b = 2
c = 3
a + b + c = 6

如果使用CSV或者XML的话,模板中则不得不引用CSV的文件名或者XML的根节点名称,
参数文件也需要使用逗号或者放到XML的TAG中,而使用Lua参数文件则非常简单,直接赋值即可.
不过要注意的是,这些变量全被定义为Lua的全局变量,所以在使用的时候要注意命名冲突的问题.
当然如果变量非常多的话,则应该使用Lua的Table把变量组织起来.



错误处理

如果在生成文本时产生错误,SmartText会将错误信息以红色字体显示到文本框中.

Lua错误

SmartText将模板内容解析为Lua代码,所以模板应当符合Lua的语法要求,否则Lua的编译器就会报错,
另外一种就是模板没有语法错误,但是做为Lua代码运行时发生了运行时错误,
无论哪种错误,SmartText都会将错误信息截取并显示到文本框中.
看下面的例子:

#{for i = 1, 5}
i = ${i}
#{end}

该模板不需要参数文件即可运行,但是运行时SmartText会显示如下:

文本框中第一行是Lua编译器的错误信息,编译错误的格式为[string "chunk"]:line:
其中的line即是Lua代码中出错的行号.后面的内容是详细的错误描述,即缺少do.
第2行以下,就是根据模板解析生成的Lua代码,为了便于查看,SmartText在每行代码前添加了行号.

从输出的Lua代码中我们可以看出SmartText在解析模板时的一些处理细节:
1.流程控制#{...}中的内容直接被解析为Lua代码.(示例中的for和end语句);
2.RenderText是SmartText内部使用的一个函数,用来返回最终生成的文本;
3.使用 [=[ 和 ]=] 表示普通的字符串,防止其中的内容被转义;
4.Lua代码的最后一行return 0是SmartText固定添加的

未定义变量错误

当使用参数中不存在的变量时,会发生该错误.比如下面的模板:

${a} + ${b} + ${c}

如果不使用任何参数文件,该模板会产生如下错误:

[string "chunk"]:1: attempt to concatenate global 'c' (a nil value)
Lua Source:
  1 : RenderText(1, [=[]=] .. (a) .. [=[ + ]=] .. (b) .. [=[ + ]=] .. (c) .. [=[]=], '\r\n'); 
  2 : return 0

错误信息中明确的指出了哪个变量不存在,和该变量在代码中出现的位置.

另外,如果指定了参数文件, SmartText还会将参数文件解析成的Lua代码添加到文本框的最后,以便分析错误.



命令行参数

SmartText可以使用命令行参数,格式如下:

SmartText.exe template [parameter [output [template encoding [parameter encoding [output encoding]]]]]

分别对应模板文件,参数文件,输出文件,模板文件编码,参数文件编码和输出文件编码.
其中模板文件是必须项, 其它都可以省略.
第4到6个参数要求是编码的CODE PAGE(一个整数),可通过SmartText设定窗口中的各编码的下拉框查询编码的CODE PAGE.
下面是一个使用命令行参数的示例:

SmartText.exe "d:\template.txt" "" "d:\output.txt" 936 0 65001

使用d:\template.txt做为模板文件,不使用参数文件,使用d:\output.txt做为输出文件,模板文件的编码为GB2312,输出文件的编码为UTF-8.

当调用成功,输出文件就会被生成,除此之外没有任何提示,另外SmartText的返回值为0
如果调用失败,SmartText的GUI会显示出来,可通过错误处理中介绍的方法查看是哪出了问题.