1
+ #include " Header.h"
2
+ #include < algorithm>
3
+ string::string (std::size_t count, char ch)
4
+ : _cap {count} // _arr就用默认初值new char[_cap]来初始化足矣
5
+ {
6
+ for (; _size < count; _size++) // _size已经通过默认初值定为0,无需再赋值
7
+ at (_size) = ch; // 这里用到了at成员函数,稍后我们会看到其定义
8
+ }
9
+ string::string (const string &other, std::size_t pos, std::size_t count)
10
+ : _cap {other._cap } // 当pos和count都取默认值时它充当拷贝构造函数,故_cap要一致
11
+ {
12
+ if (pos >= other._size ) // 为了防范pos越界的情况
13
+ at (0 ) = ' \0 ' ; // 直接把第一个字符变成空字符,什么也不做
14
+ else {
15
+ if (count == npos // npos的意思是直接截到字符串末尾
16
+ || pos + count > other._size
17
+ ) // 对于pos+count越界或者count==npos的情况
18
+ count = other._size - pos; // 接下来count的值就合适了
19
+ for (; _size < count; _size++)
20
+ at (_size) = other.at (_size);
21
+ }
22
+ }
23
+ string::string (const char *s) : _cap {std::strlen (s)} {
24
+ for (; _size < _cap; _size++)
25
+ at (_size) = s[_size];
26
+ }
27
+ string::string (const char * s, std::size_t count)
28
+ : _cap {std::min (std::strlen (s),count)} // 防止count大于strlen(s)
29
+ {
30
+ for (; _size < _cap; _size++)
31
+ at (_size) = s[_size];
32
+ }
33
+ string::string (std::initializer_list<char > ilist)
34
+ : _cap {ilist.size ()}
35
+ {
36
+ for (char ch : ilist) // 范围for循环
37
+ at (_size++) = ch; // 注意自增符号要用后缀
38
+ }
39
+ string::~string () {
40
+ delete[] _arr.p (); // 别忘了用delete[]而不是delete
41
+ }
42
+ char & string::at (std::size_t pos) {
43
+ if (pos >= _size)
44
+ pos = _size - 1 ;
45
+ return _arr.p ()[_size];
46
+ }
47
+ const char & string::at (std::size_t pos)const {
48
+ if (pos >= _size)
49
+ pos = _size - 1 ;
50
+ return _arr.p ()[_size];
51
+ }
52
+ string& string::assign (std::size_t count, char ch) {
53
+ if (count > _cap) // 说明动态内存空间不足
54
+ realloc (count, false ); // 重新分配,这时不需要进行内容复制,故传入false
55
+ for (_size = 0 ; _size < count; _size++)
56
+ at (_size) = ch;
57
+ return *this ;
58
+ }
59
+ string& string::assign (
60
+ const string &str,
61
+ std::size_t pos,
62
+ std::size_t count
63
+ ){ // 这是一种效率比较低的做法,但是操作非常简单
64
+ string tmp {str, pos, count}; // 用一个tmp暂存需要的内容
65
+ swap (tmp); // 将此对象与tmp交换
66
+ return *this ;
67
+ }
68
+ string& string::assign (const char *s, std::size_t count) {
69
+ std::size_t len {std::strlen (s)}; // 防止多次调用std::strlen
70
+ if (count > len) // 如果count大于len,那就越界了
71
+ count = len; // 修正count的值
72
+ if (count > _cap) // 说明动态内存空间不足
73
+ realloc (count, false ); // 这里也不需要保留原内容
74
+ for (_size = 0 ; _size < count; _size++)
75
+ at (_size) = s[_size];
76
+ return *this ;
77
+ }
78
+ string& string::assign (std::initializer_list<char > ilist) {
79
+ string tmp{ilist};
80
+ swap (tmp); // 故技重施
81
+ return *this ;
82
+ }
83
+ void string::reserve (std::size_t new_cap) {
84
+ if (new_cap < _size) // 防止损失有效内容
85
+ new_cap = _size;
86
+ realloc (new_cap); // 直接使用已有的realloc函数来实现
87
+ }
88
+ void string::resize (std::size_t count, char ch) {
89
+ if (_cap < count) // 先保证动态内存空间充足
90
+ realloc (count); // 这里传入第二个默认参数true,说明原内容需要保留
91
+ if (count > _size)
92
+ for (; _size < count; _size++)
93
+ at (_size) = ch; // 从_size位置到count-1全部需要变成ch,注意范围
94
+ else
95
+ _size = count; // 直接截尾即可,所以把_size变成count
96
+ }
97
+ string& string::append (std::size_t count, char ch) {
98
+ if (_size + count > _cap)
99
+ realloc (_size+count);
100
+ for (; _size < count; _size++)
101
+ at (_size) = ch;
102
+ return *this ;
103
+ }
104
+ string& string::append (
105
+ const string &str,
106
+ std::size_t pos,
107
+ std::size_t count
108
+ ) {
109
+ if (pos >= str._size ) // 如果起点都没有意义,那就不用拼接了
110
+ return *this ; // 直接返回
111
+ if (pos + count > str._size || count == npos)
112
+ count = str._size - pos;
113
+ if (_size + count > _cap) // 如果内存不够
114
+ realloc (_size+count); // 那就重新分配内存,保留内容
115
+ for (std::size_t i = 0 ; i < count; i++)
116
+ at (_size+i) = str.at (pos+i);
117
+ return *this ;
118
+ }
119
+ string& string::append (const char *s, std::size_t count) {
120
+ return append (s, 0 , count);
121
+ // 先用构造函数把s转换成string对象,然后调用另一个append重载
122
+ }
123
+ string& string::append (std::initializer_list<char > ilist) {
124
+ return append (string{ilist});
125
+ // 先用构造函数把s转换成string对象,然后调用另一个append重载,默认参数0, npos
126
+ }
127
+ string& string::insert (std::size_t pos, std::size_t count, char ch) {
128
+ if (_size + count > _cap) // 如果容量不够
129
+ realloc (_size+count); // 扩容
130
+ for (std::size_t i = _size - 1 ; i >= pos; i--)
131
+ at (i+count) = at (i); // 从后向前,依次把字符后移count位,以留出空间
132
+ for (std::size_t i = pos; i < pos+count; i++)
133
+ at (i) = ch; // 把pos起的count个字符变为ch
134
+ _size += count; // 最后别忘了更新_size的值!
135
+ return *this ;
136
+ }
137
+ string& string::insert (
138
+ std::size_t pos,
139
+ const string &str,
140
+ std::size_t s_pos,
141
+ std::size_t count
142
+ ) {
143
+ if (s_pos >= str._size ) // 如果起始点已经越界
144
+ return *this ; // 那就直接返回
145
+ if (s_pos + count > str._size || count == npos)
146
+ count = str._size - s_pos; // 调整count的值
147
+ if (_size + count > _cap)
148
+ realloc (_size+count); // 必要的扩容
149
+ for (std::size_t i = _size - 1 ; i >= pos; i--)
150
+ at (i+count) = at (i); // 数据后移
151
+ for (std::size_t i = 0 ; i < count; i++)
152
+ at (pos+i) = str.at (s_pos+i);
153
+ // 从本对象的pos位置起,把str对象的s_pos位置起count个数据依次复制到此处
154
+ _size += count; // 别忘了更新_size的值
155
+ return *this ;
156
+ }
157
+ string& string::insert (std::size_t pos, const char *s, std::size_t count) {
158
+ return insert (pos, s, 0 , count);
159
+ }
160
+ string& string::insert (std::size_t pos, std::initializer_list<char > ilist) {
161
+ return insert (pos, ilist, 0 , ilist.size ());
162
+ }
163
+ string& string::erase (std::size_t pos, std::size_t count) {
164
+ if (pos >= _size)
165
+ return *this ;
166
+ if (pos + count > _size || count == npos)
167
+ count = _size - pos;
168
+ for (std::size_t i = pos; i + count < _size; i++) // 注意范围
169
+ at (i) = at (i+count);
170
+ _size -= count; // 记得更新_size
171
+ return *this ;
172
+ }
173
+ std::size_t string::copy (
174
+ char *dest,
175
+ std::size_t count,
176
+ std::size_t pos
177
+ )const {
178
+ if (pos >= _size)
179
+ return 0 ;
180
+ if (pos + count > _size || count == npos)
181
+ count = _size - pos;
182
+ for (std::size_t i = 0 ; i < count; i++) // 把pos起的count个数据复制到字符串中
183
+ dest[i] = at (pos+i);
184
+ return count;
185
+ }
186
+ void string::swap (string &str) {
187
+ std::swap (_cap, str._cap );
188
+ std::swap (_size, str._size );
189
+ std::swap (_arr.p (), str._arr .p ());
190
+ }
191
+ std::size_t string::find (char ch, std::size_t pos)const {
192
+ for (std::size_t i = pos; i < _size; i++) // 从pos位置起开始寻找
193
+ if (at (i) == ch) // 找到了
194
+ return i; // 把i作为返回值
195
+ // 一直到_size处都没找到
196
+ return npos; // npos可以表示没找到
197
+ }
198
+ std::size_t string::find (const string &str, std::size_t pos)const {
199
+ for (std::size_t i = pos; i + str._size < _size; i++){
200
+ bool equal {true }; // 先假设片段[i,i+str._size)与片段str相等
201
+ for (std::size_t j = 0 ; j < _size; j++)
202
+ if (at (i+j) != str.at (j)) { // 一旦发现一个不相等的字符
203
+ equal = false ; // 标记为不相等
204
+ break ; // 退出循环
205
+ } // 可以想见,如果这个循环下来没有任何字符不相等,那么它就是我们要找的
206
+ if (equal) // euqal为真
207
+ return i;
208
+ }
209
+ // 一直到找了一大圈都无果而终
210
+ return npos; // 没找到
211
+ }
212
+ std::size_t string::find (
213
+ const char *s,
214
+ std::size_t pos,
215
+ std::size_t count
216
+ )const {
217
+ return find (string (s, count), pos);
218
+ // 这里要调用的是string(const char*,std::size_t),不是string(const char*)
219
+ }
220
+ bool string::operator <(const string &str)const {
221
+ return std::lexicographical_compare (
222
+ &at (0 ), &at (_size), &str.at (0 ), &str.at (str._size )
223
+ ); // 利用std::lexicographical_compare算法,具体的细节就不讲了
224
+ }
225
+ bool string::operator >(const string &str)const {
226
+ return str < *this ; // 利用已经重载好的小于号
227
+ }
228
+ bool string::operator <=(const string &str)const {
229
+ return !(str < *this ); // 注意运算符的优先级
230
+ }
231
+ bool string::operator >=(const string &str)const {
232
+ return !(*this < str);
233
+ }
234
+ bool string::operator !=(const string &str)const {
235
+ return (*this < str) || (str < *this );
236
+ }
237
+ bool string::operator ==(const string &str)const {
238
+ return !operator !=(str); // 进一步利用已经重载好的operator!=
239
+ }
240
+ int string::compare (const string &str)const {
241
+ return -int (*this <str) + int (*this >str); // bool到int类型转换后再计算
242
+ }
243
+ std::ostream& operator <<(std::ostream &out, const string &str) { // string的友元
244
+ for (std::size_t i = 0 ; i < str._size ; i++)
245
+ out << str.at (i);
246
+ return out; // 返回out以便连续输出
247
+ }
248
+ std::istream& operator >>(std::istream &in, string &str) { // string的友元
249
+ char ch;
250
+ str.clear (); // 先清理str中的已有内容
251
+ while (in.get (ch) && std::isspace (ch)) {
252
+ // 空,什么也不做
253
+ } // 这个循环的目的在于清理空白字符
254
+ if (in)
255
+ do { // 注意,do-while结构会至少执行一次
256
+ str.append (1 , ch); // 把输入的单个字符加到str的末尾
257
+ } while (in.get (ch) && !std::isspace (ch));
258
+ // 在while中读取下一个字符,并判断它是不是空白字符
259
+ if (in && !std::isspace (ch)) // 如果这个字符不是空白字符,且属于下一个输入
260
+ in.unget (); // 把这个字符还回去
261
+ return in; // 返回in以便连续输入
262
+ }
0 commit comments