daily pastebin goal
77%
SHARE
TWEET

Untitled

a guest Jul 20th, 2018 53 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #pragma once
  2.  
  3. // Contains useful utility functions for std::string that are missing from the STL.
  4. // These are largely inspired by the python string functions and in fact try to
  5. // emulate them as close as is reasonably possible.
  6. //
  7.  
  8. #include <string>
  9. #include <vector>
  10. #include <algorithm>
  11. using std::string;
  12. using std::vector;
  13.  
  14. // trim leading whitespace
  15. static inline string ltrim(string s) {
  16.     s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); }));
  17.     return s;
  18. }
  19.  
  20. // trim trailing whitespace
  21. static inline string rtrim(string s) {
  22.     s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end());
  23.     return s;
  24. }
  25.  
  26. // trim leading and trailing whitespace
  27. static inline string trim(string s) {
  28.     return ltrim(rtrim(s));
  29. }
  30.  
  31.  
  32. // uppercase a string
  33. static inline string upper(string s) {
  34.     std::transform(s.begin(), s.end(), s.begin(), [](int ch) { return std::toupper(ch); });
  35.     return s;
  36. }
  37.  
  38.  
  39. // lowercase a string
  40. static inline string lower(string s) {
  41.     std::transform(s.begin(), s.end(), s.begin(), [](int ch) { return std::tolower(ch); });
  42.     return s;
  43. }
  44.  
  45.  
  46. // return true if string starts with another string
  47. static inline bool isprefix(string pre, string str) {
  48.     if (pre.size()  > str.size()) return false;
  49.     if (pre.size() == str.size()) return pre == str;
  50.     return str.find(pre) == 0;
  51. }
  52.  
  53.  
  54. // return true if string ends with another string
  55. static inline bool issuffix(string pre, string str) {
  56.     if (pre.size()  > str.size()) return false;
  57.     if (pre.size() == str.size()) return pre == str;
  58.     return str.rfind(pre) == (str.size()-pre.size());
  59. }
  60.  
  61.  
  62. // takes some iterable container of things that can be appended to a std::string and joins
  63. // them with the given token.  This can be a vector<string>, vector<const char*>,
  64. // list<string>, etc...
  65. //
  66. // @param tokens  random access iterable container of string-appendable things
  67. // @param sep     separator between tokens
  68. //
  69. template <typename T>
  70. static inline string join(const T &tokens, string sep=" ") {
  71.     string result;
  72.     for (auto iter=begin(tokens); iter != end(tokens); iter++) {
  73.         result += *iter;
  74.         if (iter != end(tokens)-1) {
  75.             result += sep;
  76.         }
  77.     }
  78.     return result;
  79. }
  80.  
  81.  
  82. // split a string into substrings using given delimiter string
  83. //
  84. // @param str    string to split
  85. // @param delim  delimiter string to split at, if empty any whitespace sequence
  86. // @param max    maximum number of words to return
  87. //
  88. static inline vector<string> split(string str, string delim=string(), ssize_t max=0) {
  89.     vector<string> tokens;
  90.  
  91.     if (delim == string()) {
  92.         // whitespace delimited split
  93.         const char* prev = str.c_str();
  94.         const char* next = prev;
  95.  
  96.         // skip any leading whitespace
  97.         while (isspace(*next)) { next++; }
  98.         prev = next;
  99.  
  100.         // grab tokens
  101.         while (*next && (!max || (ssize_t)tokens.size() < max)) {
  102.             // consume non-whitespace
  103.             while (*next && !isspace(*next)) { next++; }
  104.             tokens.emplace_back(
  105.                 prev, next-prev
  106.             );
  107.  
  108.             // consume whitespace
  109.             while (*next &&  isspace(*next)) { next++; }
  110.             prev = next;
  111.         }
  112.     } else {
  113.         // split on delimiter
  114.         const char* prev = str.c_str();
  115.         const char* next = prev;
  116.         while (!max || (ssize_t)tokens.size() < max) {
  117.             next = strstr(next, delim.c_str());
  118.             if (!next) {
  119.                 break;
  120.             }
  121.  
  122.             tokens.emplace_back(
  123.                 prev, next-prev
  124.             );
  125.             next += delim.size();
  126.             prev  = next;
  127.         }
  128.  
  129.         // the rest of the string
  130.         ssize_t size = (str.c_str() + str.size()) - prev;
  131.         if (size > 0) {
  132.             tokens.emplace_back(
  133.                 prev, size
  134.             );
  135.         }
  136.     }
  137.  
  138.     return tokens;
  139. }
  140.  
  141.  
  142. // replace occurences of one string with another
  143. //
  144. // @param olds  old string to search for
  145. // @param news  new string to replace with
  146. //
  147. static inline string replace(string str, string olds, string news) {
  148.     return join(split(str, olds), news);
  149. }
  150.  
  151.  
  152. #ifdef DOCTEST_LIBRARY_INCLUDED
  153.  
  154. TEST_SUITE("strutil") {
  155.     TEST_CASE("rtrim") {
  156.         REQUIRE(rtrim("testing")        == "testing");
  157.         REQUIRE(rtrim("testing ")       == "testing");
  158.         REQUIRE(rtrim("testing \t\n  ") == "testing");
  159.     }
  160.  
  161.     TEST_CASE("ltrim") {
  162.         REQUIRE(ltrim("testing")        == "testing");
  163.         REQUIRE(ltrim(" testing")       == "testing");
  164.         REQUIRE(ltrim(" \t\n  testing") == "testing");
  165.     }
  166.  
  167.     TEST_CASE("trim") {
  168.         REQUIRE(trim("testing")        == "testing");
  169.         REQUIRE(trim(" testing ")      == "testing");
  170.         REQUIRE(trim(" \ttesting\t ")  == "testing");
  171.     }
  172.  
  173.     TEST_CASE("upper") {
  174.         REQUIRE(upper("testing") == "TESTING");
  175.         REQUIRE(upper("TESTING") == "TESTING");
  176.     }
  177.  
  178.     TEST_CASE("lower") {
  179.         REQUIRE(lower("TESTING") == "testing");
  180.         REQUIRE(lower("testing") == "testing");
  181.     }
  182.  
  183.     TEST_CASE("isprefix") {
  184.         REQUIRE( isprefix("test",     "testing"));
  185.         REQUIRE( isprefix("testing",  "testing"));
  186.         REQUIRE(!isprefix("testing1", "testing"));
  187.         REQUIRE(!isprefix("test",     " testing"));
  188.     }
  189.    
  190.     TEST_CASE("issuffix") {
  191.         REQUIRE( issuffix("ting",     "testing"));
  192.         REQUIRE( issuffix("testing",  "testing"));
  193.         REQUIRE(!issuffix("testing1", "testing"));
  194.         REQUIRE(!issuffix("ting",     "testing "));
  195.     }
  196.  
  197.     TEST_CASE("join") {
  198.         REQUIRE(join(vector<string>{"one", "two", "three"})      == "one two three");
  199.         REQUIRE(join(vector<string>{"one", "two", "three"}, ",") == "one,two,three");
  200.     }
  201.  
  202.     TEST_CASE("split") {
  203.         // split on whitespace without any whitespace
  204.         REQUIRE(split("helloworld") == vector<string>{"helloworld"});
  205.  
  206.         // split on delimiter
  207.         REQUIRE(split(":one::two:::three", ":") == vector<string> {"", "one", "", "two", "", "", "three"});
  208.  
  209.         // split on whitespace
  210.         REQUIRE(split("one two three")                == vector<string> {"one", "two", "three" });
  211.         REQUIRE(split("\t\none two three")            == vector<string> {"one", "two", "three" });
  212.         REQUIRE(split("\t\none two three\t\n")        == vector<string> {"one", "two", "three" });
  213.         REQUIRE(split(" \t\none\t  two \n three\t\n") == vector<string> {"one", "two", "three" });
  214.  
  215.         // split on lines
  216.         REQUIRE(split("one\ntwo\nthree\n", "\n")      == vector<string> {"one", "two", "three" });
  217.         REQUIRE(split("one\ntwo\nthree",   "\n")      == vector<string> {"one", "two", "three" });
  218.     }
  219.  
  220.     TEST_CASE("replace") {
  221.         REQUIRE(replace("foobarfoozle", "foo", "baz") == "bazbarbazzle");
  222.         REQUIRE(replace("testing", "test", "fight")   == "fighting");
  223.     }
  224. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top