字符串的比较与数字的比较有其固有的不同。数字有恒定的永远有意义
的值
为了评定两个字符串的大小关系,必须进行字典比较 lexical comparison
C++提供了多种字符串比较方法,各具特色。最简单的就是使用非成员
的重载运算符函数:operator== operator!= operator> operator<
operator>= operator<=
//: C03:CompStr.h
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#ifndef COMPSTR_H
#define COMPSTR_H
#include <string>
#include "../TestSuite/Test.h"
using std::string;
class CompStrTest : public TestSuite::Test {
public:
void run() {
// Strings to compare
string s1("This");
string s2("That");
test_(s1 == s1);
test_(s1 != s2);
test_(s1 > s2);
test_(s1 >= s2);
test_(s1 >= s1);
test_(s2 < s1);
test_(s2 <= s1);
test_(s1 <= s1);
}
};
#endif // COMPSTR_H ///:~
//: C03:CompStr.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
//{L} ../TestSuite/Test
#include "CompStr.h"
int main() {
CompStrTest t;
t.run();
return t.report();
} ///:~
重载的比较运算符不但能进行字符串全串比较还能进行字符串的个别
字符元素比较
命令行输出
Test "class CompStrTest":
Passed: 8 Failed: 0
贴剩下的Test.h 和Test.cpp
注意在比较
//: TestSuite:Test.h
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#ifndef TEST_H
#define TEST_H
#include <string>
#include <iostream>
#include <cassert>
using std::string;
using std::ostream;
using std::cout;
// fail_() has an underscore to prevent collision with
// ios::fail(). For consistency, test_() and succeed_()
// also have underscores.
#define test_(cond) \
do_test(cond, #cond, __FILE__, __LINE__)
#define fail_(str) \
do_fail(str, __FILE__, __LINE__)
namespace TestSuite {
class Test {
ostream* osptr;
long nPass;
long nFail;
// Disallowed:
Test(const Test&);
Test& operator=(const Test&);
protected:
void do_test(bool cond, const string& lbl,
const char* fname, long lineno);
void do_fail(const string& lbl,
const char* fname, long lineno);
public:
Test(ostream* osptr = &cout) {
this->osptr = osptr;
nPass = nFail = 0;
}
virtual ~Test() {}
virtual void run() = 0;
long getNumPassed() const { return nPass; }
long getNumFailed() const { return nFail; }
const ostream* getStream() const { return osptr; }
void setStream(ostream* osptr) { this->osptr = osptr; }
void succeed_() { ++nPass; }
long report() const;
virtual void reset() { nPass = nFail = 0; }
};
} // namespace TestSuite
#endif // TEST_H ///:~
//: TestSuite:Test.cpp {O}
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include "Test.h"
#include <iostream>
#include <typeinfo>
using namespace std;
using namespace TestSuite;
void Test::do_test(bool cond, const std::string& lbl,
const char* fname, long lineno) {
if(!cond)
do_fail(lbl, fname, lineno);
else
succeed_();
}
void Test::do_fail(const std::string& lbl,
const char* fname, long lineno) {
++nFail;
if(osptr) {
*osptr << typeid(*this).name()
<< "failure: (" << lbl << ") , " << fname
<< " (line " << lineno << ")" << endl;
}
}
long Test::report() const {
if(osptr) {
*osptr << "Test \"" << typeid(*this).name()
<< "\":\n\tPassed: " << nPass
<< "\tFailed: " << nFail
<< endl;
}
return nFail;
} ///:~
注意在比较运算符左右两边的自变量类型的灵活性
为了高效率地运行,对于字符串对象、引用文字和指向C语言风格的
字符串的指针等的直接比较,string类不创建临时string对象,而是
采用重载运算符进行
//: C03:Equivalence.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include <iostream>
#include <string>
using namespace std;
int main() {
string s2("That"), s1("This");
// The lvalue is a quoted literal
// and the rvalue is a string:
if("That" == s2)
cout << "A match" << endl;
// The left operand is a string and the right is
// a pointer to a C-style null terminated string:
if(s1 != s2.c_str())
cout << "No match" << endl;
getchar();
} ///:~
c_str()函数返回一个const char*,它指向一个C语言风格的具有 “空结束符”
的字符串,此字符串与string对象内容等价
在字符串的运算符中,不会找到逻辑非 ! 或逻辑比较运算符 && ||
输出
A match
No match
compare()采用函数能够提供远比非成员函数符集更复杂精密的比较
手段,它提供那些重载版本,可以比较
两个完整的字符串
一个字符串的某一部分与另一字符串的全部
两个字符串的子集
比较两个完整的字符串
//: C03:Compare.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Demonstrates compare() and swap().
#include <cassert>
#include <string>
using namespace std;
int main() {
string first("This");
string second("That");
assert(first.compare(first) == 0);
assert(second.compare(second) == 0);
// Which is lexically greater?
assert(first.compare(second) > 0);
assert(second.compare(first) < 0);
first.swap(second);
assert(first.compare(second) < 0);
assert(second.compare(first) > 0);
} ///:~
无输出 没有弹出异常对话框 正常运行
swap()函数所做的工作,交换其自身对象和产生的内容
为了对一个字符串或两个字符串中的字符子集进行比较,加上两个
产生,一个参数定义开始比较的位置, 另一个参数定义字符子集
考虑的字符个数
compare函数的重载
//: C03:Compare2.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Illustrate overloaded compare().
#include <cassert>
#include <string>
using namespace std;
int main() {
string first("This is a day that will live in infamy");
string second("I don't believe that this is what "
"I signed up for");
// Compare "his is" in both strings:
assert(first.compare(1, 7, second, 22, 7) == 0);
// Compare "his is a" to "his is w":
assert(first.compare(1, 9, second, 22, 9) < 0);
} ///:~
无输出,没有弹出异常对话框,所以 assert里面的条件都是对的
如果涉及字符串中的个别字符,可以使用C语言风格的数组索引语法
C++中字符串类提供一种s[n]表示法的替代方法,at()成员函数
如果不出意外事件,在C++中这两种索引机制产生的结果是一样的
//: C03:StringIndexing.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include <cassert>
#include <string>
using namespace std;
int main() {
string s("1234");
assert(s[1] == '2');
assert(s.at(1) == '2');
} ///:~
无输出,没有弹出异常对话框,所以 assert里面的条件都是对的
然而,数组索引下标表示[]与at()之间有一个重要的不同点
如果程序员想引用一个超过边界的 数组元素,at()将会抛出一个异常,
而普通的[]语法将让程序员自行决策
//: C03:BadStringIndexing.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include <exception>
#include <iostream>
#include <string>
using namespace std;
int main() {
string s("1234");
// at() saves you by throwing an exception:
try {
s.at(5);
} catch(exception& e) {
cerr << e.what() << endl;
}
getchar();
} ///:~
输出
invalid string position
有责任心的程序员不会去用有冒险的索引,程序员希望能够从自动
边界检查中受益
使用at()代替【】,就有机会从容地修复由于引用了不存在的数组元素
而存在的错误
at()成员抛出的是一个out_of_range类对象,它派生于std::exception