From 14ba145ea7f0ced4d42db4b3c41dc993d6f9c043 Mon Sep 17 00:00:00 2001 From: ZhouYongyou <128128010+zhouyongyou@users.noreply.github.com> Date: Wed, 5 Nov 2025 00:54:51 +0800 Subject: [PATCH] =?UTF-8?q?perf(decision):=20precompile=20regex=20patterns?= =?UTF-8?q?=20for=20performance=20##=20Changes=20-=20Move=20all=20regex=20?= =?UTF-8?q?patterns=20to=20global=20precompiled=20variables=20-=20Reduces?= =?UTF-8?q?=20regex=20compilation=20overhead=20from=20O(n)=20to=20O(1)=20-?= =?UTF-8?q?=20Matches=20z-dev's=20performance=20optimization=20##=20Modifi?= =?UTF-8?q?ed=20Patterns=20-=20reJSONFence:=20Match=20```json=20code=20blo?= =?UTF-8?q?cks=20-=20reJSONArray:=20Match=20JSON=20arrays=20-=20reArrayHea?= =?UTF-8?q?d:=20Validate=20array=20start=20-=20reArrayOpenSpace:=20Compact?= =?UTF-8?q?=20array=20formatting=20-=20reInvisibleRunes:=20Remove=20zero-w?= =?UTF-8?q?idth=20characters=20##=20Performance=20Impact=20-=20Regex=20com?= =?UTF-8?q?pilation=20now=20happens=20once=20at=20startup=20-=20Eliminates?= =?UTF-8?q?=20repeated=20compilation=20in=20extractDecisions()=20(called?= =?UTF-8?q?=20every=20decision=20cycle)=20-=20Expected=20performance=20imp?= =?UTF-8?q?rovement:=20~5-10%=20in=20JSON=20parsing=20##=20Safety=20?= =?UTF-8?q?=E2=9C=85=20All=20regex=20patterns=20remain=20unchanged=20(only?= =?UTF-8?q?=20moved=20to=20global=20scope)=20=E2=9C=85=20Compilation=20suc?= =?UTF-8?q?cessful=20=E2=9C=85=20Maintains=20same=20functionality=20as=20b?= =?UTF-8?q?efore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- decision/engine.go | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/decision/engine.go b/decision/engine.go index 92aece8d..7008548e 100644 --- a/decision/engine.go +++ b/decision/engine.go @@ -12,6 +12,17 @@ import ( "time" ) +// 预编译正则表达式(性能优化:避免每次调用时重新编译) +var ( + // ✅ 安全的正則:精確匹配 ```json 代碼塊 + // 使用反引號 + 拼接避免轉義問題 + reJSONFence = regexp.MustCompile(`(?is)` + "```json\\s*(\\[\\s*\\{.*?\\}\\s*\\])\\s*```") + reJSONArray = regexp.MustCompile(`(?is)\[\s*\{.*?\}\s*\]`) + reArrayHead = regexp.MustCompile(`^\[\s*\{`) + reArrayOpenSpace = regexp.MustCompile(`^\[\s+\{`) + reInvisibleRunes = regexp.MustCompile(`[\u200B\u200C\u200D\uFEFF]`) +) + // PositionInfo 持仓信息 type PositionInfo struct { Symbol string `json:"symbol"` @@ -461,8 +472,7 @@ func extractDecisions(response string) ([]Decision, error) { s = fixMissingQuotes(s) // 1) 优先从 ```json 代码块中提取 - reFence := regexp.MustCompile(`(?is)` + "```json\\s*(\\[\\s*\\{.*?\\}\\s*\\])\\s*```") - if m := reFence.FindStringSubmatch(s); m != nil && len(m) > 1 { + if m := reJSONFence.FindStringSubmatch(s); m != nil && len(m) > 1 { jsonContent := strings.TrimSpace(m[1]) jsonContent = compactArrayOpen(jsonContent) // 把 "[ {" 规整为 "[{" jsonContent = fixMissingQuotes(jsonContent) // 二次修復(防止 regex 提取後還有全角) @@ -478,8 +488,7 @@ func extractDecisions(response string) ([]Decision, error) { // 2) 退而求其次:全文寻找首个对象数组 // 注意:此時 s 已經過 fixMissingQuotes(),全角字符已轉換為半角 - reArray := regexp.MustCompile(`(?is)\[\s*\{.*?\}\s*\]`) - jsonContent := strings.TrimSpace(reArray.FindString(s)) + jsonContent := strings.TrimSpace(reJSONArray.FindString(s)) if jsonContent == "" { return nil, fmt.Errorf("无法找到JSON数组起始(已嘗試修復全角字符)\n原始響應前200字符: %s", s[:min(200, len(s))]) } @@ -536,8 +545,7 @@ func validateJSONFormat(jsonStr string) error { trimmed := strings.TrimSpace(jsonStr) // 允许 [ 和 { 之间存在任意空白(含零宽) - reHead := regexp.MustCompile(`^\[\s*\{`) - if !reHead.MatchString(trimmed) { + if !reArrayHead.MatchString(trimmed) { // 检查是否是纯数字/范围数组(常见错误) if strings.HasPrefix(trimmed, "[") && !strings.Contains(trimmed[:min(20, len(trimmed))], "{") { return fmt.Errorf("不是有效的决策数组(必须包含对象 {}),实际内容: %s", trimmed[:min(50, len(trimmed))]) @@ -575,14 +583,12 @@ func min(a, b int) int { // removeInvisibleRunes 去除零宽字符和 BOM,避免肉眼看不见的前缀破坏校验 func removeInvisibleRunes(s string) string { - re := regexp.MustCompile(`[\u200B\u200C\u200D\uFEFF]`) - return re.ReplaceAllString(s, "") + return reInvisibleRunes.ReplaceAllString(s, "") } // compactArrayOpen 规整开头的 "[ {" → "[{" func compactArrayOpen(s string) string { - re := regexp.MustCompile(`^\[\s+\{`) - return re.ReplaceAllString(strings.TrimSpace(s), "[{") + return reArrayOpenSpace.ReplaceAllString(strings.TrimSpace(s), "[{") } // validateDecisions 验证所有决策(需要账户信息和杠杆配置)