前言¶
智能體處理日誌、校驗用戶給的 pattern、從一段文本里抽出字段,正則幾乎是默認手段。問題是:模型「心算」正則的錯誤率很高,也沒法把中間結果交給人覈對。常見替代是讓模型現寫一段 node -e 或 Python,再通過 bash 跑——多一次進程開銷,也多一層現寫腳本的正確性風險。
DeepSeek Harness(dsh)內置的 grep 只能做文件域搜索,不能對任意字符串做測試、提取、替換,更不能解釋一段 pattern 到底在匹配什麼。社區插件 dsh-tool-regex 就是爲這件事準備的:給當前 dsh 進程註冊一個 regex 工具,用確定性的純函數結果代替心算。
本文按插件目錄頁、GitHub 倉庫 README 與源碼交叉覈對後整理:它是什麼、四個 action 怎麼用、怎麼安裝,以及 ReDoS 相關的邊界。
這是什麼¶
dsh-tool-regex 是一款面向 DeepSeek Harness 的工具與能力插件,由 GitHub 組織 omdsh-dev 維護,倉庫地址是 omdsh-dev/dsh-tool-regex。目錄頁收錄日期爲 2026-08-14,許可證 MIT,主要語言 TypeScript。截至本文查閱時,倉庫星標爲 3。
它解決的是這一類任務:
- 判斷一段文本是否匹配給定 pattern
- 從日誌或任意字符串中提取編號捕獲組、命名捕獲組
- 做帶
$1/$2/$$語義的安全替換 - 在不執行匹配的前提下,把 pattern 拆成人能讀的解釋節點
插件以 Profile Bundle 形式接入。package.json 裏包名聲明爲 @deepseek-ai/dsh-tool-regex,安裝後會在 profile 的 layer stack 插入 row id tool-regex。這是社區開源插件,不是 DeepSeek / 幻方的官方應用;DeepSeek Harness 本身的設計原則是「一切皆插件」,社區目錄 deepseek-harness-plugin.com 是獨立站點,與官方倉庫無從屬關係。
運行時沒有第三方依賴:package.json 沒有 dependencies 字段,peer 依賴由 profile 提供(@deepseek-ai/cordis、@deepseek-ai/dsh-tools、@deepseek-ai/dsh-invariants)。引擎側是純函數;test / find / replace 會再進 worker 線程執行。
核心功能¶
插件只註冊一個工具:regex。調用時用 action 區分四類操作,統一返回 JSON 文本字符串。
四個 action¶
| action | 做什麼 | 輸出形態 |
|---|---|---|
test |
判斷是否匹配 | {"matched":true} 或 {"matched":false} |
find |
收集全部匹配:下標、完整匹配、編號組 captures、命名組 groups |
數組;零匹配返回 [] |
replace |
全局安全替換,返回結果文本和替換次數 | {"result":"...","replaced":1} |
explain |
靜態解析 pattern,輸出人讀節點序列 | 節點數組,例如 {"kind":"escape","text":"\\d","meaning":"A digit [0-9]"} |
幾點行爲需要單獨記住:
test不會自動加首尾錨點。整串匹配要由模型自己寫成^...$。find和replace在沒有g時會自動補g,否則只能拿到第一處匹配。explain是差異化能力:只做線性 tokenizer,不構造RegExp實例、不執行匹配,因此天然免疫 ReDoS。節點上限 4,096,超限返回regex: explain: pattern too complex。
README 裏的三個可復現例子如下。
提取捕獲組:
regex { action: "find", pattern: "(\\w+)@(\\w+)", input: "a@b x c@d" }
返回兩處匹配,第一處大致是 {"index":0,"match":"a@b","captures":["a","b"],"groups":null},第二處從下標 6 開始,對應 c@d。
交換兩個單詞:
regex { action: "replace", pattern: "(\\w+) (\\w+)", input: "hello world", replacement: "$2 $1" }
得到 {"result":"world hello","replaced":1}。
解釋一段日期片段:
regex { action: "explain", pattern: "\\d{4}-\\d{2}" }
會拆成轉義 \d、量詞 {4}、字面量 - 等節點,並帶上英文 meaning 字段。
工具參數¶
| 參數 | 必填 | 說明 |
|---|---|---|
action |
是 | test / find / replace / explain |
pattern |
是 | JavaScript 正則語法,不要帶外圍 /;上限 16KB |
input |
test/find/replace 必需 |
待匹配文本;上限 64,000 字節(UTF-8) |
flags |
否 | 如 "gi";允許 g i m s u y d v,必須唯一且合法 |
replacement |
replace 時需要 |
替換文本,走 JS 原生字符串替換路徑;上限 16KB |
limit |
否 | find 最多報告多少處匹配,默認 50,鉗制到 1,000 |
flags 是逐字符校驗的:非法字符報 regex: invalid flag "q",重複報 regex: duplicate flag "g"。無效 pattern 捕獲 SyntaxError,錯誤信息裏通常帶位置,格式爲 regex: invalid pattern: ...,不會把宿主打崩。
replace 明確走 String.prototype.replace 的字符串替換路徑,沒有 new Function,也沒有 eval。$1 / $2 是編號組,$$ 是字面量 $,命名組走 JS 原生 $<name> 語義;未知引用按 V8 規則字面保留(例如 $0)。
ReDoS 多層防線¶
JS 正則的災難性回溯是真實威脅,典型例子是 (a+)+$ 配超長輸入。倉庫 README 和工具描述都寫了同一套防線,源碼 src/index.ts、src/engine.ts 與之對應:
- worker 硬超時:
test/find/replace在可終止的 worker 線程裏同步執行,預算 1,000ms,到期調用worker.terminate(),返回regex: execution timed out (1000ms)。工具管道自己的timeoutMs對同步阻塞體只是協作式的,單靠它不夠,所以才單獨開 worker。 - 入口拒絕,不截斷:輸入超過 64KB、pattern 超過 16KB、replacement 超過 16KB,直接報錯,不進入回溯。
- 輸出與匹配數上限:輸出超過 1MB(例如
$`` /$’造成的替換放大)拒絕而非截斷;find的limit` 默認 50、上限 1,000。 explain零執行:只做靜態掃描,任何 pattern 都即時返回。
工具描述和 README 都警告模型:不要對不可信的大輸入使用無錨點的嵌套量詞,例如 (a+)+、(.*)*。超時能擋住宿主被掛死,但不能把病理 pattern 變成「安全可用」。
安裝與啓用¶
目錄頁給出的安裝命令是(以頁面原文爲準):
dsh plugin add github:omdsh-dev/dsh-tool-regex
需要可復現安裝時,固定 commit 哈希:
dsh plugin add github:omdsh-dev/dsh-tool-regex#commit
把 #commit 換成實際哈希。倉庫 main 在 2026-08-14 的最新提交是 457c84fed7849003dd006145fe7838519c8fc132。固定哈希之後,上游再推送不會悄悄改變你機器上跑的代碼。
README 推薦按 profile 安裝。web(交互式網頁)和 headless(dsh run 默認)是兩套不同的 profile,裝到一邊不會自動覆蓋另一邊:
# 交互式(web)profile
dsh plugin --profile web add github:omdsh-dev/dsh-tool-regex
# 一次性任務(headless)profile
dsh plugin --profile headless add github:omdsh-dev/dsh-tool-regex
也可以先在倉庫裏 npm pack,再用生成的 tarball 安裝:
npm pack
dsh plugin --profile web add ./dsh-tool-regex-<version>.tgz
包內 cordis.patch.yml 會在安裝後把插件插入 layer stack,row id 爲 tool-regex。缺失的 peer 依賴由 profile 的 profiles/node_modules 回退安裝提供。Windows 路徑請用正斜槓,例如 C:/...。
package.json 聲明的 Node 引擎是 ^22.19.0 || >=24.0.0。README 寫明本插件已按 @deepseek-ai/dsh@0.1.0-rc.6(npm 私有包)做過隔離消費驗證,啓動方式示例爲 npx -p @deepseek-ai/dsh@0.1.0-rc.6 dsh web,並明確不要 install -g 全局安裝。這是倉庫自述的兼容線,不是對所有 dsh 快照的保證。
驗證是否裝上:
dsh --profile web --dump-config | grep tool-regex
跑一次真實調用:
dsh run "使用 regex 工具測試 d+ 是否匹配 abc123"
典型用法¶
下面按 README 的契約,把四個 action 對應到常見任務。pattern 一律按 JavaScript 語法寫,不要加 /.../ 外圍斜槓。
1. 先解釋,再執行。 用戶丟過來一段看不懂的正則時,先 explain。它不跑匹配,只返回節點序列,適合把「這段 pattern 在幹什麼」展示給人看。未閉合的 [ / ( 會帶位置報錯,例如 regex: explain: unmatched "[" at position N。
2. 從日誌裏抽字段。 用 find,需要命名組時寫成 (?<name>...),結果裏的 groups 會帶上名字;只要編號組時看 captures。limit 默認 50,日誌很長時顯式設一個更小的值,避免輸出膨脹。
3. 做可覈對的替換。 用 replace,依賴 $1 這類引用,而不是讓模型手寫拼接。零匹配時返回原文且 replaced 爲 0,便於判斷「到底有沒有改到」。
4. 只問是否命中。 用 test。若要「整串等於」而不是「中間出現」,pattern 自己加 ^ 和 $。test 不會自動補 g,避免 lastIndex 把後續判斷帶偏。
空 pattern 是合法的(匹配空串)。帶 u / v 時,空匹配按 code point 推進,避免 UTF-16 代理對被命中兩次。這些邊界在 src/engine.ts 裏按 ECMAScript AdvanceStringIndex 實現,測試文件 engine.spec.ts 覆蓋了 flags、64KB 上限和病理 pattern 的 worker 取消。
適用場景與注意事項¶
適合這些情況:
- 智能體要驗證用戶提供的正則,並給出可展示的解釋,而不是口頭保證「這段能用」
- 從一段內存中的文本(日誌片段、表單值、模型剛生成的字符串)提取字段,而不是搜工作區文件——搜文件仍應走內置
grep - 需要帶捕獲組的替換,且不希望模型去拼
node -e腳本 - 擔心病理正則把宿主卡死,需要硬超時和輸入上限
不適合、或需要額外小心的情況:
- 把不可信的超長輸入配上無錨點嵌套量詞。超時能終止 worker,但這次調用仍然失敗。
- 把
explain當成完整的正則語義引擎。它是 tokenizer:能識別錨點、字符類、分組、量詞、轉義、交替,解釋文本是英文meaning;複雜到超過 4,096 個節點會直接拒絕。 - 只裝了 web profile、卻用
dsh run做一次性任務。dsh run默認走 headless,兩邊要分別安裝。 - 把目錄頁或 scoped 包名理解成官方出品。維護者是
omdsh-dev,許可證文件版權人爲 2026 whiteicey,包名帶@deepseek-ai/前綴是 DSH 插件常見寫法,不代表由 DeepSeek 官方發佈。
目錄頁的安全提示需要照做:插件以當前 dsh 進程的權限運行,安裝時可能執行代碼。 安裝前檢查源代碼倉庫和許可證;需要可復現安裝時固定 commit 哈希。這不是走個過場——GitHub 源安裝拿到的是源碼而不是預構建產物,信任邊界就是你本機上的 dsh 進程。
小結¶
dsh-tool-regex 把「對任意文本做正則」收成一個確定性工具:test 判斷、find 提取、replace 安全替換、explain 靜態解釋。和讓模型現寫腳本再丟給 bash 相比,它少一層正確性風險;和內置 grep 相比,它不依賴文件。真正要看的是邊界:worker 1 秒硬超時、輸入 / pattern / 輸出上限,以及 explain 不執行代碼。
目錄頁:https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-tool-regex/
GitHub:https://github.com/omdsh-dev/dsh-tool-regex