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

问题描述

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

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

有没有一种方法可以比较字符串,忽略大小写,创建临时的小写字符串,即遍历字符,在其中执行小写转换并比较结果?

解决方法

没有内置方法,但是假设您只关心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)
}

正如下面的一些评论所指出的那样,如果不对整个字符串进行操作,则不区分大小写的比较将无法在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,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"));