本文件是通用運算式語言 (CEL) 的統一 API 文件參考資料。這份清單列出所有巨集、運算子和標準函式,並指出其簽章、行為和支援狀態 (適用於官方 CEL 堆疊)。
如要進一步瞭解語言行為和規格,請參閱 CEL 語言定義。
堆疊版本
本參考文件是以下列版本的 CEL 堆疊為基礎:
- CEL Go:
v0.29.2(和更新版本) - CEL C++:
v0.15.0 - CEL Java:
v0.13.1 - CEL Python:
v0.1.3 - CEL C:開發快照 (未發布)
GitHub 鏡像
CEL 的正式實作項目會鏡像到 GitHub 的 cel-expr 機構下:
1. 核心巨集
這些是內建巨集,會在編譯時展開。
| 巨集 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
has(container.field) |
測試訊息中是否有欄位,或地圖中是否有鍵。 簽章: has(container.field) -> bool範例: has(request.auth.claims.email) |
✓ | ✓ | ✓ | ✓ | ✓ |
list.all(var, predicate) |
測試清單中的所有元素是否符合述詞。 簽章: list.all(var, predicate) -> bool範例: [1, 2, 3].all(x, x > 0) // true |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.exists(var, predicate) |
測試清單中是否至少有一個元素符合述詞。 簽章: list.exists(var, predicate) -> bool範例: [1, 2, 3].exists(x, x > 2) // true |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.exists_one(var, predicate) |
測試清單中是否只有一個項目符合述詞。 簽章: list.exists_one(var, predicate) -> bool範例: [1, 2, 3].exists_one(x, x == 2) // true |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.filter(var, predicate) |
根據述詞篩選清單元素。 簽章: list.filter(var, predicate) -> list範例: [1, 2, 3].filter(x, x > 1) // [2, 3] |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.map(var, transform) |
使用運算式轉換清單中的每個元素。 簽章: list.map(var, transform) -> list範例: [1, 2, 3].map(x, x * 2) // [2, 4, 6] |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.map(var, filter, transform) |
轉換符合篩選條件述詞的清單元素。 簽章: list.map(var, filter, transform) -> list範例: [1, 2, 3].map(x, x > 1, x * 2) // [4, 6] |
✓ | ✓ | ✓ | ✓ | ✓¹ |
¹ 由於巨集會在編譯期間由主機編譯器擴展為理解內容,因此 C 執行階段支援巨集。
2. 核心運算子
| 運算子 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
算術 (+、-、*、/、%) |
標準算術運算。否定 (-x) 和身分 (+x)。Go、C++、Java 和 Python 支援清單串連 (list + list)。簽章: T + T -> TT - T -> TT * T -> TT / T -> TT % T -> T-T -> T+T -> Tlist + list -> list範例: 1 + 2 * 3 // 7[1] + [2] // [1, 2] |
✓ | ✓ | ✓ | ✓ | ✓² |
比較 (==、!=、<、<=、>、>=) |
標準比較。數字比較是異質的 (例如 1 == 1.0)。簽章: T == T -> boolT != T -> boolT < T -> boolT <= T -> boolT > T -> boolT >= T -> bool範例: x < 42.01 == 1.0 // true |
✓ | ✓ | ✓ | ✓ | ✓ |
邏輯 (!、&&、||、? :) |
邏輯 NOT、AND、OR 和三元條件。AND/OR 使用短路求值。 簽章: !bool -> boolbool && bool -> boolbool || bool -> boolbool ? T : T -> T範例: x > 0 ? "positive" : "non-positive" |
✓ | ✓ | ✓ | ✓ | ✓ |
建立索引 ([]) |
依索引存取清單元素,或在對應中查閱索引鍵。 簽章: list[int] -> Tmap[K] -> V範例: tags[0]users['john'] |
✓ | ✓ | ✓ | ✓ | ✓ |
會員資格 (in) |
檢查元素是否位於清單中,或鍵是否位於對應中。 簽章: T in list -> boolK in map -> bool範例: 'admin' in roles |
✓ | ✓ | ✓ | ✓ | ✓ |
² C 執行階段不支援清單串連 (list + list),但支援其他算術運算子。
3. 核心功能
一般和字串函式
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
size |
傳回字串 (字元)、位元組、清單或對映的大小。 簽章: size(T) -> int (其中 T 為 string、bytes、list 或 map)<br /><br />**Examples:**<br />size("hello") // 5` |
✓ | ✓ | ✓ | ✓ | ✓ |
contains |
傳回字串是否包含子字串。 簽章: string.contains(string) -> bool範例: "hello".contains("ell") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
startsWith |
傳回字串是否以指定前置字元開頭。 簽章: string.startsWith(string) -> bool範例: "hello".startsWith("he") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
endsWith |
傳回字串是否以尾碼結尾。 簽章: string.endsWith(string) -> bool範例: "hello".endsWith("lo") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
matches |
傳回字串是否與 RE2 規則運算式相符。 簽章: string.matches(string) -> bool範例: "123".matches(r"^\d+$") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
日期和時間選取器函式
這些函式會從 google.protobuf.Timestamp 或 google.protobuf.Duration 擷取元件。
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
getFullYear |
傳回 4 位數的年份。 簽章: timestamp.getFullYear([tz]) -> int範例: timestamp("2026-07-23T00:00:00Z").getFullYear() // 2026 |
✓ | ✓ | ✓ | ✓ | ✗ |
getMonth |
傳回月份 (0 到 11)。 簽章: timestamp.getMonth([tz]) -> int範例: timestamp("2026-07-23T00:00:00Z").getMonth() // 6 |
✓ | ✓ | ✓ | ✓ | ✗ |
getDayOfMonth |
傳回當月日期 (1 到 31)。 簽章: timestamp.getDayOfMonth([tz]) -> int範例: timestamp("2026-07-23T00:00:00Z").getDayOfMonth() // 23 |
✓ | ✓ | ✓ | ✓ | ✗ |
getDayOfWeek |
傳回星期幾 (0 代表星期日)。 簽章: timestamp.getDayOfWeek([tz]) -> int範例: timestamp("2026-07-23T00:00:00Z").getDayOfWeek() // 4 |
✓ | ✓ | ✓ | ✓ | ✗ |
getDayOfYear |
傳回一年中的第幾天 (0 到 365)。 簽章: timestamp.getDayOfYear([tz]) -> int範例: timestamp("2026-07-23T00:00:00Z").getDayOfYear() // 203 |
✓ | ✓ | ✓ | ✓ | ✗ |
getHours |
傳回小時 (0 到 23)。 簽章: timestamp.getHours([tz]) -> intduration.getHours() -> int範例: duration("1h30m").getHours() // 1 |
✓ | ✓ | ✓ | ✓ | ✗ |
getMinutes |
傳回分鐘 (0 到 59)。 簽章: timestamp.getMinutes([tz]) -> intduration.getMinutes() -> int範例: duration("1h30m").getMinutes() // 30 |
✓ | ✓ | ✓ | ✓ | ✗ |
getSeconds |
傳回秒數 (0 到 59)。 簽章: timestamp.getSeconds([tz]) -> intduration.getSeconds() -> int範例: duration("1h30m45s").getSeconds() // 45 |
✓ | ✓ | ✓ | ✓ | ✗ |
getMilliseconds |
傳回毫秒 (0 到 999)。 簽章: timestamp.getMilliseconds([tz]) -> intduration.getMilliseconds() -> int範例: duration("1.5s").getMilliseconds() // 500 |
✓ | ✓ | ✓ | ✓ | ✗ |
類型轉換
| 目標類型 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
bool |
轉換為布林值。 簽章: bool(bool) -> boolbool(string) -> bool範例: bool("true") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
bytes |
轉換為位元組。 簽章: bytes(bytes) -> bytesbytes(string) -> bytes範例: bytes("hello") // b"hello" |
✓ | ✓ | ✓ | ✓ | ✓ |
double |
轉換為雙精度浮點數。 簽章: double(double) -> doubledouble(int) -> doubledouble(uint) -> doubledouble(string) -> double範例: double(1) // 1.0 |
✓ | ✓ | ✓ | ✓ | ✓ |
duration |
轉換為時間長度。 簽章: duration(duration) -> durationduration(string) -> duration範例: duration("1.5s") // 1.5s duration |
✓ | ✓ | ✓ | ✓ | ✓ |
int |
轉換為 64 位元帶正負號整數。 簽章: int(int) -> intint(uint) -> intint(double) -> int (四捨五入至零)int(string) -> intint(timestamp) -> int (自 Epoch 以來的秒數)範例: int(1.5) // 1 |
✓ | ✓ | ✓ | ✓ | ✓ |
string |
轉換為字串。 簽章: string(T) -> string (支援 bool、int、uint、double、bytes、timestamp、duration)<br /><br />**Examples:**<br />string(1.5) // "1.5"` |
✓ | ✓ | ✓ | ✓ | ✓ |
timestamp |
轉換為時間戳記。 簽章: timestamp(timestamp) -> timestamptimestamp(string) -> timestamp (RFC3339)範例: timestamp("2026-07-23T00:00:00Z") |
✓ | ✓ | ✓ | ✓ | ✓ |
uint |
轉換為 64 位元無正負號整數。 簽章: uint(uint) -> uintuint(int) -> uintuint(double) -> uintuint(string) -> uint範例: uint(1) // 1u |
✓ | ✓ | ✓ | ✓ | ✓ |
dyn |
將值轉換為動態型別,以進行型別檢查。 簽章: dyn(T) -> dyn範例: dyn([1, "two"]) |
✓ | ✓ | ✓ | ✓ | ✗ |
type |
傳回值的型別。 簽章: type(T) -> type範例: type(1) // int |
✓ | ✓ | ✓ | ✓ | ✗ |
4. 擴充功能 (程式庫)
繫結程式庫
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
cel.bind |
繫結本機變數,避免重複評估。 簽章: cel.bind(varName, initExpr, resultExpr) -> T範例: cel.bind(x, a + b, x * x) |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
如何啟用
- 前往:將
ext.Bindings()傳遞至cel.NewEnv()。 - C++:將
BindingsCompilerLibrary()新增至CompilerBuilder。(系統會自動處理執行階段)。 - Java:將
CelExtensions.bindings()新增至CelCompiler和CelRuntime建構工具。 - Python:匯入
cel_expr_python.ext.ext_bindings並在cel.NewEnv(extensions=[...])中使用ExtBindings()。
編碼器程式庫
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
base64.encode |
將位元組編碼為 base64 字串。 簽章: base64.encode(bytes) -> string範例: base64.encode(b"hello") // "aGVsbG8=" |
✓ (v0.6.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
base64.decode |
將 Base64 字串解碼為位元組。如果輸入內容無效,則會擲回錯誤。 簽章: base64.decode(string) -> bytes範例: base64.decode("aGVsbG8=") // b"hello" |
✓ (v0.6.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
json.encode |
將 CEL 值序列化為 JSON 字串。 簽章: json.encode(dyn) -> string範例: json.encode([1, 2]) // "[1,2]" |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
如何啟用
- 前往:將
ext.Encoders()傳遞至cel.NewEnv()。 - C++:
- 編譯器:將
EncodersCompilerLibrary()新增至CompilerBuilder。 - 執行階段:在
FunctionRegistry上呼叫RegisterEncodersFunctions()。
- 編譯器:將
- Java:將
CelExtensions.encoders()新增至CelCompiler和CelRuntime建構工具。 - Python:匯入
cel_expr_python.ext.ext_encoders並在cel.NewEnv(extensions=[...])中使用ExtEncoders()。
數學程式庫
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
math.greatest |
傳回數值引數 (或數值清單) 中最大的值。 簽章: math.greatest(arg, ...) -> T範例: math.greatest(1, 3, 2) // 3 |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
math.least |
傳回數值引數 (或數值清單) 中的最小值。 簽章: math.least(arg, ...) -> T範例: math.least([1, 3, 2]) // 1 |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
math.abs |
絕對值。 簽章: math.abs(T) -> T (支援 int、uint、double)<br /><br />**Examples:**<br />math.abs(-1) // 1` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.sqrt |
平方根。 簽章: math.sqrt(T) -> double (支援 int、uint、double)<br /><br />**Examples:**<br />math.sqrt(9) // 3.0` |
✓ (v0.25.1) | ✓ (v0.12.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
math.bitAnd |
位元 AND。 簽章: math.bitAnd(T, T) -> T (支援 int、uint)<br /><br />**Examples:**<br />math.bitAnd(5, 3) // 1` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitOr |
位元 OR。 簽章: math.bitOr(T, T) -> T (支援 int、uint)<br /><br />**Examples:**<br />math.bitOr(5, 3) // 7` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitXor |
位元互斥或。 簽章: math.bitXor(T, T) -> T (支援 int、uint)<br /><br />**Examples:**<br />math.bitXor(5, 3) // 6` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitNot |
位元 NOT。 簽章: math.bitNot(T) -> T (支援 int、uint)<br /><br />**Examples:**<br />math.bitNot(1) // -2` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitShiftLeft |
位元左移。 簽章: math.bitShiftLeft(T, int) -> T (支援 int、uint)<br /><br />**Examples:**<br />math.bitShiftLeft(1, 2) // 4` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitShiftRight |
向右移位。 簽章: math.bitShiftRight(T, int) -> T (支援 int、uint)<br /><br />**Examples:**<br />math.bitShiftRight(4, 2) // 1` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.ceil |
無條件進位。 簽章: math.ceil(double) -> double範例: math.ceil(1.2) // 2.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.floor |
向下捨入。 簽章: math.floor(double) -> double範例: math.floor(1.8) // 1.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.round |
四捨五入至最接近的整數。 簽章: math.round(double) -> double範例: math.round(1.5) // 2.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.trunc |
截斷捨去 (趨近於零)。 簽章: math.trunc(double) -> double範例: math.trunc(-1.8) // -1.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.isInf |
檢查 double 是否為正無限大或負無限大。 簽章: math.isInf(double) -> bool範例: math.isInf(1.0/0.0) // true |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.isNaN |
檢查 double 是否為 NaN。 簽章: math.isNaN(double) -> bool範例: math.isNaN(0.0/0.0) // true |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.isFinite |
檢查 double 是否為有限值。 簽章: math.isFinite(double) -> bool範例: math.isFinite(1.2) // true |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.sign |
傳回值的符號 (-1、0 或 1)。 簽章: math.sign(T) -> T (支援 int、uint、double)<br /><br />**Examples:**<br />math.sign(-42) // -1` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
如何啟用
- 前往:將
ext.Math()傳遞至cel.NewEnv()。 - C++:
- 編譯器:將
MathCompilerLibrary()新增至CompilerBuilder。 - 執行階段:在
FunctionRegistry上呼叫RegisterMathExtensionFunctions()。
- 編譯器:將
- Java:將
CelExtensions.math()新增至CelCompiler和CelRuntime建構工具。 - Python:匯入
cel_expr_python.ext.ext_math並在cel.NewEnv(extensions=[...])中使用ExtMath()。
Protos 程式庫
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
proto.getExt |
取得 proto2 擴充功能欄位,或未設定時的預設值。 簽章: proto.getExt(msg, extName) -> T範例: proto.getExt(msg, google.api.expr.test.int32_ext) |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
proto.hasExt |
檢查是否已設定 proto2 擴充功能欄位。 簽章: proto.hasExt(msg, extName) -> bool範例: proto.hasExt(msg, google.api.expr.test.int32_ext) |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
如何啟用
- 前往:將
ext.Protos()傳遞至cel.NewEnv()。 - C++:將
ProtoExtCompilerLibrary()新增至CompilerBuilder。 (系統會自動處理執行階段)。 - Java:將
CelExtensions.protos()新增至CelCompiler和CelRuntime建構工具。 - Python:匯入
cel_expr_python.ext.ext_proto並在cel.NewEnv(extensions=[...])中使用ExtProto()。
清單庫
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
distinct |
傳回不重複的元素。 簽章: list.distinct() -> list範例: [1, 2, 2].distinct() // [1, 2] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
flatten |
將巢狀清單扁平化。 簽章: list.flatten([depth]) -> list範例: [[1], [2, 3]].flatten() // [1, 2, 3] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.7.1) | ✓ (v0.1.1) | ✗ |
lists.range |
傳回整數清單 [0, ..., n-1]。簽章: lists.range(int) -> list(int)範例: lists.range(3) // [0, 1, 2] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
reverse |
反轉清單。 簽章: list.reverse() -> list範例: [1, 2].reverse() // [2, 1] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
slice |
傳回子清單 (包含開頭,但不包含結尾)。 簽章: list.slice(start, end) -> list範例: [1, 2, 3].slice(1, 3) // [2, 3] |
✓ (v0.17.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
sort |
排序可比較的元素清單。 簽章: list.sort() -> list範例: [3, 1, 2].sort() // [1, 2, 3] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
sortBy |
依據從運算式評估的鍵排序清單。 簽章: list.sortBy(var, expr) -> list範例: [{"val": 2}, {"val": 1}].sortBy(x, x.val) // [{"val": 1}, {"val": 2}] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
first |
傳回第一個元素 (選用)。需要選用擴充功能。 簽章: list.first() -> optional範例: [1, 2].first() // optional(1) |
✓ (v0.23.0) | ✓ (v0.15.0) | ✓ (v0.11.0) | ✓ (v0.1.2) | ✗ |
last |
傳回最後一個元素 (選用)。需要選用擴充功能。 簽章: list.last() -> optional範例: [1, 2].last() // optional(2) |
✓ (v0.23.0) | ✓ (v0.15.0) | ✓ (v0.11.0) | ✓ (v0.1.2) | ✗ |
如何啟用
- 前往:將
ext.Lists()傳遞至cel.NewEnv()。 - C++:
- 編譯器:將
ListsCompilerLibrary()新增至CompilerBuilder。 - 執行階段:在
FunctionRegistry上呼叫RegisterListsFunctions(),並在MacroRegistry上呼叫RegisterListsMacros()。
- 編譯器:將
- Java:將
CelExtensions.lists()新增至CelCompiler和CelRuntime建構工具。 - Python:透過
cel.EnvConfig啟用,方法是將lists新增至extensions清單。
集合庫
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
sets.contains |
檢查 list1 是否包含 list2 的所有元素。 簽章: sets.contains(list1, list2) -> bool範例: sets.contains([1, 2], [1]) // true |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.6.0) | ✓ (v0.1.1) | ✗ |
sets.equivalent |
檢查清單是否為集合等價 (包含相同的專屬元素)。 簽章: sets.equivalent(list1, list2) -> bool範例: sets.equivalent([1, 2], [2, 1, 1]) // true |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.6.0) | ✓ (v0.1.1) | ✗ |
sets.intersects |
檢查清單是否共用至少一個元素。 簽章: sets.intersects(list1, list2) -> bool範例: sets.intersects([1, 2], [2, 3]) // true |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.6.0) | ✓ (v0.1.1) | ✗ |
如何啟用
- 前往:將
ext.Sets()傳遞至cel.NewEnv()。 - C++:
- 編譯器:將
SetsCompilerLibrary()新增至CompilerBuilder。 - 執行階段:在
FunctionRegistry上呼叫RegisterSetsFunctions()。
- 編譯器:將
- Java:將
CelExtensions.sets()新增至CelCompiler和CelRuntime建構工具。 - Python:透過
cel.EnvConfig啟用,方法是將sets新增至extensions清單。
字串庫
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
charAt |
傳回索引處的字元。 簽章: string.charAt(int) -> string範例: "hello".charAt(1) // "e" |
✓ (第 0.4.0 版) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
indexOf |
傳回子字串第一次出現的索引,或 -1。 簽章: string.indexOf(substr, [start]) -> int範例: "hello".indexOf("l") // 2 |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
lastIndexOf |
傳回子字串最後一次出現的索引,或 -1。 簽章: string.lastIndexOf(substr, [end]) -> int範例: "hello".lastIndexOf("l") // 3 |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
join |
串連字串。 簽章: list(string).join([separator]) -> string範例: ["a", "b"].join("-") // "a-b" |
✓ (v0.10.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
split |
根據分隔符號分割字串。 簽章: string.split(separator, [limit]) -> list(string)範例: "a-b".split("-") // ["a", "b"] |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
substring |
傳回子字串 (包含開頭,但不包含結尾)。 簽章: string.substring(start, [end]) -> string範例: "hello".substring(1, 3) // "el" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
trim |
修剪 Unicode 空白字元。 簽章: string.trim() -> string範例: " hello ".trim() // "hello" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
replace |
將舊值替換為新值。 簽章: string.replace(old, new, [limit]) -> string範例: "hello".replace("l", "w") // "hewwo" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
reverse |
反轉 Unicode 碼點。 簽章: string.reverse() -> string範例: "abc".reverse() // "cba" |
✓ (v0.18.0) | ✓ (v0.14.0) | ✓ (v0.13.0) | ✓ (v0.1.1) | ✗ |
lowerAscii |
將 ASCII 字元轉換為小寫。 簽章: string.lowerAscii() -> string範例: "Hello".lowerAscii() // "hello" |
✓ (v0.6.0) | ✓ (v0.11.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
upperAscii |
將 ASCII 字元轉換為大寫。 簽章: string.upperAscii() -> string範例: "Hello".upperAscii() // "HELLO" |
✓ (v0.6.0) | ✓ (v0.11.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
quote |
逸出字串,確保列印安全。 簽章: strings.quote(string) -> string範例: strings.quote("a\tb") // "\"a\\tb\"" |
✓ (v0.14.0) | ✓ (v0.14.0) | ✓ (v0.13.0) | ✓ (v0.1.1) | ✗ |
如何啟用
- 前往:將
ext.Strings()傳遞至cel.NewEnv()。 - C++:
- 編譯器:將
StringsCompilerLibrary()新增至CompilerBuilder。 - 執行階段:在
FunctionRegistry上呼叫RegisterStringsFunctions()。
- 編譯器:將
- Java:將
CelExtensions.strings()新增至CelCompiler和CelRuntime建構工具。 - Python:匯入
cel_expr_python.ext.ext_strings並在cel.NewEnv(extensions=[...])中使用ExtStrings()。
規則運算式程式庫
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
regex.replace |
以替換字串取代相符項目 (支援反向參照)。 簽章: regex.replace(target, pat, repl, [limit]) -> string範例: regex.replace("123-456", r"(\d+)-(\d+)", r"\2-\1") // "456-123" |
✓ (v0.25.1) | ✓ (v0.13.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
regex.extract |
傳回模式的第一個相符項目 (必須有一個擷取群組)。 簽章: regex.extract(target, pat) -> optional(string)範例: regex.extract("a123b", r"(\d+)") // optional("123") |
✓ (v0.25.1) | ✓ (v0.13.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
regex.extractAll |
傳回模式的所有相符項目 (必須有一個擷取群組)。 簽章: regex.extractAll(target, pat) -> list(string)範例: regex.extractAll("a1b2", r"(\d+)") // ["1", "2"] |
✓ (v0.25.1) | ✓ (v0.13.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
如何啟用
- 前往:將
ext.Regex()傳遞至cel.NewEnv()。 - C++:
- 編譯器:將
RegexExtCompilerLibrary()新增至CompilerBuilder。 - 執行階段:在
FunctionRegistry上呼叫RegisterRegexExtensionFunctions()。
- 編譯器:將
- Java:將
CelExtensions.regex()新增至CelCompiler和CelRuntime建構工具。 - Python:透過
cel.EnvConfig啟用,方法是在extensions清單中加入regex和optional。
雙變數理解
| 巨集 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
all |
針對鍵/索引和值進行短路邏輯 AND 運算。 簽章: list.all(i, v, pred) -> boolmap.all(k, v, pred) -> bool範例: [1, 2].all(i, v, v > 0) // true |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
exists |
針對鍵/索引和值,進行邏輯 OR 短路。 簽章: list.exists(i, v, pred) -> boolmap.exists(k, v, pred) -> bool範例: [1, 2].exists(i, v, v == 2) // true |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
existsOne |
檢查是否剛好有一對滿足述詞。 簽章: list.existsOne(i, v, pred) -> boolmap.existsOne(k, v, pred) -> bool範例: [1, 2].existsOne(i, v, v == 2) // true |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
transformList |
將清單/對照表轉換/篩選為清單。 簽章: list.transformList(i, v, [filter], transform) -> listmap.transformList(k, v, [filter], transform) -> list範例: [1, 2].transformList(i, v, v * 2) // [2, 4] |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
transformMap |
將清單/對應值轉換為對應 (索引鍵保持固定)。 簽章: list.transformMap(i, v, [filter], transform) -> mapmap.transformMap(k, v, [filter], transform) -> map範例: [1, 2].transformMap(i, v, v * 2) // {0: 2, 1: 4} |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
transformMapEntry |
轉換為地圖。 簽章: list.transformMapEntry(i, v, [filter], transform_entry) -> mapmap.transformMapEntry(k, v, [filter], transform_entry) -> map範例: [1, 2].transformMapEntry(i, v, {string(v): v * 2}) // {"1": 2, "2": 4} |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
如何啟用
- 前往:將
ext.TwoVarComprehensions()傳遞至cel.NewEnv()。 - C++:
- 編譯器:將
ComprehensionsV2CompilerLibrary()新增至CompilerBuilder。 - 執行階段:在
FunctionRegistry上呼叫RegisterComprehensionsV2Functions(),並在MacroRegistry上呼叫RegisterComprehensionsV2Macros()。
- 編譯器:將
- Java:將
CelExtensions.comprehensions()新增至CelCompiler和CelRuntime建構工具。 - Python:透過
cel.EnvConfig啟用,方法是將two-var-comprehensions新增至extensions清單。
原生型別程式庫
| 功能 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
| 原生結構體 | 在 CEL 中註冊及例項化主機原生型別 (Go 結構體 / Java POJO)。 範例: Account{id: 123} (在 CEL 中例項化的 Java POJO) |
✓ (v0.13.0) | ✗ | ✓ (v0.13.0) | ✗ | ✗ |
如何啟用
- 前往:傳遞
ext.NativeTypes(...)(提供反映型別) 至cel.NewEnv()。 - C++:不支援。
- Java:將
CelExtensions.nativeTypes()(提供 Java 類別) 新增至CelCompiler和CelRuntime建構工具。 - Python:不支援。
網路程式庫
Network 程式庫提供函式,可剖析、驗證及操控 IP 位址和 CIDR 區塊。
| 函式 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
ip |
將字串剖析為 IP 位址,或從 CIDR 擷取 IP。 簽章: ip(string) -> IPCIDR.ip() -> IP範例: ip("192.168.0.1")cidr("192.168.0.0/24").ip() |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isIP |
檢查字串是否為有效的 IP 位址。 簽章: isIP(string) -> bool範例: isIP("192.168.0.1") // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
ip.isCanonical |
檢查 IP 位址字串是否為標準格式。 簽章: ip.isCanonical(string) -> bool範例: ip.isCanonical("192.168.0.1") // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
cidr |
將字串剖析為 CIDR 區塊。 簽章: cidr(string) -> CIDR範例: cidr("192.168.0.0/24") |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isCIDR |
檢查字串是否為有效的 CIDR 區塊。 簽章: isCIDR(string) -> bool範例: isCIDR("192.168.0.0/24") // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
containsIP |
檢查 CIDR 區塊是否包含 IP 位址。 簽章: CIDR.containsIP(IP) -> boolCIDR.containsIP(string) -> bool範例: cidr("192.168.0.0/24").containsIP(ip("192.168.0.1")) // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
containsCIDR |
檢查 CIDR 區塊是否包含另一個 CIDR 區塊。 簽章: CIDR.containsCIDR(CIDR) -> boolCIDR.containsCIDR(string) -> bool範例: cidr("192.168.0.0/16").containsCIDR(cidr("192.168.1.0/24")) // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
family |
傳回 IP 系列 (IPv4 為 4,IPv6 為 6)。 簽章: IP.family() -> int示例: ip("192.168.0.1").family() // 4 |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isGlobalUnicast |
檢查 IP 是否為全域單點播送位址。 簽章: IP.isGlobalUnicast() -> bool範例: ip("192.168.0.1").isGlobalUnicast() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isLinkLocalMulticast |
檢查 IP 是否為連結本機多點播送位址。 簽章: IP.isLinkLocalMulticast() -> bool範例: ip("224.0.0.1").isLinkLocalMulticast() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isLinkLocalUnicast |
檢查 IP 是否為連結本機單點播送位址。 簽章: IP.isLinkLocalUnicast() -> bool範例: ip("169.254.0.1").isLinkLocalUnicast() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isLoopback |
檢查 IP 是否為迴路位址。 簽章: IP.isLoopback() -> bool示例: ip("127.0.0.1").isLoopback() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isMask |
檢查 CIDR 是否為有效的子網路遮罩。 簽章: CIDR.isMask() -> bool範例: cidr("255.255.255.0/24").isMask() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isUnspecified |
檢查 IP 是否為未指定的位址 (例如 0.0.0.0)。簽章: IP.isUnspecified() -> bool範例: ip("0.0.0.0").isUnspecified() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
masked |
傳回遮罩 CIDR 區塊。 簽章: CIDR.masked() -> CIDR範例: cidr("192.168.0.1/24").masked() // 192.168.0.0/24 |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
prefixLength |
傳回 CIDR 區塊的前置字串長度。 簽章: CIDR.prefixLength() -> int範例: cidr("192.168.0.0/24").prefixLength() // 24 |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
string |
將 IP 或 CIDR 轉換為字串。 簽章: string(IP) -> stringstring(CIDR) -> string範例: string(ip("192.168.0.1")) // "192.168.0.1" |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
如何啟用
- 前往:將
ext.Network()傳遞至cel.NewEnv()。 - C++:不支援。
- Java:不支援。
- Python:不支援。
5. 進階功能
進階功能摘要
| 功能 | 說明 | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
| 部分評估 | 評估缺少輸入內容的運算式,並傳回不明值或簡化運算式。 | ✓³ | ✓⁴ | ✓⁴ | ✗ | ✗ |
| 非同步評估 | 以非封鎖方式並行執行擴充功能函式。 | ✓⁵ | ✗ | ✓⁶ | ✗ | ✗ |
| AST 驗證工具 | 在型別檢查後,對檢查過的 AST 執行靜態分析檢查。 | ✓ | ✓ | ✓ | ✗ | ✗ |
| AST 最佳化工具 | AST 重寫 (常數摺疊、內嵌、CSE),以提升效能。 | ✓ | ✓ | ✓ | ✗ | ✗ |
| CEL 政策編譯器 | 將以 YAML 為基礎的政策結構編譯為標準 CEL AST。 | ✓ | ✓ | ✓ | ✗ | ✗ |
³ Go 支援產生剩餘 AST (修剪後的 AST)。⁴ C++ 和 Java 支援在執行階段傳回 UnknownSet / CelUnknownSet,但不公開用於產生剩餘 AST 的 API。⁵ Go 會使用 AsyncBinding / AsyncOp 傳回管道。⁶ Java 會使用回傳 ListenableFuture 的 CelAsyncRuntime。
部分評估 (不明)
如果只知道部分輸入變數 (引數),即可使用部分評估功能評估運算式。評估作業不會失敗,而是會產生結果,指出缺少什麼內容或簡化運算式。
- 前往:完整支援。可定義具有未知屬性模式的
PartialActivation。評估會傳回types.Unknown值。Go 支援產生剩餘 AST (Env.ResidualAst),這是經過修剪的簡化 AST,只包含無法評估的運算式部分。 - C++:支援
Unknown值。不明屬性模式是透過Activation::set_unknown_attribute_patterns設定。評估 會傳回UnknownSet。公用 API 目前不會公開剩餘的 AST 生成量。 - Java:支援透過傳遞至
Program.eval()的PartialVars進行部分評估。評估會傳回CelUnknownSet。公用 API 目前不會公開剩餘的 AST 生成作業。 - Python / C:不支援原生功能。
非同步評估
非同步評估功能可讓 CEL 運算式呼叫非同步執行的函式 (例如發出 RPC 或資料庫查詢),並封鎖評估作業,直到結果可用為止,但不會封鎖主要執行緒。
- Go:透過
AsyncBinding和AsyncOp支援非同步函式多載。非同步函式會傳回 Go 管道 (<-chan ref.Val),而解譯器會管理並行執行和同步處理。 - Java:透過
CelAsyncRuntime和AsyncProgram支援非同步評估。它會使用ListenableFuture代表待處理的值,並在 Future 解決時自動完成評估。 - C++ / Python / C:不支援內建功能。
AST 驗證工具
驗證器會在型別檢查後對 Checked AST 執行靜態分析,以強制執行網域專屬限制,然後再執行程式。
- Go:支援
ASTValidator介面。標準驗證器包括cel.validator.duration、cel.validator.timestamp、cel.validator.matches(規則運算式)、cel.validator.homogeneous_literals和cel.validator.comprehension_nesting_limit。 - C++:支援
cel::Validator。標準驗證包括AstDepthValidator、ComprehensionNestingLimitValidator、DurationLiteralValidator、HomogeneousLiteralValidator、MatchesValidator和TimestampLiteralValidator。 - Java:支援
CelValidator和CelAstValidator。標準驗證器包括AstDepthLimitValidator、ComprehensionNestingLimitValidator、DurationLiteralValidator、HomogeneousLiteralValidator、RegexLiteralValidator和TimestampLiteralValidator。 - Python / C:不直接支援。
AST Optimizers
最佳化工具會重新編寫 AST,以提升執行效能。最佳化工具可分為兩類:靜態和執行階段最佳化工具。C++、Java 和 Go 支援執行階段最佳化。CEL Java 和 Go 也支援靜態最佳化工具。 常見的最佳化包括常數摺疊 (使用常數輸入預先評估子運算式) 和常見子運算式消除 (CSE)。
- Go:在編譯/規劃期間支援 AST 折疊。
- C++:在規劃期間,透過
cel::extensions::EnableConstantFolding擴充功能支援常數摺疊。 - Java:支援
CelOptimizer介面。標準最佳化工具包括ConstantFoldingOptimizer(可透過模擬部分評估來摺疊短路分支)、InliningOptimizer和SubexpressionOptimizer(CSE)。 - Python / C:不直接支援。
CEL 政策編譯器
CEL 政策是以 YAML 為基礎的格式,可將多個 CEL 運算式與變數、比對區塊、條件式輸出內容和巢狀規則組合在一起。這項功能適用於複雜的政策引擎 (例如 Kubernetes 准入控制),因為單一 CEL 運算式會變得難以解讀。
政策編譯器會將這些 YAML 政策編譯為單一標準 CEL AST,代表這些政策完全相容於標準 CEL 執行階段,並會繼承所有效能和安全保障。
- 前往:支援頁面 (透過
third_party/cel/go/policy)。 - C++:透過
third_party/cel/cpp/policy支援。 - Java:透過
third_party/java/cel/policy支援。 - Python / C:不直接支援。