cover

你有沒有想過,Markdown 是怎麼變成 HTML 的?**粗體** 怎麼變成 <strong>粗體</strong>

這背後就是 Interpreter Pattern 的思路:定義語法規則 → 解析文本 → 執行轉換。

先講結論

Interpreter Pattern 為一種「語言」定義語法規則,每個規則是一個 class,可以組合使用。適合簡單的 DSL(Domain Specific Language),但複雜語言請用 parser generator,別自己硬幹。

classDiagram
    class InterpreterRule {
        <<abstract>>
        +interpret(context)* Context
    }
    class BoldInterpreter {
        +interpret(context) Context
    }
    class ItalicInterpreter {
        +interpret(context) Context
    }
    class MarkdownInterpreter {
        -rules : InterpreterRule[]
        +addRule(rule) void
        +interpret(context) String
    }
    InterpreterRule <|-- BoldInterpreter
    InterpreterRule <|-- ItalicInterpreter
    MarkdownInterpreter o-- InterpreterRule : 依序執行

實戰:迷你 Markdown 解析器

Interpreter 模式:文本經過濾鏡逐步轉換

class InterpreterContext {
    constructor(text) { this.text = text; }
    getText() { return this.text; }
    setText(text) { this.text = text; }
}
 
class BoldInterpreter {
    interpret(context) {
        let text = context.getText();
        text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
        context.setText(text);
        return context;
    }
}
 
class ItalicInterpreter {
    interpret(context) {
        let text = context.getText();
        text = text.replace(/\*(.*?)\*/g, '<em>$1</em>');
        context.setText(text);
        return context;
    }
}
 
class MarkdownInterpreter {
    constructor() { this.rules = []; }
    addRule(rule) { this.rules.push(rule); }
 
    interpret(context) {
        for (const rule of this.rules) {
            rule.interpret(context);
        }
        return context.getText();
    }
}
 
const interpreter = new MarkdownInterpreter();
interpreter.addRule(new BoldInterpreter());  // 先處理粗體
interpreter.addRule(new ItalicInterpreter()); // 再處理斜體
 
const context = new InterpreterContext('這是 **粗體** 和 *斜體*');
console.log(interpreter.interpret(context));
// 這是 <strong>粗體</strong> 和 <em>斜體</em>

注意規則的順序很重要——如果先處理斜體,**粗體** 會被吃掉(因為 ** 裡面包含 *)。

什麼時候適合用 Interpreter?

  • 簡單的 DSL 解析(設定檔語法、查詢語言)
  • 規則是可組合的、會成長的
  • 語法不會太複雜(規則超過 20 條就該考慮用 parser generator)

什麼時候不該用?

語法複雜的時候。Interpreter Pattern 每個規則一個 class,語法一複雜 class 數量就爆炸。真的要做語言解析,用 PEG.js、ANTLR 這類工具。


Interpreter Pattern 就像翻譯——每個翻譯員負責一種語法,文本經過所有翻譯員之後就變成目標語言了。只是翻譯員太多的時候,翻出來的東西連你自己都看不懂


延伸閱讀