在忽略大小写的情况下比较字符串的有效方法是什么?
What is an efficient way to compare strings while ignoring case?
要比较两个 String
s,忽略大小写,看起来我首先需要将字符串转换为小写版本:
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"));
要比较两个 String
s,忽略大小写,看起来我首先需要将字符串转换为小写版本:
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"));