|
1 #ifndef STRINGUTILS_H__ 2 #define STRINGUTILS_H__ 3 4 #include <sstream> 5 #include <string> 6 #include <vector> 7 #include <algorithm> 8 #include <stdarg.h> 9 10 /** 11 * Collection of various helper methods for strings. 12 * 13 * \sa std::string 14 * 15 * \todo Test, test, test! 16 */ 17 namespace StringUtils { 18 19 /** 20 * Converts the string \a str to lowercase. 21 * \param str String to convert. 22 * \return Lowercase version of \a str. 23 */ 24 static std::string lowercase(const std::string& str) { 25 std::string toReturn(str); 26 std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::tolower); 27 return toReturn; 28 }; 29 /** 30 * Converts the string \a str to uppercase. 31 * \param str String to convert. 32 * \return Uppercase version of \a str. 33 */ 34 static std::string uppercase(const std::string& str) { 35 std::string toReturn(str); 36 std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::toupper); 37 return toReturn; 38 }; 39 /** 40 * Splits \a str into a vector of strings representing float values. 41 * Floats formatted as [-][0-9]*.[0-9]* are considered, all other characters in between are ignored. 42 * 43 * \param str Input string to parse. 44 * 45 * \note TODO: The detection algorithm is a litte simplified and will not yield correct results 46 * in every case. 47 **/ 48 static std::vector<std::string> parseFloats(const std::string& str){ 49 static const std::string floatCharacters("0123456789.-"); 50 std::vector<std::string> toReturn; 51 size_t strpos = 0; 52 size_t endpos = 0; 53 // we just started or just finished parsing an entry, check if finished and skip to beginning of next entry 54 while ((endpos != std::string::npos) && (strpos = str.find_first_of(floatCharacters, strpos)) != std::string::npos) { 55 // strpos currently points to the beginning of a float, now find its end 56 endpos = str.find_first_not_of(floatCharacters, strpos + 1); 57 // extract float 58 std::string token = str.substr(strpos, endpos - strpos); 59 // sanity checks 60 size_t signPos = token.rfind('-'); 61 if (signPos == 0 || signPos == std::string::npos) { // sign only allowed at beginning 62 if (token.find('.') == token.rfind('.')) { // only one . allowed 63 toReturn.push_back(token); 64 } 65 } 66 strpos = endpos + 1; 67 } 68 return toReturn; 69 }; 70 /** 71 * Replaces all occurrences of \a from in \a str with \a to. 72 * \param str String to perform replacement on. 73 * \param from String to be replaced. 74 * \param to String replace. 75 * \return \a str with all occurrences of \a from replaced with \a to. 76 */ 77 static std::string replaceAll(const std::string& str, const std::string& from, const std::string& to) 78 { 79 std::string toReturn(str); 80 std::string::size_type strpos = 0; 81 std::string::size_type foundpos; 82 while ((foundpos = toReturn.find(from, strpos)) != std::string::npos) { 83 toReturn.replace(foundpos, from.size(), to); 84 strpos = foundpos + to.size(); 85 } 86 return toReturn; 87 }; 88 static bool replace(std::string& str, const std::string& from, const std::string& to) { 89 size_t start_pos = str.find(from); 90 if (start_pos == std::string::npos) 91 return false; 92 str.replace(start_pos, from.length(), to); 93 return true; 94 }; 95 96 static bool replaceLast(std::string& str, const std::string& from, const std::string& to) { 97 size_t start_pos = str.rfind(from); 98 if (start_pos == std::string::npos) 99 return false; 100 str.replace(start_pos, from.length(), to); 101 return true; 102 }; 103 /** 104 * Splits the string \a str into pieces separated by the delimiters in \a delimiter. 105 * \param str String to split. 106 * \param delimiter Set of delimiters. 107 * \return Vector of the split substrings. 108 */ 109 static std::vector<std::string> split(const std::string& line, const std::string& delimiter) { 110 std::vector<std::string> toReturn; 111 std::string::size_type linepos = 0; 112 std::string::size_type endpos = 0; 113 // we are at the beginning of an entry, skip whitespace and check if not already reached end of line 114 while (endpos != std::string::npos) { 115 endpos = line.find_first_of(delimiter, linepos); 116 toReturn.push_back(line.substr(linepos, endpos - linepos)); 117 linepos = endpos + 1; 118 } 119 return toReturn; 120 }; 121 template<class T> 122 static std::vector<T> splitStringT(const std::string& line, const std::string& delimiter) { 123 std::vector<T> toReturn; 124 std::string::size_type linepos = 0; 125 std::string::size_type endpos = 0; 126 // we are at the beginning of an entry, skip whitespace and check if not already reached end of line 127 while (endpos != std::string::npos) { 128 endpos = line.find_first_of(delimiter, linepos); 129 toReturn.push_back(StringUtils::fromString<T>(line.substr(linepos, endpos - linepos))); 130 linepos = endpos + 1; 131 } 132 return toReturn; 133 }; 134 /** 135 * Trims the string \a str. 136 * All leading and trailing occurrences of the characters in \a whitespace will be removed. 137 * 138 * \param str The string to trim. 139 * \param whitespace Set of whitespace characters which shall be removed at the beginning and the end. 140 * \return The original string without leading and trailing whitespace. 141 */ 142 static std::string trim(const std::string& str, const std::string& whitespace = " \t\n\r\0\x0B") { 143 std::string::size_type first = str.find_first_not_of(whitespace); 144 if (first == std::string::npos) { 145 return ""; 146 } 147 else { 148 std::string::size_type last = str.find_last_not_of(whitespace); 149 return str.substr(first, last - first + 1); 150 } 151 }; 152 /** 153 * Splits the string \a str into trimmed pieces separated by the delimiters in \a delimiter. 154 * Delimiters in quoted strings (\a quotes) will be ignored, double quotes within quoted strings will be 155 * interpreted as literal quotes. Each token will be trimmed. 156 * 157 * \param str String to split. 158 * \param delimiter Set of delimiters. 159 * \param quotes Character used for quotes. 160 * \param whitespace Set of whitespace characters which shall be removed during trimming. 161 * \return Vector of the split substrings. 162 */ 163 static std::vector<std::string> splitStringsafe(const std::string& str, const std::string& delimiter, char quotes = '"', const std::string& whitespace = " \t\n\r\0\x0B") 164 { 165 std::vector<std::string> toReturn; 166 std::string::size_type strpos = 0; 167 std::string::size_type endpos = 0; 168 // we are at the beginning of an entry, skip whitespace and check if not already reached end of str 169 while ((endpos != std::string::npos) && (strpos = str.find_first_not_of(whitespace, strpos)) != std::string::npos) { 170 // now strpos points to the first non blank character, here starts the entry 171 // check whether there are quotes 172 if (str[strpos] == quotes) { 173 // find position of closing quotes 174 endpos = str.find_first_of('"', strpos + 1); 175 std::string toPush = str.substr(strpos + 1, endpos - strpos - 1); 176 // ensure we haven't found double quotes ("") which shall be resolved to one double quote in resulting string 177 while ((endpos != std::string::npos) && (endpos + 1 < str.length()) && (str[endpos + 1] == '"')) { 178 strpos = endpos + 1; 179 endpos = str.find_first_of('"', endpos + 2); 180 toPush.append(str.substr(strpos, endpos - strpos)); 181 } 182 // push string in quotes onto toReturn 183 toReturn.push_back(trim(toPush, whitespace)); 184 // ignore everything until next delimiter 185 endpos = str.find_first_of(delimiter, endpos); 186 } 187 // ok, this entry is not in quotes - just push everything until next delimiter onto toReturn 188 else { 189 endpos = str.find_first_of(delimiter, strpos); 190 toReturn.push_back(trim(str.substr(strpos, endpos - strpos), whitespace)); 191 } 192 strpos = endpos + 1; 193 } 194 return toReturn; 195 }; 196 197 /** 198 * Converts the value \a value to a string. 199 * \param value The value to convert, must be compatible with std::stringstream. 200 * \return A string representation of \a value. 201 */ 202 template<class T> 203 static std::string toString(const T& value) { 204 std::ostringstream stream; 205 stream << value; 206 return stream.str(); 207 }; 208 /** 209 * Converts the string \a str to its original value. 210 * \param str The string to convert 211 * \return The back-converted value of \a str, type must be compatible with std::stringstream. 212 * \throw tgt::Exception on conversion failure 213 */ 214 template<class T> 215 static T fromString(const std::string& str) { 216 T toReturn; 217 std::istringstream stream; 218 stream.str(str); 219 try 220 { 221 stream >> toReturn; 222 } 223 catch (std::exception& ex) 224 { 225 std::cout << "Failed to convert string '" << str << "'" << " exception=" << ex.what() << std::endl; 226 return NULL; 227 } 228 return toReturn; 229 }; 230 /** 231 * Joins the substrings in \a tokens together using \a delimiter in between. 232 * \param tokens List of substrings to join. 233 * \param delimiter Delimiter which shall be placed between the substrings. 234 * \return A string containing the joined substrings. 235 */ 236 template<typename T> 237 static std::string join(const std::vector<T>& tokens, const std::string& delimiter) { 238 if (tokens.empty()) 239 return ""; 240 std::stringstream s; 241 s << tokens[0]; 242 for (std::vector<T>::size_type i = 1; i < tokens.size(); ++i) 243 s << delimiter << tokens[i]; 244 return s.str(); 245 }; 246 247 248 static bool startsWith(const std::string &str, const std::string &prefix) { 249 return str.size() >= prefix.size() && 250 str.compare(0, prefix.size(), prefix) == 0; 251 }; 252 static bool endsWith(const std::string &str, const std::string &suffix) { 253 return str.size() >= suffix.size() && 254 str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; 255 }; 256 257 static std::string format(const char* format, )//一个参数数量可变的函数 258 { 259 std::string ret; 260 va_list ap;//新特性 261 va_start(ap, format); 262 char* buf = (char*)malloc(1024 * 100); 263 if (buf != nullptr) 264 { 265 vsnprintf(buf, 1024 * 100, format, ap); 266 ret = buf; 267 free(buf); 268 } 269 va_end(ap); 270 return ret;//返回字符串 271 }; 272 }
|