能否使用C++20的starts_with/ends_with进行大小写不敏感比较?
好问题!确实C++20新增的starts_with()和ends_with()是大小写敏感的,就像你举的例子那样,用大写的"HTTPS"去匹配小写开头的url会返回false。如果不想依赖Boost的istarts_with,也不想通过转全小写/大写产生额外的字符串副本,我们可以自己实现高效的大小写不敏感版本。
方案1:手动逐字符比较(直观可控)
直接基于std::string_view实现,避免字符串拷贝,只在比较时临时转换单个字符的大小写:
#include <string_view> #include <cctype> #include <iostream> // 大小写不敏感的前缀检查 bool istarts_with(std::string_view str, std::string_view prefix) { if (prefix.size() > str.size()) { return false; } for (size_t i = 0; i < prefix.size(); ++i) { // 转成unsigned char避免tolower处理有符号char的未定义行为 if (std::tolower(static_cast<unsigned char>(str[i])) != std::tolower(static_cast<unsigned char>(prefix[i]))) { return false; } } return true; } // 同理实现后缀检查 bool iends_with(std::string_view str, std::string_view suffix) { if (suffix.size() > str.size()) { return false; } auto str_pos = str.end() - suffix.size(); auto suffix_pos = suffix.begin(); while (str_pos != str.end()) { if (std::tolower(static_cast<unsigned char>(*str_pos)) != std::tolower(static_cast<unsigned char>(*suffix_pos))) { return false; } ++str_pos; ++suffix_pos; } return true; } // 测试你的例子 int main() { const std::string url { "https://isocpp.org" }; if (istarts_with(url, "HTTPS")) { std::cout << "you're using the correct site!\n"; } return 0; }
方案2:用std::equal简化代码
利用标准库的std::equal算法,配合自定义谓词实现更简洁的版本,同样无额外拷贝:
#include <algorithm> #include <string_view> #include <cctype> #include <iostream> bool istarts_with(std::string_view str, std::string_view prefix) { return prefix.size() <= str.size() && std::equal(prefix.begin(), prefix.end(), str.begin(), [](unsigned char a, unsigned char b) { return std::tolower(a) == std::tolower(b); }); } bool iends_with(std::string_view str, std::string_view suffix) { return suffix.size() <= str.size() && std::equal(suffix.rbegin(), suffix.rend(), str.rbegin(), [](unsigned char a, unsigned char b) { return std::tolower(a) == std::tolower(b); }); } // 测试 int main() { const std::string url { "https://isocpp.org" }; if (istarts_with(url, "HTTPS")) { std::cout << "you're using the correct site!\n"; } return 0; }
注意事项
- 上面的代码基于ASCII字符处理,
std::tolower在处理非ASCII字符时可能不符合预期(比如带重音的字母)。如果需要支持Unicode,可以考虑使用专门的字符处理函数,但这会引入额外依赖。 - 用
static_cast<unsigned char>包裹字符是必要的:因为char可能是有符号类型,当字符值为负(比如某些扩展ASCII)时,std::tolower的行为是未定义的,转成无符号类型可以避免这个问题。
这样实现的函数和Boost的istarts_with效果类似,而且不需要依赖第三方库,也不会产生额外的字符串副本,效率很高。
内容的提问来源于stack exchange,提问作者fen
相关产品推荐
相关产品推荐

