Crystal语法
水晶报表默认支持的公式语言(除此之外还支持Basic),可参考VS报表官方文档,基础教程
- 大小写不敏感
- 由一系列表达式组成,最后一个表达式是公式的返回值
- 公式必须返回一个基本类型的值
1.基本类型
数字、货币、字符串、布尔值、日期、时间、日期时间。
// 货币
$10000
-$20
$1.23
CCur (10000)
CCur (-20)
CCur (1.23)
// 字符串
"This is a string."
"123"
"The word ""hello"" is quoted."
'.'
'3'
'r''s'
"hello" [2] //Equal to "e"
"hello" [-5] //Equal to "h"
"604-555-1234" [1 to 3] //Equal to "604"
"abcdef" [-3 to -1] //Equal to "def"
// 日期 时间 日期时间
#8/6/1976 1:20 am#
#August 6, 1976#
#6 Aug 1976 13:20:19#
#6 Aug 1976 1:30:15 pm#
#8/6/1976#
#10:20 am#
// 转为日期时间
CDateTime ("8/6/1976 1:20 am")
CDateTime ("10:20 am")
// 转为日期
CDate ("Aug 6, 1969")
CDate (1969, 8, 6) //指定年、月、日。
CDate (#Aug 6, 1969#)
// 转为时间
CTime ("10:30 am")
CTime (10, 30, 0) //指定小时、分钟、秒。
CTime (#10:30 am#)
2.范围数据类型
除布尔值外,所有基本类型都可以使用范围类型。
// [2, 5]
2 To 5
// (2, 5]
2 _To 5
// <= 5
UpTo 5
// < 5
UpTo_ 5
#Jan 5, 1999# To #Dec 12, 2000#
UpFrom #Jan 1, 2000#
结合IF
Select {Student.Test Scores}
Case UpFrom 90 :
"A"
Case 80 To_ 90 :
"B"
Case 70 To_ 80 :
"C"
Case 60 To_ 70 :
"D"
Default :
"F";
结合IN
5 In 2 To 10; //True
5 In 2 To_ 5; //False
5 In 2 To 5; //True
结合最大值或最小值获得边界
Maximum (2 To 10) //Returns 10
3.数组数据类型
与其他语言相似
[10, 5, 20] [2 To 3] // = [5, 20]
4.变量
声明
Local NumberVar x := 10 + 20;
Local StringVar y := "Hello" + " " + "World";
Local DateVar z := CDate (#Sept 20, 1999#);
Local NumberVar Range gradeA := 90 To 100;
Local NumberVar Range gradeA;
Local DateVar Range quarter;
gradeA := 90 To 100;
quarter := CDate (1999, 10, 1) To CDate (1999, 12, 31);
作用域:局部、全局、共享。
局部变量通过Local关键字声明。局部变量仅单个公式共享。
//Formula A
Local NumberVar x;
x := 10;
//Formula B
EvaluateAfter ({@Formula A})
Local NumberVar x;
x := x + 1;
全局变量通过Global关键字声明,可省略Global。全局变量在主报表中共享。
Global StringVar y;
StringVar y; //等同于: Global StringVar y;
共享变量使用相同的内存块,在整个主报表和所有子报表中共享。在主报表和子报表都需要声明。
Shared NumberVar x := 1000; // 主报表
Shared NumberVar x; // 子报表
5.数组变量
声明
//将 x 声明为数字数组类型的全局变量
Global NumberVar Array x := [10 , 20, 30];
//Cost 是货币数组类型的全局变量。
//由于忽略了作用域指定符(Local、Global 或 Shared 其中之一),因此它将自动成为全局变量。
CurrencyVar Array cost := [$19.95, $79.50, $110.00, $44.79, $223.99];
//payDays 是日期数组类型的全局变量。
Global DateVar Array payDays := [CDate(1999, 5, 15), CDate(1999, 5, 31)];
//y 是字符串范围数组类型的共享变量。
Shared StringVar Range Array y := ["A" To "C", "H" To "J"];
//days 是字符串数组类型的局部变量。
Local StringVar Array days;
days := ["Sun", "Mon", "Tue", "Wed", "Th", "Fri", "Sat"];
调整数组变量的大小
Local NumberVar Array x;
Redim x [2]; // x = [0, 0]
x [2] := 20; // x = [0, 20]
Redim x [3]; // x = [0, 0, 0]
x [3] := 30; // x = [0, 0, 30]
Redim Preserve x [4]; // x = [0, 0, 30, 0]
"finished"
Local StringVar Array a;
Redim a [2];
a[1] := "good";
a[2] := "bye";
a[1] & a[2] //该公式返回字符串“goodbye”
结合for
Local NumberVar Array b;
Redim b[10];
Local NumberVar i;
For i := 1 To 10 Do
(
b[i] := 10 * i
);
b [2]
6.类型转换
支持:数字到货币、日期到日期时间、简单类型到同一简单类型的范围值
Local CurrencyVar cost;
//等同于: cost := $10
cost := 10;
Local DateTimeVar orderDate;
//等同于: orderDate := CDateTime (1999, 9, 23, 0, 0, 0)
orderDate := CDate (1999, 9, 23);
Local NumberVar Range aRange;
//等同于: aRange := 20 To 20
aRange := 20;
Local NumberVar Range Array aRangeArray;
//等同于: aRangeArray := [10 To 10, 20 To 25, 2 To 2]
aRangeArray := [10, 20 To 25, 2];
货币到数字
Local NumberVar num;
num := 5 + $10;
//正确 - 使用 CDbl 函数转换为数字类型
num := CDbl (5 + $10)
7.运算符
算数运算符: 加 (+)、减 (-)、乘 (*)、除 (/)、整除 ()、百分比 (%)、求余 (Mod)、求反 (-) 和求幂 (^)。
//未上市的优先股占普通股的百分比。
{Financials.Preferred Stock} %
{Financials.Common Stock};
7 + 2 * 3 - 2 + Sqr(6 + 3) * Length("up");
//该公式返回 17。
布尔运算符: Not、And、Or、Xor、Eqv 和 Imp。
8.条件分支
IF
条件结果类型应当保持一致
If {Employee.Dept} = "Sales" Then
{Employee.Salary} * 0.06
Else
{Employee.Salary} * 0.04
分组时返回值类型也应当保持一致,如下所示可颠倒表达式的顺序,都返回0
Local StringVar message;
Local CurrencyVar ship;
If {Orders.Ship Date} - {Orders.Order Date} <= 3 Then
(
message := "Rush";
ship := {Orders.Order Amount} * 0.05;
0
)
Else
(
ship := {Orders.Order Amount} * 0.02;
message := "Regular";
0
);
message & " shipping is " & CStr (ship)
Select
Select {Customer.Fax}[1 To 3]
Case "604", "250" :
"BC"
Case "206", "509", "360" :
"WA"
Default :
"";
9.循环
For
Local StringVar str := "";
Local NumberVar strLen :=
Length ({Customer.Customer Name});
Local NumberVar i;
For i := 1 To strLen Do
(
Local NumberVar charPos := strLen - i + 1;
str := str + {Customer.Customer Name}[charPos]
);
str
For Step
Local StringVar str := "";
Local NumberVar strLen :=
Length ({Customer.Customer Name});
Local NumberVar i;
For i := strLen To 1 Step -1 Do
(
str := str + {Customer.Customer Name}[i]
);
str
Exit For退出循环
Global StringVar Array names;
//名称数组已初始化,并已填充到其他公式中。["Frank", "Helen", "Fred", "Linda"]
Local NumberVar i;
Local NumberVar result := -1;
//UBound 函数返回其数组参数的大小。
For i := 1 to UBound (names) Do
(
If names [i] = "Fred" Then
(
result := i;
Exit For
)
);
result
While Do 或Do While,Exit While可退出循环
Local StringVar inString := "The 7 Dwarves";
Local NumberVar strLen := Length (inString);
Local NumberVar result := -1;
Local NumberVar i := 1;
While i <= strLen And result = -1 Do
(
Local StringVar c := inString [i];
If NumericText (c) Then
result := i;
i := i + 1;
);
result
循环存在一个安全机制
每个公式求值最多有100000次循环条件求值。
安全机制针对每个公式,并非应用每个循环。
触发演示一
Local NumberVar i := 1;
While i <= 200000 Do
(
If i > {movie.STARS} Then
Exit While;
i := i + 1
);
20
触发演示二
Local NumberVar i := 1;
For i := 1 To 40000 Do
(
Sin (i);
);
While i <= 70000 Do
(
i := i + 1;
)
10.公式大小限制
除了安全机制中的100000次循环条件求值,还有
- 字符串最大长度65534
- 数组最大大小1000个元素
- 参数个数不定的函数最多支持1000个参数,如Choose
- 日期1-9999(Visual Basic为100-9999)
11.常用函数
Mid截取字符串
Local StringVar x := "hello";
Local StringVar y;
//从位置 2 开始,直到字符串的末尾。
y := Mid (x, 2); //y 现在为 "ello"。
//Start at position 2, extract 1 character
y := Mid (x, 2, 1) //y 现在为 "e"。
空值
IsNull({Product.Color}) Or
InStr({Product.Color}, " ") = 0
反向字符串
StrReverse ({Customer.Customer Name})
除此之外,在编辑公式的弹窗中,软件提供了【函数】【运算符】参考。
eg.
循环
WhilePrintingRecords;
Local StringVar Array InputNum := {?StringMultiParam};
Local StringVar str := "";
Local NumberVar strLen := Count (InputNum);
Local NumberVar i;
For i := 1 to strLen Step + 1 Do
(str := str + '+' + InputNum[i] + chr(13));
str
条件
WhilePrintingRecords;
Local StringVar Array InputNum := {?StringMultiParam};
Local StringVar str := "";
Local NumberVar strLen := Count (InputNum);
Local NumberVar i;
For i := 1 to strLen Step + 1 Do
(
If i = strLen Then
(
If InputNum[i][1] = 'a' Then
str := str + ' ' + InputNum[i][2 to Length(InputNum[i])]
Else
str := str + ' ' + InputNum[i][2 to Length(InputNum[i])]
)
Else
(
If InputNum[i][1] = 'a' Then
str := str + ' ' + InputNum[i][2 to Length(InputNum[i])] + ' '
Else
str := str + ' ' + InputNum[i][2 to Length(InputNum[i])] + ' '
)
);
str