03 / 真實套件案例 / 閱讀約 7 分鐘

slugify:為什麼 URL 裡還有「!」?

「Déjà Vu!」 變成了「deja-vu!」,但你想要的是「deja-vu」。用 REA 分析這個 JavaScript 套件,找到控制標點的設定,再驗證結果。

本頁內容
slugify 1.6.6 / MITREA 6.4.0驗證於 2026 年 10 月 12 日

直接看答案

lower: true 只會把大寫字母改成小寫。再加上 strict: true 就能同時移除標點。這是需要開啟的選項,並非庫本身的錯誤。

可用設定
slugify("Déjà Vu!", { lower: true, strict: true })
// → "deja-vu"

01. 我們想要的 URL

slug 是 URL 末尾便於閱讀的一段,例如 deja-vu (完整 URL 為 example.com/posts/deja-vu)。本範例使用真實的 slugify 1.6.6 npm 發行版本。下方結果來自在本機執行該版本。

試試下方標題,再開啟 移除標點符號 看看差別。

試用真實套件 slugify 1.6.6
生成的 URL
example.com/posts/deja-vu!

還有「!」?請開啟 移除標點符號。

JavaScript 選項{ lower: true, strict: false }

在瀏覽器本機執行,不上傳任何內容。REA 的使用見文字教學。

下面是同樣的 JavaScript 比較:

套件的實際行為
slugify("Déjà Vu!")
// → "Deja-Vu!"

slugify("Déjà Vu!", { lower: true })
// → "deja-vu!"

重音符號消失了,感嘆號卻還在。我們用 REA 定位套件入口檔案,讀取過濾程式碼,並查明哪個選項會移除感嘆號。你可以按下方步驟重現。

02. 下載套件,用 REA 分析

我們下載了固定版本的 npm tarball,解壓時沒有安裝或執行套件。以下準備指令需要 shell 中有 tar:

終端機
mkdir rea-slugify-case
cd rea-slugify-case
npm pack [email protected]
tar -xzf slugify-1.6.6.tgz

隨後,我們對解壓後的 package 目錄執行 REA 的 JavaScript 應用程式分析器:

如果更習慣使用 AI 程式開發代理,請替換路徑並貼上這段提示詞:

複製到 AI 程式開發代理
使用 REA 分析 /absolute/path/to/rea-slugify-case/package。我用 slugify 生成文章 URL。為什麼 slugify('Déjà Vu!', { lower: true }) 會保留感嘆號?找到入口檔案,展示允許保留它的程式碼,並指出移除它的選項。不要修改套件。

也可以直接在終端機收集分析結果:

終端機
npx -y [email protected] analyze-javascript-application ./package --json > analysis.json

REA 將套件識別為 slugify,版本為 1.6.6,入口為 ./slugify.js。報告紀錄了三個相關檔案,解析失敗數為零;同時將整體圖覆蓋範圍標記為 partial(部分覆蓋),我們在釋出的摘要中保留了這一點。

這是可讀的 JavaScript 發行包。REA 提供了檔案清單和分析上下文,隨後透過原始碼檢查和直接驗證確認行為,未涉及原生程式碼反編譯。

03. 找到移除標點的選項

在發行套件的 slugify.js中,第 33–42 行完成字串正規化、語言或字元對映替換,以及字元過濾。預設過濾規則明確允許感嘆號。

slugify.js · 第 41–47 行
// remove not allowed characters
.replace(options.remove || /[^\w\s$*_+~.()'"!\-:@]+/g, '')
}, '');

if (options.strict) {
  slug = slug.replace(/[^A-Za-z0-9\s]/g, '');
}

strict 分支隨後執行,移除字母、數字和空白以外的字元。小寫轉換是第 57–58 行的獨立操作。由此可以提出一個可測試的預測:

預測
slugify("Déjà Vu!", { lower: true, strict: true })
// should return "deja-vu"

同一檔案也解釋了為什麼多個空格合併成一個分隔符,為什麼 & 變成 and,以及為什麼德語設定會改變 Ä 變為 AE。

04. 在真實套件上執行驗證

我們對未經修改的 1.6.6 版本執行了八項斷言,包括最初的問題和幾個相關行為。

8 / 8
驗證通過。

原始套件 · Node.js 22.23.1 · macOS arm64

輸入選項實際結果
Déjà Vu!預設Deja-Vu!
Déjà Vu!lowerdeja-vu!
Déjà Vu!lower + strictdeja-vu
hello world(兩側有空格)預設hello-world
Rock & Roll預設Rock-and-Roll
Äpfel德語設定 + loweraepfel
空字串預設空字串
42(數字)預設丟擲「string argument expected」錯誤

檢視已紀錄的驗證結果,或使用上方互動示範。示範在瀏覽器中執行同一固定版本的套件。

05. 我們測試了什麼

對於這個版本和這些輸入,原始碼與實際輸出一致。如果想得到 deja-vu,請同時使用 lower: true 和 strict: true。

注意驗證範圍。 八項驗證不能覆蓋所有 Unicode 或語言設定行為。REA 的關係圖並不完整;圖中缺少某個關係,並不能證明關係不存在。我們沒有重建原生二進位檔案,也沒有恢復無法取得的原始碼。

發行套件中的原始碼可讀,因此直接檢查原始碼也是可行方法。這個案例示範完整的分析習慣:確認分析物件,檢查一條規則,再對照原始實作驗證結論。

06. 下載並執行這個範例

下載小型重現資料包,其中包含固定版本的依賴、全部八項斷言,以及收集 REA 證據的步驟。

下載重現資料包

在解壓後的資料包中執行
npm install --ignore-scripts
node verify.mjs

斷言指令碼會列印每項結果,任一驗證失敗時以錯誤退出。只有到這一步,Node.js 才會執行 npm 套件;此前 REA 的靜態分析不會執行它。

試試另一篇教學查明應用程式把匯出檔案儲存在哪裡。

證據: REA 分析摘要 · 驗證結果 · 已分析的原始碼 · MIT 授權條款。套件由 simov 和貢獻者開發。分析和執行驗證於 2026 年 10 月 12 日在本機完成。公開摘要已省略本機檔案系統路徑。

第一次使用這個工具? REA 是什麼? · 我們如何查核教學