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";
  }
}