將只有 ASCII 範圍的 wstring 轉換成 string

Windows 的程式,若是 Unicode enabled 的話,預設使用的編碼是 UTF-16,每個字元的型別為 wchar_t。這樣的字串,無法使用 std::string 處理,必須改用 std::wstring。但有時候,現有的函式如果只吃 std::string,而且我們的字串又只包含有 ASCII 定義的字元(也就是只有英文及半型符號)的話,我們就必須把 std::wstring 轉成 std::string

有一種比較偷懶的做法:

std::wstring ws(L"Hello");
std::string s(ws.begin(), ws.end());

但是在比較嚴謹的 C++ 編譯器(例如 VS 2022),就會發出警告(因為隱式把 wchar_t 轉換成 char,可能造成資料流失)。想要避開警告,就必須明確使用 static_cast<> 進行資料轉換。此時就可以利用 std::transform() 來做:

std::wstring ws(L"Hello");
std::string s(ws.size(), 0);
std::transform(ws.begin(), ws.end(), s.begin(), [](wchar_t c){
    return static_cast<char>c;
});

[Rust] 如何產生靜態連結的 Win32/64 執行檔?

在預設情況下,Windows 版本的 rustc 編譯出來的 Win32/Win64 執行檔,會需要一些 Visual C++ 的 DLL 才能執行。對於軟體開發人員來說,在建構開發環境的過程中,這些 DLL 都會被安裝到系統之中,因此不太會遇到編譯出來的執行檔無法執行的問題;但若是我們要將執行檔給別人、在沒有安裝開發環境的電腦上執行,往往就會遇到問題。

我們可以利用 Visual Studio 所內建的工具程式 dumpbin(加上參數 /dependents)來檢查執行檔的 DLL 依存關係:

上面列出來的 DLL 中,KERNEL32.DLLbcrypt.dll 是 Windows 內建的 DLL,其他的都是 Visual C++ 提供的 DLL,不見得每一台 PC 上都會有這些 DLL。

如果希望 rustc 採用靜態連結的方式、移除對 VC++ DLL 的依存性,可以在 Rust 專案中的 .cargo\config 檔案中,加上這兩行:

[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]

然後重新編譯程式。這樣就可以了:

  • 資料來源:https://stackoverflow.com/questions/31770604/how-to-generate-statically-linked-executables

在 wxWidgets 中執行繁重工作時不讓 UI 凍結的作法

我想要用 wxWidgets 寫一個程式,能夠掃瞄整個目錄結構,然後把不需要的檔案刪掉。掃瞄這件事情可以用遞迴來做:

void MainFrame::RecursiveClean(const wxString& dirname) {
  wxDir dir(dirname);
  if (!dir.IsOpened()) {
    return;
  }
  wxString name;
  wxFileName fn(dirname, "");
  bool found = dir.GetFirst(&name);
  while (found) {
    wxString fullpath = fn.GetPathWithSep() + name;
    if (wxDirExists(fullpath)) {
      if (delete_folder_patterns_.Match(name)) {
        // ...delete folder...
      } else {
        RecursiveClean(fullpath);
      }
    } else if (wxFileExists(fullpath)) {
      if (delete_file_patterns_.Match(name)) {
        // ...delete file...
      }
    }
    found = dir.GetNext(&name);
  }
}
Code language: C++ (cpp)

但掃瞄的過程很花時間。如果我們就直接這樣硬幹,在掃瞄的過程中,wxWidgets 就沒有辦法處理事件,導致整個 UI 就會停在那邊沒有反應。所以我們要想個方法去解決。

Read More

用 Rust 寫簡單的互動式命令列程式

最近在研究 1904 年日期系統,想說寫一個簡單的 Rust 程式來測試一下想法。主要的轉換函式寫完後,希望把程式寫成簡單的互動式程式,方便測試。

參考網路上的文章,結果如下:

// 先不用管 y1904 的細節,在這個範例中不重要。
mod y1904;

// 使用 std::io::Write 是為了 flush()
use std::io::{stdin, stdout, Write};
use y1904::*;

fn main() {
    loop {
        // 記得轉成 lowercase,比較好處理
        match prompt_for_input("> ").to_ascii_lowercase().as_str() {
            "exit" => break,
            s @ _ => match s.parse::<u64>() {
                Ok(num) => println!("{:?}", num_to_date(num)),
                _ => continue,
            },
        }
    }
}

fn prompt_for_input(prompt: &str) -> String {
    print!("{}", prompt);

    // 如果沒有呼叫 flush() 的話,在使用者輸入之前,上一行可能不會印出來
    stdout().flush().unwrap();

    let mut result = String::new();
    stdin().read_line(&mut result).unwrap();

    // 使用 trim() 去掉換行符號。
    // trim() 回傳的是 &str,因此要再轉成 String 回傳
    result.trim().to_string()
}

