在開發程式的時候常常會需要處理檔案路徑或是URL網址的串接問題,如果字串是從使用者端輸入的,由於不同使用者的習慣不同,可能有人習慣在檔案目錄路徑或是網址前面後面多加斜線,也可能有人習慣不加。如果程式是設計成要用某個使用者輸入的字串當作前綴,去串接其它的字串來組成檔案路徑或是網址的話,那麼前綴是不是以斜線結尾的影響就很大了。例如使用者輸入了path/to/folder/這樣的檔案目錄路徑,然後程式要串在其後的字串為/file,串起來之後的路徑就變成path/to/folder//file,這就可能會是一個不合法的路徑。



因為使用者習慣不同,所以我們必須要做其它的處理。例如以下程式,可以去除輸入的字串之最後面的斜線,但是如果它原本就只是一個斜線的話就不再去除:

let length = s.len();

if length > 1 && s.ends_with('/') {
    return &s[..length - 1];
} else {
    return s;
}

程式非常簡單,但也是因為如此,如果每次都要在新的程式專案中,寫這樣類似或是一樣的程式碼來處理斜線,那真的很無聊。

Slash Formatter

「Slash Formatter」是筆者開發的套件,提供多種函數來處理斜線和反斜線的字串串接。

Crates.io

Cargo.toml

slash-formatter = "*"

使用方法

slash_formatter這個crate,提供了數十種的函數,主要有add_start_slashadd_end_slashdelete_start_slashdelete_end_slashconcat_with_slash這五大類,且每一類皆有slash(斜線)、backslash(反斜線)、file_separator(根據編譯目標的作業系統來決定用斜線或是反斜線)、file_separator_build(根據專案在哪個作業系統上編譯來決定用斜線或是反斜線)的分別。其中每個函數都有不額外配置空間的「in-place」版本,例如add_start_slash_in_place所以每一類都有6個函數,五大類合起來共40個函數。

舉例來說,如果要以斜線串接兩個字串,程式如下:

assert_eq!("path/to", slash_formatter::concat_with_slash("path", "to/"));

let mut s = String::from("path");

slash_formatter::concat_with_slash_in_place(&mut s, "to/");

assert_eq!("path/to", s);

如果要以反斜線串接兩個字串,程式如下:

assert_eq!(r"path\to", slash_formatter::concat_with_backslash("path", r"to\"));

let mut s = String::from("path");

slash_formatter::concat_with_backslash_in_place(&mut s, "to\\");

assert_eq!("path\\to", s);

如果要根據運行的作業系統環境來決定要使用斜線還是反斜線來串接兩個字串的話,程式如下:

assert_eq!(r"path\to", slash_formatter::concat_with_file_separator("path", r"to\"));

let mut s = String::from("path");

slash_formatter::concat_with_file_separator_in_place(&mut s, "to/");

assert_eq!("path/to", s);

當然,如果您只是純粹想串接出能用用在目前程式執行的作業系統上的檔案路徑,可以直接使用Rust標準函式庫提供的std::path模組來處理路徑串接問題。

巨集用法

concat_with_*函數都有對應的巨集,巨集名稱為函數名稱再去除掉前綴concat_with_,支援任意參數數量,換句話說可以將傳入的任意數量的參數串接起來!

用法如下:

assert_eq!("path/to/file", slash_formatter::slash!("path", "to/", "/file/"));

let s = String::from("path");

let s = slash_formatter::slash!(s, "to/", "/file/");

assert_eq!("path/to/file", s);

let mut s = String::from("path");

slash_formatter::slash_in_place!(&mut s, "to/", "/file/");

assert_eq!("path/to/file", s);

另外還有以concat_with_為名稱前綴的巨集(例如:concat_with_slash),可以將任意數量的定數在編譯階段時串接為&'static str。是使用concat_with這個crate提供的concat_impl巨集來實作的。

用法如下:

assert_eq!("test\\10\\b\\true", slash_formatter::concat_with_backslash!("test", 10, 'b', true));

concat_with_file_separator_build巨集還有一個變體,那就是concat_with_file_separator_debug_release巨集。在Debug模式下編譯,這個巨集等同於concat_with_file_separator;而在在Release模式下編譯,這個巨集等同於concat_with_file_separator_build巨集。