00001 // Filename: string_utils.cxx 00002 // Created by: drose (18Jan99) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "string_utils.h" 00020 00021 #include <ctype.h> 00022 00023 // Case-insensitive string comparison, from Stroustrup's C++ third edition. 00024 // Works like strcmp(). 00025 int 00026 cmp_nocase(const string &s, const string &s2) { 00027 string::const_iterator p = s.begin(); 00028 string::const_iterator p2 = s2.begin(); 00029 00030 while (p != s.end() && p2 != s2.end()) { 00031 if (toupper(*p) != toupper(*p2)) { 00032 return (toupper(*p) < toupper(*p2)) ? -1 : 1; 00033 } 00034 ++p; 00035 ++p2; 00036 } 00037 00038 return (s2.size() == s.size()) ? 0 : 00039 (s.size() < s2.size()) ? -1 : 1; // size is unsigned 00040 } 00041 00042 INLINE int 00043 toupper_uh(int ch) { 00044 return (ch == '_') ? '-' : toupper(ch); 00045 } 00046 00047 00048 int 00049 cmp_nocase_uh(const string &s, const string &s2) { 00050 string::const_iterator p = s.begin(); 00051 string::const_iterator p2 = s2.begin(); 00052 00053 while (p != s.end() && p2 != s2.end()) { 00054 if (toupper_uh(*p) != toupper_uh(*p2)) { 00055 return (toupper_uh(*p) < toupper_uh(*p2)) ? -1 : 1; 00056 } 00057 ++p; 00058 ++p2; 00059 } 00060 00061 return (s2.size() == s.size()) ? 0 : 00062 (s.size() < s2.size()) ? -1 : 1; // size is unsigned 00063 } 00064 00065 00066 00067 //////////////////////////////////////////////////////////////////// 00068 // Function: downcase 00069 // Description: Returns the input string with all uppercase letters 00070 // converted to lowercase. 00071 //////////////////////////////////////////////////////////////////// 00072 string 00073 downcase(const string &s) { 00074 string result; 00075 result.reserve(s.size()); 00076 string::const_iterator p; 00077 for (p = s.begin(); p != s.end(); ++p) { 00078 result += tolower(*p); 00079 } 00080 return result; 00081 } 00082 00083 //////////////////////////////////////////////////////////////////// 00084 // Function: upcase 00085 // Description: Returns the input string with all lowercase letters 00086 // converted to uppercase. 00087 //////////////////////////////////////////////////////////////////// 00088 string 00089 upcase(const string &s) { 00090 string result; 00091 result.reserve(s.size()); 00092 string::const_iterator p; 00093 for (p = s.begin(); p != s.end(); ++p) { 00094 result += toupper(*p); 00095 } 00096 return result; 00097 } 00098 00099 00100 //////////////////////////////////////////////////////////////////// 00101 // Function: extract_words 00102 // Description: Divides the string into a number of words according 00103 // to whitespace. The words vector should be cleared by 00104 // the user before calling; otherwise, the list of words 00105 // in the string will be appended to the end of whatever 00106 // was there before. 00107 // 00108 // The return value is the number of words extracted. 00109 //////////////////////////////////////////////////////////////////// 00110 int 00111 extract_words(const string &str, vector_string &words) { 00112 int num_words = 0; 00113 00114 size_t pos = 0; 00115 while (pos < str.length() && isspace((unsigned int)str[pos])) { 00116 pos++; 00117 } 00118 while (pos < str.length()) { 00119 size_t word_start = pos; 00120 while (pos < str.length() && !isspace((unsigned int)str[pos])) { 00121 pos++; 00122 } 00123 words.push_back(str.substr(word_start, pos - word_start)); 00124 num_words++; 00125 00126 while (pos < str.length() && isspace((unsigned int)str[pos])) { 00127 pos++; 00128 } 00129 } 00130 00131 return num_words; 00132 } 00133 00134 //////////////////////////////////////////////////////////////////// 00135 // Function: tokenize 00136 // Description: Chops the source string up into pieces delimited by 00137 // any of the characters specified in delimiters. 00138 // Repeated delimiter characters represent zero-length 00139 // tokens. 00140 // 00141 // It is the user's responsibility to ensure the output 00142 // vector is cleared before calling this function; the 00143 // results will simply be appended to the end of the 00144 // vector. 00145 //////////////////////////////////////////////////////////////////// 00146 void 00147 tokenize(const string &str, vector_string &words, const string &delimiters) { 00148 size_t p = 0; 00149 while (p < str.length()) { 00150 size_t q = str.find_first_of(delimiters, p); 00151 if (q == string::npos) { 00152 words.push_back(str.substr(p)); 00153 return; 00154 } 00155 words.push_back(str.substr(p, q - p)); 00156 p = q + 1; 00157 } 00158 words.push_back(string()); 00159 } 00160 00161 //////////////////////////////////////////////////////////////////// 00162 // Function: trim_left 00163 // Description: Returns a new string representing the contents of the 00164 // given string with the leading whitespace removed. 00165 //////////////////////////////////////////////////////////////////// 00166 string 00167 trim_left(const string &str) { 00168 size_t begin = 0; 00169 while (begin < str.size() && isspace((unsigned int)str[begin])) { 00170 begin++; 00171 } 00172 00173 return str.substr(begin); 00174 } 00175 00176 //////////////////////////////////////////////////////////////////// 00177 // Function: trim_right 00178 // Description: Returns a new string representing the contents of the 00179 // given string with the trailing whitespace removed. 00180 //////////////////////////////////////////////////////////////////// 00181 string 00182 trim_right(const string &str) { 00183 size_t begin = 0; 00184 size_t end = str.size(); 00185 while (end > begin && isspace((unsigned int)str[end - 1])) { 00186 end--; 00187 } 00188 00189 return str.substr(begin, end - begin); 00190 } 00191 00192 //////////////////////////////////////////////////////////////////// 00193 // Function: string_to_int 00194 // Description: A string-interface wrapper around the C library 00195 // strtol(). This parses the ASCII representation of an 00196 // integer, and then sets tail to everything that 00197 // follows the first valid integer read. If, on exit, 00198 // str == tail, there was no valid integer in the 00199 // source string; if !tail.empty(), there was garbage 00200 // after the integer. 00201 // 00202 // It is legal if str and tail refer to the same string. 00203 //////////////////////////////////////////////////////////////////// 00204 int 00205 string_to_int(const string &str, string &tail) { 00206 const char *nptr = str.c_str(); 00207 char *endptr; 00208 int result = strtol(nptr, &endptr, 10); 00209 tail = endptr; 00210 return result; 00211 } 00212 00213 //////////////////////////////////////////////////////////////////// 00214 // Function: string_to_int 00215 // Description: Another flavor of string_to_int(), this one returns 00216 // true if the string is a perfectly valid integer (and 00217 // sets result to that value), or false otherwise. 00218 //////////////////////////////////////////////////////////////////// 00219 bool 00220 string_to_int(const string &str, int &result) { 00221 string tail; 00222 result = string_to_int(str, tail); 00223 return tail.empty(); 00224 } 00225 00226 //////////////////////////////////////////////////////////////////// 00227 // Function: string_to_double 00228 // Description: A string-interface wrapper around the C library 00229 // strtol(). This parses the ASCII representation of an 00230 // floating-point number, and then sets tail to 00231 // everything that follows the first valid integer read. 00232 // If, on exit, str == tail, there was no valid integer 00233 // in the source string; if !tail.empty(), there was 00234 // garbage after the number. 00235 // 00236 // It is legal if str and tail refer to the same string. 00237 //////////////////////////////////////////////////////////////////// 00238 double 00239 string_to_double(const string &str, string &tail) { 00240 const char *nptr = str.c_str(); 00241 char *endptr; 00242 double result = strtod(nptr, &endptr); 00243 tail = endptr; 00244 return result; 00245 } 00246 00247 //////////////////////////////////////////////////////////////////// 00248 // Function: string_to_double 00249 // Description: Another flavor of string_to_double(), this one 00250 // returns true if the string is a perfectly valid 00251 // number (and sets result to that value), or false 00252 // otherwise. 00253 //////////////////////////////////////////////////////////////////// 00254 bool 00255 string_to_double(const string &str, double &result) { 00256 string tail; 00257 result = string_to_double(str, tail); 00258 return tail.empty(); 00259 } 00260 00261 //////////////////////////////////////////////////////////////////// 00262 // Function: string_to_float 00263 // Description: Another flavor of string_to_float(), this one 00264 // returns true if the string is a perfectly valid 00265 // number (and sets result to that value), or false 00266 // otherwise. 00267 //////////////////////////////////////////////////////////////////// 00268 bool 00269 string_to_float(const string &str, float &result) { 00270 string tail; 00271 result = (float)string_to_double(str, tail); 00272 return tail.empty(); 00273 }