怎样把 MediaWiki 的 wikitext 转换为 GitHub 风格的 markdown

Revision as of 14:22, 10 March 2026 by Mwroot (talk | contribs)
;; wikitext -> gfm converter
;;
;; 设计原则:
;; 1 所有规则按顺序执行
;; 2 每条规则对应一段代码
;; 3 不做抽象,优先可读性
;;
;; 规则:
;; 1 <code> 和 </code> -> ```
;; 2 <syntaxhighlight> 和

-> ```

3 # -> *
4 ====== -> ######
5 ===== -> #####
6 ==== -> ####
7 === -> ###
8 == -> ##
9 -> ~~
10 ---- -> ---

(defun wikitext-convert-all (&optional start end)

 "Convert simple wikitext to GFM markdown."
 (interactive
  (if (use-region-p)
      (list (region-beginning) (region-end))
    (list (point-min) (point-max))))
 (save-excursion
   (save-restriction
     (narrow-to-region start end)
     ;; --------------------------------------------------
     ;; 1. inline 
     ;; --------------------------------------------------
     (goto-char (point-min))
     (while (re-search-forward "\\([^<\n]*\\)" nil t)
       (replace-match (concat "`" (match-string 1) "`") t t))
     (goto-char (point-min))
     (while (re-search-forward "" nil t)
       (replace-match "`"))
     (goto-char (point-min))
     (while (re-search-forward "" nil t)
       (replace-match "`"))
     ;; --------------------------------------------------
     ;; 2. syntaxhighlight
     ;; --------------------------------------------------
     (goto-char (point-min))
     (while (re-search-forward "<syntaxhighlight\\s-+lang=[\"']\\([^\"']+\\)[\"'][^>]*>" nil t)
       (replace-match (concat "```" (match-string 1)) t t))
     (goto-char (point-min))
     (while (re-search-forward "</syntaxhighlight>" nil t)
       (replace-match "```"))
     ;; --------------------------------------------------
     ;; 3. 列表 # → *
     ;; --------------------------------------------------
     (let ((in-code-block nil))
       (goto-char (point-min))
       (while (not (eobp))
         (let ((line (thing-at-point 'line t)))
           (when (string-match "^```" line)
             (setq in-code-block (not in-code-block)))
           (unless in-code-block
             (beginning-of-line)
             (while (search-forward "#" (line-end-position) t)
               (replace-match "*"))))
         (forward-line 1)))
     ;; --------------------------------------------------
     ;; 4. headings
     ;; --------------------------------------------------
     (dolist (n '(6 5 4 3 2))
       (goto-char (point-min))
       (let ((pat (format "^=\\{%d\\}[ \t]*\\(.*?\\S-\\)[ \t]*=\\{%d\\}[ \t]*$" n n))
             (rep (concat (make-string n ?#) " \\1")))
         (while (re-search-forward pat nil t)
           (replace-match rep))))
     ;; --------------------------------------------------
     ;; 5. other
     ;; --------------------------------------------------
     (goto-char (point-min))
     (while (re-search-forward "" nil t)
       (replace-match "~~"))
     (goto-char (point-min))
     (while (re-search-forward "" nil t)
       (replace-match "~~"))
     (goto-char (point-min))
     (while (re-search-forward "^----[ \t]*$" nil t)
       (replace-match "---"))
     (widen))))

</syntaxhighlight>