# 如何在 Windows 打造 OpenCC 中文繁簡轉換工具

[OpenCC](https://github.com/BYVoid/OpenCC) 是一個開源的中文繁簡轉換工具，可以用來將簡體中文轉換成繁體中文，或是將繁體中文轉換成簡體中文，我已經用十多年了，是個很棒的工具。不過，我以前一直都是在 Linux 底下使用它，因為官方並沒有提供 Windows 執行檔，如果要能在 Windows 直接執行，就需要自行編譯原始碼才行。這篇文章將介紹如何在 Windows 平台上建置 OpenCC 專案，以及分享如何透過 .NET 8 (`C#`) 載入 `opencc.dll` 直接呼叫 C++ 的函式庫。

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/3355e0e6439fbac05cf6-938b22f6-76c7-477b-8b24-c95435957baa.webp)

### 安裝 Microsoft Visual C++ Redistributable

由於 [OpenCC](https://github.com/BYVoid/OpenCC) 主要以 C++ 開發而成，所以在 Windows 平台上執行時，需要安裝 [Microsoft Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version) 才能確保執行時不會遇到缺少 DLL 的問題。

你可以直接到 [Microsoft Visual C++ Redistributable latest supported downloads](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version) 頁面下載 `X64` 版本回來安裝即可：

直接下載連結: [https://aka.ms/vs/17/release/vc\_redist.x64.exe](https://aka.ms/vs/17/release/vc_redist.x64.exe)

### 安裝 CMake 建置工具

[CMake](https://cmake.org/) 是一套強大的軟體建置系統，主要用來建置 C++ 的程式碼，而 OpenCC 若要在 Windows 平台建置，就要使用 CMake 來建置專案。

我打算使用 [Chocolatey](https://chocolatey.org/install) 來安裝 [CMake 3.29.1](https://community.chocolatey.org/packages/cmake) 套件：

```bash
choco install cmake --installargs 'ADD_CMAKE_TO_PATH=User' --apply-install-arguments-to-dependencies
```

### 下載原始碼並建置專案

請使用「命令提示字元」(Command Prompt) 來執行以下指令：

1.  下載最新版原始碼
    
    ```batch
    git clone https://github.com/BYVoid/OpenCC.git
    cd OpenCC
    ```
    
2.  建立 `build/` 資料夾
    
    這個步驟會指定最後的**安裝路徑**在 `C:\Tools\OpenCC` 目錄下，執行完後會產生一個 `build/` 資料夾，裡面會準備好編譯的原始碼：
    
    ```batch
    cmake -S. -Bbuild -DCMAKE_INSTALL_PREFIX:PATH="C:\Tools\OpenCC"
    ```
    
    在建置成功後，你就會在 `build/` 資料夾下看到完整的 Visual Studio 方案檔 (`opencc.sln`)，也代表你可以用 Visual Studio 2022 來開啟並編譯這個方案。
    
    > 你從 [cmake](https://cmake.org/cmake/help/latest/manual/cmake.1.html) 的文件中可以發現，當你加上 `-D` 參數時，若設定選項的值是個「路徑」的話，你可以加上 `:PATH` 代表你要設定的是一個「路徑」，如果輸入相對路徑的話，`cmake` 在執行時會自動幫你轉成「絕對路徑」。
    
3.  建置專案並安裝至指定路徑
    
    接下來可以直接透過 `cmake` 命令進行建置並自動安裝，你若使用 Visual Studio 開啟 `build\opencc.sln` 也可以建置！
    
    ```batch
    cmake --build build --config Release --target install
    ```
    
    > 這個命令的 `--target install` 參數，代表在建置成功後，會自動安裝到指定目錄。
    
4.  最後一個步驟，則是自行設定 `PATH` 環境變數，讓系統可以自動找到 `opencc.exe` 執行檔：
    
    以我上述的安裝步驟來說，你要設定的路徑在：
    
    ```batch
    C:\Tools\OpenCC\bin
    ```
    
    > 請注意: 由於在建置 OpenCC 的時候，我們已經設定了 `CMAKE_INSTALL_PREFIX` 為 `C:\Tools\OpenCC`，所以 `opencc.exe` 會被安裝在 `C:\Tools\OpenCC\bin` 目錄下，如果你今後移動了 `opencc.exe` 執行檔的路徑，他在執行時還是會去找 `C:\Tools\OpenCC` 目錄下的相關檔案，路徑是寫死在程式中的。也因為這樣，如果你想要變更路徑，就需要自行重新編譯程式，並指定不同的 `CMAKE_INSTALL_PREFIX` 參數值。
    

### 使用 OpenCC 命令

在安裝完成後，你可以在命令提示字元中輸入 `opencc` 來執行 OpenCC 的命令列工具，以下是一些常見用法：

1.  查看版本
    
    ```bash
    opencc --version
    ```
    
    ```
    Open Chinese Convert (OpenCC) Command Line Tool
    Version: 1.1.7
    ```
    
2.  查看使用說明
    
    ```bash
    opencc -h
    ```
    
    ```
    Open Chinese Convert (OpenCC) Command Line Tool
    Author: Carbo Kuo <byvoid@byvoid.com>
    Bug Report: http://github.com/BYVoid/OpenCC/issues
    
    Usage:
    
      opencc  [--noflush <bool>] [-i <file>] [-o <file>] [-c <file>] [--]
              [--version] [-h]
    
    Options:
    
      --noflush <bool>
        Disable flush for every line
    
      -i <file>,  --input <file>
        Read original text from <file>.
    
      -o <file>,  --output <file>
        Write converted text to <file>.
    
      -c <file>,  --config <file>
        Configuration file
    
      --,  --ignore_rest
        Ignores the rest of the labeled arguments following this flag.
    
      --version
        Displays version information and exits.
    
      -h,  --help
        Displays usage information and exits.
    
    
      Open Chinese Convert (OpenCC) Command Line Tool
    ```
    
3.  將 `README_CN.md` (簡體中文) 轉換為 `README_TW.txt` (繁體中文)
    
    若要將一份簡體中文的 `README_CN.md` 轉換為繁體中文的 `README_TW.md`，以下是我常用的指令：
    
    ```bash
    opencc -i README_CN.md -o README_TW.md -c s2twp.json
    ```
    
    你可以從 `C:\Tools\OpenCC\share\opencc` 目錄下找到許多不同的轉換設定檔 (`*.json`)，這裡我使用的是 `s2twp.json`，代表將簡體中文轉換為繁體中文(台灣)。這裡的 `s` 代表簡體中文，`t` 代表繁體中文，`w` 代表台灣慣用字，而 `p` (phrase) 才是代表台灣慣用詞彙。
    

### 執行 OpenCC 的效能測試

OpenCC 的執行效率非常高，如果要看看繁簡轉換的效能，必須重新編譯程式，並加入 `ENABLE_BENCHMARK=ON` 參數。

1.  準備 OpenCC 的效能測試
    
    ```bash
    cmake -S. -Bbuild -DENABLE_BENCHMARK=ON -DCMAKE_INSTALL_PREFIX:PATH=C:\Tools\OpenCC
    ```
    
2.  建置專案
    
    ```bash
    cmake --build build --config Release
    ```
    
3.  手動複製 `benchmark.dll` 檔案到發行目錄
    
    ```bash
    copy build\src\benchmark\benchmark.dll build\src\benchmark\Release\
    ```
    
4.  執行效能測試
    
    ```bash
    build\src\benchmark\Release\performance.exe
    ```
    

### 從 C# 呼叫 OpenCC 執行

這裡我參考了[黑暗執行緒](https://blog.darkthread.net/)的[使用 C# 整合 OpenCC 執行中文繁簡轉換](https://blog.darkthread.net/blog/call-opencc-with-csharp/)文章中提供的範例，並修正了一些 `Interop` 寫法 (主要是用來避免記憶體洩漏的問題)。也参考了 [Opencc Memory Leak](https://www.ci-yu.top/dotnet/opencc-memory-leak/) 文章，改用 OpenCC 內部原生的 `opencc_convert_utf8_free` 與 `opencc_close` 方法來釋放記憶體，這才徹底解決了記憶體洩漏的問題。新版如下：

```csharp
using System.Runtime.InteropServices;
using System.Text;

public static class OpenCCHelper
{
    [DllImport(@"C:\Tools\opencc\bin\opencc.dll", EntryPoint = "opencc_open")]
    private static extern IntPtr opencc_open(string configFileName);

    [DllImport(@"C:\Tools\opencc\bin\opencc.dll", EntryPoint = "opencc_convert_utf8")]
    private static extern IntPtr opencc_convert_utf8(IntPtr opencc, IntPtr input, UIntPtr length);

    [DllImport(@"C:\Tools\opencc\bin\opencc.dll", EntryPoint = "opencc_convert_utf8_free")]
    private static extern IntPtr opencc_convert_utf8_free(IntPtr str);

    [DllImport(@"C:\Tools\opencc\bin\opencc.dll", EntryPoint = "opencc_close")]
    private static extern IntPtr opencc_close(IntPtr opencc);

    public static string ConvertFromSimplifiedToTraditional(this string text, string config = "s2t")
    {
        return OpenCC(text, config: config);
    }

    public static string ConvertFromSimplifiedToTraditionalTaiwan(this string text, string config = "s2twp")
    {
        return OpenCC(text, config: config);
    }

    public static string ConvertFromTraditionalTaiwanToSimplified(this string text, string config = "tw2sp")
    {
        return OpenCC(text, config: config);
    }

    public static string ConvertFromTraditionalToSimplified(this string text, string config = "t2s")
    {
        return OpenCC(text, config: config);
    }

    public static string OpenCC(this string text, string config)
    {
        var configFile = $"C:\\Tools\\OpenCC\\share\\opencc\\{config}.json";
        if (!File.Exists(configFile))
        {
            throw new FileNotFoundException("設定檔找不到", configFile);
        }
        IntPtr opencc = opencc_open(configFile);
        try
        {
            IntPtr inputPtr = Marshal.StringToCoTaskMemUTF8(text);
            try
            {
                var input = text.ToCharArray();
                UIntPtr length = new((uint)Encoding.UTF8.GetByteCount(input));

                IntPtr resultPtr = opencc_convert_utf8(opencc, inputPtr, length);
                try
                {
                    string? result = Marshal.PtrToStringUTF8(resultPtr);
                    return result!;
                }
                finally
                {
                    //改為使用Opencc內建的釋放資源函數
                    opencc_convert_utf8_free(resultPtr);
                }
            }
            finally
            {
                Marshal.FreeCoTaskMem(inputPtr);
            }
        }
        finally
        {
            //改為使用Opencc內建的釋放資源函數
            opencc_close(opencc);
        }
    }
}
```

使用方式如下：

```csharp
string text = "";

text = "多奇数位创意有限公司";

Console.WriteLine(text.ConvertFromSimplifiedToTraditionalTaiwan());

text = "多奇數位創意有限公司";

Console.WriteLine(text.ConvertFromTraditionalTaiwanToSimplified());
```

### 相關連結

-   OpenCC
    -   [開放中文轉換 Open Chinese Convert (OpenCC)](https://opencc.byvoid.com/)
    -   GitHub Repo: [https://github.com/BYVoid/OpenCC](https://github.com/BYVoid/OpenCC)
-   黑暗執行緒
    -   [OpenCC 中文繁簡體轉換工具](https://blog.darkthread.net/blog/opencc-notes-1/)
    -   [使用 C# 整合 OpenCC 執行中文繁簡轉換](https://blog.darkthread.net/blog/call-opencc-with-csharp/)
-   [CMake - Upgrade Your Software Build System](https://cmake.org/)
-   [DllImportAttribute Class (System.Runtime.InteropServices) | Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportattribute?view=net-8.0&WT.mc_id=DT-MVP-4015686)
