在開發程式的時候我們時常會需要判斷某個字串的開頭或結尾是否符合某個字串,例如判斷網址是否以http或是https開頭時,或是判斷檔案名稱是否以.jpg或是.png結尾時。然而在上述提到的例子中,通訊協定或是檔案副檔名都是可忽略大小寫的,Rust程式語言雖然有提供eq_ignore_ascii_case方法,卻沒有提供starts_with_ignore_ascii_caseends_with_ignore_ascii_case等方法,在判斷上述例子時需要程式設計師自行先把字串做轉大寫或是轉小寫的動作才能進行判斷。



如以下程式,可以判斷一個檔案路徑的副檔名是否為png。

if path.to_lowercase().ends_with(".png") {
    ...
}

以上程式,因為我們不知道path的副檔名是pngPNG,還是PnG,因此只好先將其透過to_lowercase方法來轉成小寫,如此一來只要用ends_with來判斷它是否以.png結尾就好。

然而,對字串使用to_lowercase方法,會另外產生新的字串出來,這會讓程式記憶體用得更多,程式效能也會變得比較不好。

所以,比較好的作法是,先取得path的副檔名部份的字串切片,再利用Rust程式語言的字串內建的eq_ignore_ascii_case方法,來做判斷。程式改寫如下:

if path[(path.len() - ".png".len())..].eq_ignore_ascii_case(".png") {
    ...
}

這樣寫起來有點麻煩,而且還有可能因path本身沒有到達.png的長度,而導致程式發生panic,因此在將path轉成更小範圍的字串切片前還需進行長度的檢查。

str Utils

「str Utils」是筆者開發的套件,提供了一些特性,可以擴充有實作AsRef<[u8]>或是AsRef<str>特性的型別,使它們擁有更多的字串相關的方法。

Crates.io

https://crates.io/crates/str-utils

Cargo.toml

str-utils = "*"

使用方法

文章一開始舉的例子,可以用EndsWithIgnoreAsciiCase特性改寫成以下程式:

extern crate str_utils;

use str_utils::EndsWithIgnoreAsciiCase;

...

if path.ends_with_ignore_ascii_case(".png") {
    ...
}

另外,由於我們可以確定輸入至ends_with_ignore_ascii_case方法的字串一定是小寫,所以可以改用ends_with_ignore_ascii_case_with_lowercase方法以獲得更好的效能。

extern crate str_utils;

use str_utils::EndsWithIgnoreAsciiCase;

...

if path.ends_with_ignore_ascii_case_with_lowercase(".png") {
    ...
}

當然這個套件的功能不只這些,再舉幾個用法:

extern crate str_utils;

use str_utils::*;

assert_eq!(true, "foobar".starts_with_ignore_ascii_case("FoO"));
assert_eq!(Some(1), "photo.jpg".ends_with_ignore_ascii_case_multiple(&[".png", ".jpg", ".gif"]));
assert_eq!(true, "http".eq_ignore_ascii_case_with_uppercase("HTTP")); // faster than `eq_ignore_ascii_case`