校验密码是否正确,或者把一组单词按字母顺序排列,都需要对字符串进行比较。
在 C++ 中,比较 std::string 字符串一般分为 2 种方式:一种是 “使用比较运算符”,另一种是 “使用 compare() 函数”。其中比较运算符直观好读,是我们平时最推荐掌握的方式。
判断字符串是否相等
如果我们想知道两个字符串的内容是否完全一样,可以直接使用比较运算符中的 ==;如果想判断它们是否不同,则使用 !=。
语法:
s1 == s2
s1 != s2说明:
只有当两个字符串的字符内容、排列顺序以及长度都完全相同时,== 才会返回 true。只要有任何一个字符不同,或者中间多了一个空格,!= 就会返回 true。
跟拼接字符串类似,使用 == 或 != 时,只要左右两边至少有一边是 std::string 变量,另一边直接写双引号字符串字面量也是完全合法的,比如 input == "admin"。
示例 1:判断字符串是否相等
#include <iostream>
#include <string>
int main() {
std::string s1 = "lvyenet";
std::string s2 = "lvyenet";
std::string s3 = "lvye net";
if (s1 == s2) {
std::cout << "s1 与 s2 相等" << '\n';
}
if (s1 != s3) {
std::cout << "s1 与 s3 不相等" << '\n';
}
if (s1 == "lvyenet") {
std::cout << "内容匹配成功" << '\n';
}
return 0;
}运行结果如下。
s1 与 s2 相等
s1 与 s3 不相等
内容匹配成功分析:
在这个例子中,s1 和 s2 保存的字符完全相同,所以 s1 == s2 成立。s3 中间多了一个空格,空格本身也算一个字符,因此 s1 != s3 成立。同时,s1 == "lvyenet" 也直接完成了变量与字面量的内容比对。
这里需要特别注意,不能把两个 C 风格字符串直接使用 == 比较内容。对两个 char 数组写 ==,比较的是它们在内存中的存放地址,哪怕两个数组保存的文字一模一样,比较结果也会是 false。
此外,C++ 的字符串比较严格区分英文字母的大小写。也就是说,"Admin" 和 "admin" 并不会被当成相同的字符串,下面我们来看一个例子。
示例 2:比较时区分大小写
#include <iostream>
#include <string>
int main() {
std::string input = "Admin";
std::string target = "admin";
if (input != target) {
std::cout << "两个字符串不相等" << '\n';
}
return 0;
}运行结果如下。
两个字符串不相等分析:
input 的首字母是大写 'A'(ASCII 码为 65),而 target 的首字母是小写 'a'(ASCII 码为 97),两者的编码值不同,因此 input != target 成立。
如果我们希望在比较时忽略字母的大小写差异,可以先将字符串统一转为小写再进行比较,后面在 “C++ 字符串大小写转换” 一节中会展开介绍。
C++ 字符串大小比较
除了判断相等之外,std::string 还支持使用 <、>、<=、>= 来比较两个字符串的大小。很多初学的小伙伴会觉得好奇:“数字可以比大小,那两个字符串比大小到底是在比什么呢?难道是比谁的长度更长吗?”
其实字符串比大小跟长度没有直接关系,它的规则跟平时查英文字典非常相似,在编程中也叫 “字典序比较”。
具体来说,程序会从两个字符串的第一个字符开始,从左往右逐个对比字符的 ASCII 码。一旦遇到第一个不相同的字符,谁的 ASCII 码大,谁所在的字符串就大,后面的字符就不需要再比了。
语法:
s1 < s2
s1 > s2说明:
对于常见的数字和英文字母,小伙伴们不用去死记具体的编码数值,只需要记住下面这个先后顺序即可:
数字字符 '0' ~ '9' 小于大写字母 'A' ~ 'Z',而大写字母又小于小写字母 'a' ~ 'z',同一组内部按数字或字母表顺序从小到大排列。
示例 3:按字典序比较大小
#include <iostream>
#include <string>
int main() {
std::string a = "abcde";
std::string b = "abxde";
if (a < b) {
std::cout << "abcde 小于 abxde" << '\n';
}
std::string s1 = "cat";
std::string s2 = "banana";
if (s1 > s2) {
std::cout << "cat 大于 banana" << '\n';
}
return 0;
}运行结果如下。
abcde 小于 abxde
cat 大于 banana分析:
先看第一组 a 和 b:它们的前两个字符都是 'a' 和 'b',无法区分大小。比到第 3 个字符时,'c' 的 ASCII 码小于 'x',因此直接得出 "abcde" 小于 "abxde",后面的 "de" 就不再比较了。
再看第二组 s1 和 s2:虽然 "cat" 只有 3 个字母,而 "banana" 有 6 个字母,但在对比第一个字符时,'c' 的编码值(99)大于 'b' 的编码值(98),在开头就已经分出了大小,因此 "cat" 大于 "banana"。
那如果两个字符串前面的字符全都一模一样,直到其中一个字符串先结束,此时又应该怎么判断呢?这种情况下,后面还有剩余字符的那个字符串更大,请看下面例子。
示例 4:前缀相同时比较大小
#include <iostream>
#include <string>
int main() {
std::string s1 = "app";
std::string s2 = "apple";
if (s1 < s2) {
std::cout << "app 小于 apple" << '\n';
}
return 0;
}运行结果如下。
app 小于 apple分析:
"app" 和 "apple" 的前 3 个字符完全相同。此时 "app" 已经没有后续字符了,而 "apple" 后面还有 "le",因此 "app" 小于 "apple"。
这里小伙伴们还要留意一个反直觉的细节:如果拿两个数字字符串直接比大小,比如 "9" 和 "10",得到的结果会是 "9" > "10"。
这是因为字符串永远是从左往右逐个比字符,首字符 '9' 的编码值(57)大于 '1' 的编码值(49),程序并不会把它们当成数学上的整数 9 和 10 来比较。
使用 compare() 函数(了解)
除了使用比较运算符之外,std::string 还提供了一个 compare() 成员函数。它的比较规则跟前面完全一致,只不过它返回的不是 true 或 false,而是一个 int 整数。
语法:
s1.compare(s2)说明:
调用 s1.compare(s2) 后,我们可以根据返回值与 0 的大小关系来判断比较结果,具体分为以下 3 种情况:
- 返回值小于 0:表示
s1小于s2。 - 返回值等于 0:表示
s1等于s2。 - 返回值大于 0:表示
s1大于s2。
示例 5:使用 compare() 函数
#include <iostream>
#include <string>
int main() {
std::string a = "apple";
std::string b = "banana";
int result = a.compare(b);
if (result < 0) {
std::cout << "a 小于 b" << '\n';
} else if (result == 0) {
std::cout << "a 等于 b" << '\n';
} else {
std::cout << "a 大于 b" << '\n';
}
return 0;
}运行结果如下。
a 小于 b分析:
a.compare(b) 会依次对比 "apple" 和 "banana" 的字符。由于首字母 'a' 小于 'b',函数返回一个负数,程序进入 if...else 语句的第一个分支并输出结果。
需要注意的是,C++ 标准只规定 compare() 返回负数、0 或正数,并不一定返回 -1 或 1,有些编译器会直接返回字符的编码差值。因此判断时应该写成 result < 0 或 result > 0,不要写成 result == -1。
在实际开发中,直接使用 ==、!=、<、> 比调用 compare() 直观得多,推荐大家优先使用比较运算符。
