跳到主要内容

表达式与函数

凡是流程需要"算"而不只是"存"的地方——If 的条件、Loop 的上界、边上的条件、Variable 的赋值、Input Text 要敲出的文字——干活的都是同一门小语言。本页是它的参考。

它小得很刻意。没有循环,没有赋值,没有任何通往文件系统或网络的路。一个表达式读若干值,返回一个值。

引用一个值

{{gem_count}} 变量 gem_count
${gem_count} 完全相同——两种写法都接受
vars.gem_count 同一个变量的完整写法
result.output.text 上游节点的输出

值从哪来,见变量

运算符

优先级从高到低——就是解析器的处理顺序:

层级运算符说明
取用. [ ]属性与下标:split(x, ",")[0]
一元! -取反、取负
乘除* / %
加减+ -
比较< <= > >=
相等== !=
空合并??取左边,除非它是 null
&&短路
||短路

括号按你想的那样分组。

算术是严格类型的,这是有意的

+ 拼接两个字符串,也相加两个数。它拒绝混合的一对——"5" + 1 直接报错,而不去猜你想要哪个。布尔值永远不是操作数。除以零报错。

这不是疏漏。放松 + 会悄悄改变每一个已发布流程的计算结果,所以类型转换是一个你能在表达式里看见的函数——number()text()int()——绝不是隐式强制转换。Variable 节点的意图行会替你写出这些调用:选"给计数器加 1",你就得到一次正确的转换,一个字都不用写。

函数

29 个名字,下面全部列出。每一个都是全函数——只要还能回答,它就回答而不是抛错——而且除 random 外每一个都是确定性的,所以条件重放的结果完全一致。

文本谓词把 null 当作空字符串,所以哪怕上面的检测什么都没读到,contains(result.output.text, "Start") 依然安全:你拿到 false,而不是一次死掉的运行。

判断文本

函数返回
contains(text, part)part 是否出现在 text
not_contains(text, part)相反
starts_with(text, part)
ends_with(text, part)
equals_ignore_case(a, b)忽略大小写的相等
is_empty(value)空字符串、空数组、空对象,或 null
is_not_empty(value)相反
regex_match(text, pattern)该模式是否能在 text 中找到

加工文本

函数返回
lower(text) / upper(text)大小写转换
trim(text)去掉首尾空白
concat(a, b, …)把每个参数当文本拼起来——+ 拒绝做的混合类型拼接
replace(text, find, replacement)每一处字面出现。 不是正则。find 为空则原样返回
split(text, separator)各个部分,是数组——可以取下标:split(x, ",")[0]。分隔符为空则报错
substring(text, start)start 到末尾。负的 start 从末尾往回数
substring(text, start, length)最多 length 个字符
extract(text, pattern)第一个捕获组,模式没有捕获组时则是整个匹配——没匹配上时是 null
extract(text, pattern, group)指定的组
default(value, fallback)valuenull 或为空时取 fallback
len(value) / length(value)字符数、数组长度或对象大小。null0

substring 是夹取而不是报错。 起点超出末尾就给 ""。OCR 读回来比平时短是再普通不过的一天,不构成杀掉一次运行的理由。

extract 没匹配上返回 null,正是这一点让它可组合:extract({{ocr}}, "[0-9]+") ?? "0"

default?? 更宽。 ?? 只覆盖 nulldefault() 还覆盖空字符串——那才是一次失败读取的日常形状。

数字

函数返回
number(value)数值——不是数就报错
number(value, fallback)……或者用回退值而不报错
text(value)值的文本形式
is_number(value)number() 会不会成功
int(value)向零截断——int(-2.7)-2
round(value) / round(value, digits)逢五远离零进位
floor(value) / ceil(value)
abs(value)
min(a, b, …) / max(a, b, …)
clamp(value, low, high)夹在界内。low > high 时报错
random(low, high)[low, high] 内的整数,两端都含
number() 不猜分隔符

"1,234" 是真的有歧义——逗号在英语里是千分位,在越南语里是小数点number() 只接受朴素的数字字面量。要去掉分隔符,请自己 replace(),好让语言习惯这个决定显式写在流程里,而不是被流程替你假定。

round 对你写下的那个数取整。 round(1.005, 2)1.01。对二进制近似值取整会得到 1.0——理论上说得通,在支持工单里根本解释不清。

random 是唯一不确定的函数,而这正是它的全部用途:一个永远用同一个上限的流程,每次跑起来一模一样。它在每次求值时重新抽取——没有任何地方缓存它。两个界限顺序随便写,并且会向内取整,所以小数参数绝不会扩大范围。

random(1, 100) <= 20 五次里有一次

旧写法

老流程以及 no-code 构建器编译出来的东西可能用 camelCase:notContainsstartsWithendsWithequalsIgnoreCaseisEmptyisNotEmpty。它们仍然有效,与 snake_case 版本完全等价。新写的东西请用 snake_case。

实战写法

从有噪声的 OCR 结果里读出一个数。

number(extract({{ocr_text}}, "[0-9]+") ?? "0")

extract"LEVEL 5" 里拽出数字,?? 在读空时给一个值,number 让它变得可以参与运算。没有那个回退值,一次空读就会抛错。

从一大段剪贴板文本里取第 n 条记录的第 n 个字段。

split({{noidung}}, "\n")[{{i}} * 5 + 1]

这是桌面数据录入示例的核心:一次 Ctrl+C 把整个文件取回成文本,一个 Loop 计数器每五行走一步。

永远不越界的百分比。

clamp(round({{done}} / {{total}} * 100), 0, 100)

常见错误

错误后果修复
对 OCR 结果写 {{ocr}} + 1报错——字符串加数字number({{ocr}}, 0) + 1
"1,234"number()报错number(replace({{x}}, ",", ""))
replace() 当正则用什么都匹配不上——它是字面的要模式请用 extract()
对空字符串用 ???? 只覆盖 nulldefault(value, fallback)
以为 extract 返回 ""它返回 null后面接 ??default()
在期望可重放的条件里用 random它每次求值都重新抽先存进变量

相关页面