在忽略大小写的情况下比较字符串的有效方法是什么?

What is an efficient way to compare strings while ignoring case?

要比较两个 Strings,忽略大小写,看起来我首先需要将字符串转换为小写版本:

let a_lower = a.to_lowercase();
let b_lower = b.to_lowercase();
a_lower.cmp(&b_lower)

是否有一种方法可以比较字符串,忽略大小写,无需创建临时小写字符串,即遍历字符,在那里执行到小写的转换并进行比较结果?

没有 built-in 方法,但您可以编写一个完全按照您描述的方法,假设您只关心 ASCII 输入。

use itertools::{EitherOrBoth::*, Itertools as _}; // 0.9.0
use std::cmp::Ordering;

fn cmp_ignore_case_ascii(a: &str, b: &str) -> Ordering {
    a.bytes()
        .zip_longest(b.bytes())
        .map(|ab| match ab {
            Left(_) => Ordering::Greater,
            Right(_) => Ordering::Less,
            Both(a, b) => a.to_ascii_lowercase().cmp(&b.to_ascii_lowercase()),
        })
        .find(|&ordering| ordering != Ordering::Equal)
        .unwrap_or(Ordering::Equal)
}

正如下面的一些评论所指出的,如果不对整个字符串进行操作,case-insensitive 比较对于 UTF-8 将无法正常工作,即使这样也有一些大小写转换的多种表示形式,这可能会产生意想不到的结果。

考虑到这些注意事项,与上面的 ASCII 版本相比,以下内容适用于很多额外的情况(例如,大多数带重音的拉丁字符),并且可能会令人满意,具体取决于您的要求:

fn cmp_ignore_case_utf8(a: &str, b: &str) -> Ordering {
    a.chars()
        .flat_map(char::to_lowercase)
        .zip_longest(b.chars().flat_map(char::to_lowercase))
        .map(|ab| match ab {
            Left(_) => Ordering::Greater,
            Right(_) => Ordering::Less,
            Both(a, b) => a.cmp(&b),
        })
        .find(|&ordering| ordering != Ordering::Equal)
        .unwrap_or(Ordering::Equal)
}

如果您只使用 ASCII,您可以使用 eq_ignore_ascii_case:

assert!("Ferris".eq_ignore_ascii_case("FERRIS"));