至於 y1904 的內容.... 之後再說好了。 XDD

全主場時代球迷與球團的心態調整

按:此文為 2014 年 Lamigo 桃猿隊實施「全猿主場」之初,於 Blogger 及 PTT 上發表過的文章,單純搬運回來當作備份。

我從職棒紀元前的「甲組成棒聯賽」開始看台灣成棒/職棒,看著看著竟也有二十餘年了。職棒走過了二十多年的「草創時期」,今年終於有個球團完全落實屬地主義,打破二十多年來「壁壘分明」、「漢賊不兩立」的傳統,將整個內野區劃為「主場球隊責任區」。突破「傳統」的做法想當然爾會引起話題和爭論,不過平心而論,這樣的做法完全符合世界潮流,是中華職棒的一大進步;球迷間的反應也以正面居多。而其他球團雖然有些反對的雜音,但目前的趨勢看起,各隊都多多少少朝著「全主場」的方向前進中。

不諱言地說,我目前支持的球隊正是實施「全猿主場」的 Lamigo 桃猿,今年的「全猿主場」當然也進場體驗過了幾次。對於球團努力的成果,我給予高度的肯定!不過,也許是二十多年來那種壁壘分明的對立心態還存在我們心中,我覺得球迷們(尤其是客隊的球迷)好像還沒有準備好接受這樣的改變。另外,目前的「全猿主場」做法我也覺得還有些可以調整的地方,藉由這篇文章來一起討論。

Read More

Rustlings 習題探討:errors6.rs

主要是要練習如何撰寫及應用 error conversion。

整個程式是要實作一個新的型別 PositiveNonzeroInteger,意即「正整數」;0 或負整數都不是合法的。這個正整數要從字串 parsing 而來。如果 parsing 時就出問題,要把 parse() 的 error 轉換成 ParsePosNonezeroError::ParseInt();而如果 parsing 沒問題,但數值本身是 0 或負整數的話,就要回傳 ParsePosNonezeroError::Creation()(依據數值是 0 或負整數,會代不同的 error code)。

Conversion 的部份很單純:

impl ParsePosNonzeroError {
    fn from_creation(err: CreationError) -> ParsePosNonzeroError {
        ParsePosNonzeroError::Creation(err)
    }

    fn from_parsing(err: ParseIntError) -> ParsePosNonzeroError {
        ParsePosNonzeroError::ParseInt(err)
    }
}

比較有趣的是應用的部份。

Read More

Dev-C++ 的前世今生

Dev-C++ 是一套 Windows 上免費(且開放原始碼)的 C/C++ 整合式開發環境 (IDE)。它的 GUI 部份基本上是使用 Delphi 寫成,而背後的編譯器則是使用 Mingw 版本的 GCC。因為可以免費取得,而且安裝、使用上又方便(跟原始 Mingw GCC 比較的話),所以不少學校在教 C++ 的時候,都建議學生使用這一套 IDE。

但 Dev-C++ 在網路上有幾個常見的分支,常常看到初學者使用非常舊的版本,不但編譯器不支援新的 C++ 語法,而且 Dev-C++ 本身還可能有尚未修正的 bug。在此稍微聊一下 Dev-C++ 常見的幾個版本,並且提出給 C/C++ 初學者的建議。

Read More

[Exercism][Rust] Diffie Hellman

題目網址(需登入 Exercism)

這個題目在 Rust 語言方面,沒有什麼太困難的地方。所以重點都是在 modular arithmetic 的運算上。

use rand::Rng;

pub fn private_key(p: u64) -> u64 {
    let mut rng = rand::thread_rng();
    rng.gen_range(2..p)
}

pub fn public_key(p: u64, g: u64, a: u64) -> u64 {
    modular_exp(g, a, p)
}

pub fn secret(p: u64, b_pub: u64, a: u64) -> u64 {
    modular_exp(b_pub, a, p)
}
Read More

Wizardry 開發史 (3) – Wizardry

當 Robert Woodhead 完成 Galactic Attack 時,其實他腦中已經有下一部遊戲的想法了。

他繼續從 PLATO 系統上找靈感。當時 PLATO 系統上有幾個類似 D&DDungeons and Dragons,《龍與地下城》)系統的角色扮演遊戲,像是 dnd(看名字就知道)、Moria(這個名字就是《魔戒》中的「摩瑞亞坑道」)、Oubliette(即「地下城」的法文),以及 Avatar 等。這些遊戲在大學校園中相當受歡迎,而家用電腦的領域中卻沒有類似的遊戲。Robert 思索著該如何將這樣的遊戲系統轉移到 Apple ][ 上。他將這個遊戲計畫的名稱暫定為 Paladin

巧的是,在康乃爾大學中,也有個主修資訊的研究生在做類似的事情。那個傢伙就是 Andrew Greenburg(傳說中的 Werdna)。

Read More