558 lines
14 KiB
Markdown
558 lines
14 KiB
Markdown
# TSL 值与字面量
|
|
|
|
文档类型:语法主线
|
|
是否可直接用于生成代码:是
|
|
是否含可直接照写示例:是
|
|
是否含不可照写反例:是
|
|
遇到不确定时:先按本页候选页继续判断;[04_variables_and_constants.md](04_variables_and_constants.md)、[06_expressions_and_operators.md](06_expressions_and_operators.md)、[12_matrix_and_collections.md](12_matrix_and_collections.md)、[17_types_and_conversions.md](17_types_and_conversions.md);仍在语法层但不命中时回到本 Skill 路由中心 [index.md](index.md);如果问题已经超出语法层,停止并交接给对应事实所有者
|
|
|
|
这一篇整理基本类型、字面量、数组、字符串、字符串编码边界与基础值模型,避免把值规则分散在函数或金融示例里。
|
|
|
|
## 本篇职责
|
|
|
|
回答“基本类型怎么写、数组和字符串怎么索引、字符串编码边界怎么写、哪些值规则属于语言级事实”。矩阵、集合扩展和复杂容器不在本页展开;命中这些任务时跳到 [12_matrix_and_collections.md](12_matrix_and_collections.md) 或对应深水专题。
|
|
|
|
## 智能体值写法判断流程
|
|
|
|
1. 普通值优先从整数、实数、普通字符串、布尔和 `array(...)` 起手。
|
|
2. 字符串默认用普通字符串;只有编码、宽串、UTF8、原始字符串、字符码或 ASCII `0` 需求明确时,才使用本页字符串边界规则里的文档明确形态。
|
|
3. 看到 `array(...)` 时,先判断要顺序数组还是字符串键表:顺序数组用位置元素,字符串键表用 `"Key": value`。
|
|
4. 写下标前先判断对象类别:顺序数组和二进制缓冲区下标从 `0` 开始,字符串下标从 `1` 开始。
|
|
5. 写字符串区间前先确认 `s[start:end]` 的 `end` 会被包含;不要按半开区间推断。
|
|
6. 如果任务已经变成矩阵、集合扩展、结果集过滤或 TS-SQL 数据形态,不要留在值页硬拼写法;先跳到 [12_matrix_and_collections.md](12_matrix_and_collections.md)、[13_resultset_and_filters.md](13_resultset_and_filters.md) 或 [14_ts_sql.md](14_ts_sql.md)。
|
|
7. 没有对应代码块时不要发明值写法;尤其不要从 JSON、JavaScript、Pascal 或 C 字符串规则直接迁移。
|
|
|
|
## 核心规则
|
|
|
|
- 最先掌握的几类值是:整数、实数、普通字符串、布尔和 `array(...)`。
|
|
- 普通字符串既可以用双引号,也可以用单引号。
|
|
- 同类引号本身可以通过连续写两个同类引号放进字符串里。
|
|
- `\\`、`\"`、`\n` 这类基础转义可用。
|
|
- `\t` 和 `\xNN` 这类转义也可用。
|
|
- `\r`、`\r\n`、`\a`、`\b`、`\f`、`\v` 这些经典转义也可用。
|
|
- `array(...)` 既可以写顺序数组,也可以写字符串键表。
|
|
- 顺序数组下标从 `0` 开始。
|
|
- `binary(...)` 创建的二进制缓冲区也用 `[]` 访问,并且下标从 `0` 开始。
|
|
- 字符串下标从 `1` 开始。
|
|
- `s[0]` 在运行时会越界,不要把字符串当成 0 基下标。
|
|
- 字符串取子串用 `s[start:end]`,并且 `end` 是包含在结果里的。
|
|
- 字符串替换子串用 `s[start:end] := "..."`。
|
|
- 字符串删除子串,本质上就是 `s[start:end] := ""`。
|
|
- 字符串插入子串用 `s[index:0] := "..."`。
|
|
- 普通字符串、`L""` 宽串、`U""` UTF8 前缀串,以及 `%%` 原始字符串都属于文档明确写法。
|
|
- `%%` 原始字符串开头后必须先跟一个空白分隔符;可以带标识符,也支持多行。
|
|
- `L%% ...%%` 与 `U%% ...%%` 这两种带前缀的原始字符串也属于文档明确写法。
|
|
- 普通字符串里的 `\uXXXX` 不要直接按“单字符宽串”理解;`length("\u0041") = 2`,而 `length(L"\u0041") = 1`、`length(U"\u0041") = 1`。
|
|
- `U""` 不是宽串;需要在 UTF8、宽串、普通串之间显式转换时,继续用 `utf8ToUnicode(...)`、`utf8ToAnsi(...)`、`ansiToUtf8(...)`、`unicodeToUtf8(...)`、`string(...)`、`wideString(...)`。
|
|
- `#number` 可以直接把字符码拼进字符串。
|
|
- `\0` 和 `#0` 都能把 ASCII `0` 放进字符串,并且不会把字符串截断。
|
|
|
|
## 可直接照写示例
|
|
|
|
使用这些示例时遵守:
|
|
|
|
- 只复制任务需要的值、字面量、下标或字符串片段,不要把多个示例拼成未写入文档的新语法。
|
|
- 普通示例默认按 `.tsl` 脚本语句区书写;需要函数或类型时,放在后置声明区。
|
|
- 字符串编码、宽串和原始字符串边界不清楚时,优先看本页“字符串边界规则”。
|
|
|
|
最基础的值写法:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
count := 1;
|
|
price := 12.5;
|
|
name := "ABC";
|
|
flag1 := true;
|
|
flag2 := false;
|
|
items := array(1, 2, 3);
|
|
writeLn(count);
|
|
writeLn(price);
|
|
writeLn(name);
|
|
writeLn(flag1);
|
|
writeLn(flag2);
|
|
writeLn(items[1]);
|
|
```
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
1
|
|
12.5
|
|
ABC
|
|
1
|
|
0
|
|
2
|
|
```
|
|
|
|
代码块说明:`true` / `false` 可以直接写成布尔值;运行输出里分别表现为 `1` / `0`。
|
|
|
|
普通字符串字面量:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
writeLn("ABC");
|
|
writeLn('XYZ');
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 依次输出 `ABC`、`XYZ`
|
|
|
|
字符串内引号与基础转义:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
writeLn("A""B");
|
|
writeLn('A''B');
|
|
writeLn("A\\B");
|
|
writeLn("A\"B");
|
|
writeLn("A\nB");
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 依次输出 `A"B`、`A'B`、`A\B`
|
|
- `"A\nB"` 会分成两行输出 `A` 和 `B`
|
|
|
|
更多基础转义:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
writeLn("A\tB" = "A"#9"B");
|
|
writeLn("A\x30B" = "A0B");
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 两行都输出 `1`
|
|
- 说明 `\t` 可以表示制表符,`\x30` 这类写法可以按 ANSI 字节值插入字符
|
|
|
|
经典控制字符转义:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
writeLn("\r" = #13);
|
|
writeLn("\r\n" = #13#10);
|
|
writeLn(length("\r\n"));
|
|
writeLn("\a" = #7);
|
|
writeLn("\b" = #8);
|
|
writeLn("\f" = #12);
|
|
writeLn("\v" = #11);
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 依次输出 `1`、`1`、`2`、`1`、`1`、`1`、`1`
|
|
- 说明 `\r` / `\r\n` 可以直接表示回车和回车换行
|
|
- 说明 `\a`、`\b`、`\f`、`\v` 也属于可用的经典转义
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
items := array(10, 20, 30);
|
|
row := array("Code": "0001", "Price": 12.3);
|
|
s := "ABC";
|
|
writeLn(items[0]);
|
|
writeLn(items[1]);
|
|
writeLn(row["Code"]);
|
|
writeLn(s[1]);
|
|
writeLn(s[2]);
|
|
writeLn(s[3]);
|
|
```
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
10
|
|
20
|
|
0001
|
|
A
|
|
B
|
|
C
|
|
```
|
|
|
|
代码块说明:顺序数组 `items` 从 `0` 开始,字符串键表 `row` 用字符串键访问,字符串 `s` 从 `1` 开始。
|
|
|
|
### 字符串边界规则
|
|
|
|
原始字符串 `%%` 的空白分隔、标识符和多行:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
s1 := %% ABC%%;
|
|
s2 := %%tag A"B'C%%tag;
|
|
s3 := %%m
|
|
A
|
|
B%%m;
|
|
writeLn(s1);
|
|
writeLn(s2);
|
|
writeLn(s3);
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- `s1` 输出 `ABC`
|
|
- `s2` 输出 `A"B'C`
|
|
- `s3` 输出两行 `A`、`B`
|
|
- 说明 `%%` 开头后的第一个空白只是分隔符,不属于正文
|
|
- 说明 `%%tag ...%%tag` 可以用标识符配对
|
|
- 也说明 `%%` 原始字符串支持直接跨行
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
ABC
|
|
A"B'C
|
|
A
|
|
B
|
|
```
|
|
|
|
带前缀的原始字符串:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
writeLn(L%% ABC%% = L"ABC");
|
|
writeLn(U%% ABC%% = "ABC");
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 依次输出 `1`、`1`
|
|
- 说明 `L%% ...%%` 和 `U%% ...%%` 都属于文档明确写法
|
|
|
|
`\uXXXX` 在普通串、宽串和 `U` 串里的边界:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
writeLn(length("\u0041"));
|
|
writeLn(length(L"\u0041"));
|
|
writeLn(length(U"\u0041"));
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 依次输出 `2`、`1`、`1`
|
|
- 因此不要把普通字符串里的 `"\u0041"` 直接理解成和 `L"\u0041"` 一样的“单字符”写法
|
|
|
|
字符串显式编码转换:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
utf8_s := U"\u5929\u8F6F";
|
|
utf8_s2 := unicodeToUtf8(L"\u5929\u8F6F");
|
|
wide_s := utf8ToUnicode(utf8_s);
|
|
ansi_s := utf8ToAnsi(utf8_s);
|
|
writeLn(ifWString(utf8_s));
|
|
writeLn(utf8_s = utf8_s2);
|
|
writeLn(wide_s = L"\u5929\u8F6F");
|
|
writeLn(ansi_s = string(L"\u5929\u8F6F"));
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 依次输出 `0`、`1`、`1`、`1`
|
|
- 说明 `U""` 不是宽串
|
|
- 说明 UTF8、宽串、普通串之间可以按示例显式转换
|
|
|
|
ASCII `0` 字符不会截断字符串:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
s1 := "A\0B";
|
|
s2 := "A"#0"B";
|
|
writeLn(length(s1));
|
|
writeLn(length(s2));
|
|
writeLn(s1 = s2);
|
|
writeLn(s1[2] = #0);
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 依次输出 `3`、`3`、`1`、`1`
|
|
- 说明 `\0` 和 `#0` 都可以把 ASCII `0` 放进字符串
|
|
- 也说明 TSL 字符串不是遇到 `#0` 就自动截断的 C 风格零结尾串
|
|
|
|
字符码拼接:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
writeLn("A"#48"B");
|
|
writeLn("A"#13#10"B");
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 第一行输出 `A0B`
|
|
- 第二组输出会分成两行 `A`、`B`
|
|
- 说明 `#48` 这类写法会按字符码直接参与字符串拼接,`#13#10` 可以直接表示换行
|
|
|
|
二进制缓冲区:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
b := binary("30");
|
|
writeLn(ifBinary(b));
|
|
writeLn(b[0] = "3");
|
|
writeLn(b[1] = "0");
|
|
b[1] := 0x31;
|
|
writeLn(b[1] = "1");
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 依次输出 `1`、`1`、`1`、`1`
|
|
- 说明 `binary(...)` 会得到二进制缓冲区
|
|
- 说明二进制缓冲区的 `[]` 下标从 `0` 开始
|
|
- 也说明二进制缓冲区项可以直接按单字节读写
|
|
|
|
字符串子串读取:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
s := "ABCDE";
|
|
writeLn(s[2:4]);
|
|
```
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
BCD
|
|
```
|
|
|
|
代码块说明:字符串区间 `2:4` 会包含结束位 `4`。
|
|
|
|
字符串替换子串:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
s := "ABCDE";
|
|
s[2:4] := "XYZ";
|
|
writeLn(s);
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 输出 `AXYZE`
|
|
|
|
字符串删除子串:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
s := "ABCDE";
|
|
s[2:4] := "";
|
|
writeLn(s);
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 输出 `AE`
|
|
|
|
字符串插入子串:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
s := "AAABBB";
|
|
s[4:0] := "111";
|
|
writeLn(s);
|
|
```
|
|
|
|
结果说明:
|
|
|
|
- 输出 `AAA111BBB`
|
|
- 这说明 `s[index:0] := ...` 是在指定位置插入,而不是删除或替换区间
|
|
|
|
### 字符串 `$` 连接与拼装
|
|
|
|
`$` 用于字符串连接和类型转字符串拼装:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
s1 := "abc" $ "def";
|
|
a := 1;
|
|
b := 2.34;
|
|
c := "AAA";
|
|
d := "A=" $ a $ " B=" $ b $ " C=" $ c;
|
|
writeLn(s1);
|
|
writeLn(d);
|
|
```
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
abcdef
|
|
A=1 B=2.34 C=AAA
|
|
```
|
|
|
|
说明:
|
|
|
|
- `"abc" $ "def"` 连接两个字符串得到 `"abcdef"`
|
|
- 整数、实数等类型可以直接用 `$` 拼装成字符串
|
|
- 拼接实数时,保留最高精度,表现与 `floattostr` 一致
|
|
- 纯小数可能走科学计数法:`"_" $ 0.0000005 $ ","` 返回 `"_5E-7,"`
|
|
- 带整数部分的小数保留精度:`"_" $ 1.0000005 $ ","` 返回 `"_1.0000005,"`
|
|
|
|
### 字符串 `like` 模式匹配
|
|
|
|
`like` 用于判断字符串是否符合指定模式(支持通配符和正则表达式):
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
result1 := "hello" like "he*";
|
|
result2 := "HELLO" like "he*";
|
|
result3 := "test@example.com" like "*@*";
|
|
writeLn("result1:", result1);
|
|
writeLn("result2:", result2);
|
|
writeLn("result3:", result3);
|
|
```
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
result1: 1
|
|
result2: 0
|
|
result3: 1
|
|
```
|
|
|
|
说明:
|
|
|
|
- `like` 大小写敏感,`"hello" like "he*"` 返回 `1`(真),`"HELLO" like "he*"` 返回 `0`(假)
|
|
- `*` 是通配符,匹配任意字符序列
|
|
- `like` 也支持正则表达式模式(如 `"\\d{4}-\\d{2}-\\d{2}"` 匹配日期格式)
|
|
|
|
`not like` 是取反形式(TSL 2025/8 版本起支持):
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
result := "abc" not like "xyz*";
|
|
writeLn(result);
|
|
```
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
1
|
|
```
|
|
|
|
### `format` 格式化占位符
|
|
|
|
`format` 用于按占位符格式化输出:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
result := format("%d-%s", 7, "x");
|
|
writeLn(result);
|
|
```
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
7-x
|
|
```
|
|
|
|
说明:
|
|
|
|
- `%d` 是整数占位符
|
|
- `%s` 是字符串占位符
|
|
- `format` 的完整占位符规范使用 `tsl-api-reference` skill 按名查询。
|
|
|
|
### `formatdatetime` 日期格式化
|
|
|
|
`formatdatetime` 用于将日期按指定格式输出:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
dt := strtodate("2024-01-02");
|
|
result := formatdatetime("yyyy-mm-dd", dt);
|
|
writeLn(result);
|
|
```
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
2024-01-02
|
|
```
|
|
|
|
说明:
|
|
|
|
- `yyyy` 表示四位年份
|
|
- `mm` 表示两位月份
|
|
- `dd` 表示两位日期
|
|
- `formatdatetime` 的完整格式说明使用 `tsl-api-reference` skill 按名查询。
|
|
|
|
## 默认生成模板
|
|
|
|
如果你只是要抓住“基本类型 + array”的第一层,用这个最短例子:
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
count := 1;
|
|
price := 12.5;
|
|
name := "ABC";
|
|
flag := true;
|
|
items := array(1, 2, 3);
|
|
```
|
|
|
|
## 禁止项
|
|
|
|
- 用 `s[0]` 访问字符串首字符。
|
|
- 误以为 `array(...)` 只能写顺序数组,不能写字符串键表。
|
|
- 误以为字符串区间和数组一样从 `0` 开始。
|
|
- 把 `s[index:0] := ...` 误解成“替换到第 0 位”。
|
|
- 把二进制缓冲区也按字符串的 `1` 基下标去理解。
|
|
- 在普通字符串示例里默认切到原始字符串、宽串 / UTF8 前缀、字符码或编码转换,却没有按本页字符串边界规则确认。
|
|
- 把普通字符串里的 `\uXXXX` 直接当成宽串单字符。
|
|
- 把 `U""` 当成宽串;需要宽串时按本页转换链处理。
|
|
- 把 `#0` / `\0` 当成 C 风格字符串终止符。
|
|
|
|
代码块身份:反例 / 不可照写
|
|
|
|
```text
|
|
s := "ABC";
|
|
writeLn(s[0]);
|
|
```
|
|
|
|
上面这类写法在运行时会报字符串下标越界。
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
String index out of bounds
|
|
```
|
|
|
|
代码块身份:可直接照写示例
|
|
|
|
```tsl
|
|
s := "ABCDE";
|
|
writeLn(s[1:3]);
|
|
```
|
|
|
|
不要把上面这个区间访问类比成数组切片的半开区间。按文档输出,它返回 `ABC`,不是 `AB`;字符串区间的结束位会被包含进结果。
|
|
|
|
代码块身份:输出片段
|
|
|
|
```text
|
|
ABC
|
|
```
|