當我們辛苦的在 ChatGPT 中對話得到的結果,如果其中含有數學公式相關的格式,在將結果複製到 Word 文件中時,其實是無法直接使用的,因為公式無法正確被顯示(如下圖)。
如何解決這樣的問題?

以下是目前我有找出最方便而簡單的方式。參考以下的作法:
1. 安裝 Pandoc 。
先連線:https://pandoc.org/,下載合於你使用的版本,並且先行安裝好。
2. 將 ChatGPT 提供你的解答,複製後貼至記事本中,再另存新檔為「*.md」。

3. 我請 ChatGPT 提供一個 VBA 程式碼以將這個 Markdown 語法的內容轉換為 Word 文件。(VBA 程式碼放在網頁下方)
4. 新增一個 Word 文件,選取「開發人員/Visual Basic」。

5. 選取「插入/模組」。

6. 貼上先前複製的 VBA 程式碼,並且點選:執行。

確認執行這個巨集:

7. 選取先前儲存由 ChatGPT 提供內容的 Markdown 語法檔案。

8. 設定一個存檔的名稱,點選:儲存。

整個工作完成,可以得到轉換後的 Word 文件。

------- 以下為 VBA 程式碼 ----------------------------------------------------------------
Option Explicit
' ============================
' Windows + Pandoc 專用版本
' ============================
' 入口點
Sub MD_LaTeX_To_Word()
Dim srcPath As String, dstPath As String, refDoc As String
Dim ok As Boolean
srcPath = PickSourceFile()
If srcPath = "" Then Exit Sub
dstPath = PickDestDocx(srcPath)
If dstPath = "" Then Exit Sub
If Not HasPandocWin() Then
MsgBox "找不到 pandoc。請確認已安裝並已加入 PATH(在命令列輸入 pandoc -v 應可看到版本)。", vbCritical
Exit Sub
End If
If MsgBox("要套用自訂 Word 樣板(reference .docx)嗎?", vbQuestion + vbYesNo, "Pandoc reference-doc") = vbYes Then
refDoc = PickReferenceDocx(GetFolder(dstPath))
If refDoc = "" Then
If MsgBox("未選擇樣板,改用 Word 預設樣式繼續?", vbQuestion + vbYesNo) = vbNo Then Exit Sub
End If
End If
ok = ConvertWithPandocWin(srcPath, dstPath, refDoc)
If ok Then
Documents.Open FileName:=dstPath
MsgBox "轉換完成。", vbInformation
Else
MsgBox "轉換失敗(請檢查來源內容或 Pandoc 設定)。", vbCritical
End If
End Sub
'── 檔案挑選(安全過濾,避免 Filters.Clear 在某些環境報錯) ────────────────
Private Sub SafeSetFilters(fd As FileDialog, ByVal desc As String, ByVal pattern As String)
On Error Resume Next
fd.Filters.Clear
fd.Filters.Add desc, pattern
On Error GoTo 0
End Sub
Private Function PickSourceFile() As String
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
With fd
.Title = "選擇含 Markdown/LaTeX 的來源檔案"
.AllowMultiSelect = False
SafeSetFilters fd, "Markdown/LaTeX/Text", "*.md;*.markdown;*.tex;*.txt"
If .Show = -1 Then
PickSourceFile = .SelectedItems(1)
Else
PickSourceFile = ""
End If
End With
End Function
Private Function PickDestDocx(ByVal src As String) As String
Dim fd As FileDialog
Dim defName As String
defName = Replace(GetFileName(src), GetFileExt(src), "") & "_converted.docx"
Set fd = Application.FileDialog(msoFileDialogSaveAs)
With fd
.Title = "另存新檔(.docx)"
' 為避免相容性問題,不設定 Filters;副檔名由程式補上
.InitialFileName = GetFolder(src) & "\" & defName
If .Show = -1 Then
Dim p As String: p = .SelectedItems(1)
If LCase$(Right$(p, 5)) <> ".docx" Then p = p & ".docx"
PickDestDocx = p
Else
PickDestDocx = ""
End If
End With
End Function
Private Function PickReferenceDocx(ByVal initialFolder As String) As String
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
With fd
.Title = "選擇 reference .docx 樣板(可省略)"
.AllowMultiSelect = False
.InitialFileName = initialFolder & "\"
SafeSetFilters fd, "Word 文件", "*.docx"
If .Show = -1 Then
PickReferenceDocx = .SelectedItems(1)
Else
PickReferenceDocx = ""
End If
End With
End Function
'── Pandoc 偵測與轉換(Windows) ───────────────────────────────────────────
Private Function HasPandocWin() As Boolean
On Error GoTo EH
Dim sh As Object, ex As Object, outStr As String, errStr As String
Set sh = CreateObject("WScript.Shell")
Set ex = sh.Exec("cmd /c where pandoc")
Dim t As Date: t = Now
Do While ex.Status = 0
DoEvents
If Now - t > TimeSerial(0, 0, 5) Then Exit Do ' 最多 5 秒
Loop
outStr = ex.StdOut.ReadAll
errStr = ex.StdErr.ReadAll
HasPandocWin = (InStr(1, outStr, "pandoc.exe", vbTextCompare) > 0) Or (InStr(1, outStr, "pandoc", vbTextCompare) > 0)
Exit Function
EH:
HasPandocWin = False
End Function
Private Function ConvertWithPandocWin(ByVal src As String, ByVal dst As String, ByVal refDoc As String) As Boolean
On Error GoTo EH
Dim sh As Object, ex As Object
Dim cmd As String, outStr As String, errStr As String
' 說明:
' -f markdown+tex_math_dollars+latex_macros :啟用 $...$ / $$...$$ 與 LaTeX 宏
' -t docx --standalone :輸出為 Word(Pandoc 會把 LaTeX 數學轉為 OMML 原生方程式)
' --wrap=none :避免硬換行
' --resource-path :讓圖片等資源能以來源檔所在資料夾為基準
cmd = "pandoc " & QuoteWin(src) & _
" -f markdown+tex_math_dollars+latex_macros" & _
" -t docx --standalone --wrap=none" & _
" --resource-path=" & QuoteWin(GetFolder(src))
If Len(refDoc) > 0 Then
cmd = cmd & " --reference-doc=" & QuoteWin(refDoc)
End If
cmd = cmd & " -o " & QuoteWin(dst)
Set sh = CreateObject("WScript.Shell")
Set ex = sh.Exec("cmd /c " & cmd)
' 等待完成(最多 5 分鐘,可自行調整)
Dim t As Date: t = Now
Do While ex.Status = 0
DoEvents
If Now - t > TimeSerial(0, 5, 0) Then Exit Do
Loop
outStr = ex.StdOut.ReadAll
errStr = ex.StdErr.ReadAll
If Len(errStr) > 0 And Not FileExists(dst) Then
MsgBox "Pandoc 錯誤輸出:" & vbCrLf & errStr, vbExclamation
ConvertWithPandocWin = False
Exit Function
End If
ConvertWithPandocWin = FileExists(dst)
Exit Function
EH:
MsgBox "執行 Pandoc 時發生錯誤:" & Err.Description, vbExclamation
ConvertWithPandocWin = False
End Function
'── 路徑/字串/檔案工具 ──────────────────────────────────────────────────────
Private Function QuoteWin(ByVal s As String) As String
QuoteWin = """" & s & """"
End Function
Private Function GetFolder(ByVal path As String) As String
GetFolder = Left$(path, InStrRev(path, "\") - 1)
End Function
Private Function GetFileName(ByVal path As String) As String
GetFileName = Mid$(path, InStrRev(path, "\") + 1)
End Function
Private Function GetFileExt(ByVal path As String) As String
Dim p As Long: p = InStrRev(path, ".")
If p > 0 Then GetFileExt = Mid$(path, p) Else GetFileExt = ""
End Function
Private Function FileExists(ByVal path As String) As Boolean
On Error Resume Next
FileExists = (Len(Dir$(path, vbNormal)) > 0)
End Function
留言列表