String¶
Char to a string¶
#include <string>
int main(int argc, char *argv[]) {
// string(size_t n, char c)
std::string a(1, 'a');
}
#include <string>
int main(int argc, char *argv[]) {
std::string s;
s += 'a';
}
#include <string>
int main(int argc, char *argv[]) {
std::string s;
s = 'a';
}
C String to a String¶
#include <string>
int main(int argc, char *argv[]) {
char cstr[] = "hello cstr";
std::string s = cstr;
}
Split a String¶
// $ g++ --std=c++14 -Wall -Werror -g -O3 split.cpp
// $ ./a.out
// abc
// def
// ghi
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> split(const string &str, char delimeter) {
string s = str;
vector<string> out;
size_t pos = 0;
while((pos = s.find(delimeter)) != string::npos) {
string token = s.substr(0, pos);
out.emplace_back(token);
s.erase(0, pos + 1);
}
out.emplace_back(s);
return out;
}
int main(int argc, char *argv[]) {
string s = "abc,def,ghi";
vector<string> v = split(s, ',');
for (const auto &c : v) {
cout << c << "\n";
}
}
Using istream
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
template<char delimiter>
class String : public string
{
friend istream &operator>>( istream &is, String &out) {
std::getline(is, out, delimiter);
return is;
}
};
int main(int argc, char *argv[]) {
std::string text = "abc,def,ghi";
istringstream iss(text);
vector<string> out((istream_iterator<String<','>>(iss)),
istream_iterator<String<','>>());
for (const auto &c : out) {
cout << c << "\n";
}
}
Using std::getline
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
string in = "abc,def,ghi";
vector<string> out;
string token;
std::istringstream stream(in);
while (std::getline(stream, token, ',')) {
out.emplace_back(token);
}
for (const auto &c : out) {
cout << c << "\n";
}
}
Using boost
#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
using namespace std;
int main(int argc, char *argv[]) {
string in = "abc,def,ghi";
vector<string> out;
boost::split(out, in, [](char c) { return c == ','; });
for (const auto &s : out) {
cout << s << "\n";
}
}
Upper & Lower¶
// cc -std=c++17 -Wall -Werror -O3 a.cpp
#include <iostream>
#include <string>
#include <algorithm>
int main(int argc, char *argv[])
{
std::string s = "Hello World";
// to upper
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
std::cout << s << "\n";
// to lower
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
std::cout << s << "\n";
}
String Concat¶
Note that concatenating a string at the beginning is much slower than appending in the end. Although reserving space can speed up inserting a string in front of another one, the performance is still much slower than appending a string at the back.
#include <iostream>
#include <chrono>
constexpr int total = 100000;
using milliseconds = std::chrono::milliseconds;
template <typename F>
void profile(F &&func) {
const auto start = std::chrono::steady_clock::now();
func();
const auto end = std::chrono::steady_clock::now();
const auto d = end - start;
const auto mill = std::chrono::duration_cast<milliseconds>(d).count();
std::cout << mill << " ms\n";
}
int main(int argc, char *argv[]) {
profile([] {
std::string s;
for (int i = 0; i < total; ++i) {
s += 'a';
}
});
profile([] {
std::string s;
for (int i = 0; i < total; ++i) {
s = std::string(1, 'a') + s;
}
});
profile([] {
std::string s;
s.reserve(total+1);
for (int i = 0; i < total; ++i) {
s = std::string(1, 'a') + s;
}
});
}
// $ g++ -std=c++17 -Wall -Werror a.cc
// 0 ms
// 143 ms
// 110 ms
String Literals¶
#include <iostream>
#include <string>
#include <string_view>
int main(int argc, char *argv[]) {
using namespace std::literals;
auto s1 = "c string";
auto s2 = "std::string"s;
auto s3 = "std::string_view"sv;
std::cout << s1 << "\n";
std::cout << s2 << "\n";
std::cout << s3 << "\n";
}
String View¶
#include <iostream>
#include <string_view>
void f(std::string_view s) {
std::cout << s << "\n";
}
int main(int argc, char *argv[]) {
const std::string s = "foo";
// pass a const string is ok
f(s);
}
#include <iostream>
#include <string_view>
void f(std::string s) {
std::cout << s << "\n";
}
int main(int argc, char *argv[]) {
std::string_view s = "foo";
f(s); // compile error. cannot convert a string_view to a string
}
#include <iostream>
#include <string_view>
void f(std::string s) {
std::cout << s << "\n";
}
int main(int argc, char *argv[]) {
std::string_view s = "foo";
// we can cast a string_view to a string
f(static_cast<std::string>(s));
}
// string_view is not alway has null-terminated
#include <iostream>
#include <cstring>
#include <string_view>
int main(int argc, char *argv[]) {
char array[3] = {'B', 'a', 'r'};
std::string_view s(array, sizeof array);
// Dangerous!! ptr will access memory address larger than array+3
for (auto ptr = s.data(); !!ptr; ++ptr) {
std::cout << *ptr << "\n";
}
}