open_toontown_panda3d/dtool/src/dtoolutil/string_utils.cxx

393 lines
9.5 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file string_utils.cxx
* @author drose
* @date 1999-01-18
*/
#include "string_utils.h"
#include "textEncoder.h"
#include "pstrtod.h"
#include <ctype.h>
using std::string;
using std::wstring;
// Case-insensitive string comparison, from Stroustrup's C++ third edition.
// Works like strcmp().
int
cmp_nocase(const string &s, const string &s2) {
string::const_iterator p = s.begin();
string::const_iterator p2 = s2.begin();
while (p != s.end() && p2 != s2.end()) {
if (toupper(*p) != toupper(*p2)) {
return (toupper(*p) < toupper(*p2)) ? -1 : 1;
}
++p;
++p2;
}
return (s2.size() == s.size()) ? 0 :
(s.size() < s2.size()) ? -1 : 1; // size is unsigned
}
INLINE int
toupper_uh(int ch) {
return (ch == '_') ? '-' : toupper(ch);
}
int
cmp_nocase_uh(const string &s, const string &s2) {
string::const_iterator p = s.begin();
string::const_iterator p2 = s2.begin();
while (p != s.end() && p2 != s2.end()) {
if (toupper_uh(*p) != toupper_uh(*p2)) {
return (toupper_uh(*p) < toupper_uh(*p2)) ? -1 : 1;
}
++p;
++p2;
}
return (s2.size() == s.size()) ? 0 :
(s.size() < s2.size()) ? -1 : 1; // size is unsigned
}
/**
* Returns the input string with all uppercase letters converted to lowercase.
*/
string
downcase(const string &s) {
string result;
result.reserve(s.size());
string::const_iterator p;
for (p = s.begin(); p != s.end(); ++p) {
result += tolower(*p);
}
return result;
}
/**
* Returns the input string with all lowercase letters converted to uppercase.
*/
string
upcase(const string &s) {
string result;
result.reserve(s.size());
string::const_iterator p;
for (p = s.begin(); p != s.end(); ++p) {
result += toupper(*p);
}
return result;
}
/**
* Divides the string into a number of words according to whitespace. The
* words vector should be cleared by the user before calling; otherwise, the
* list of words in the string will be appended to the end of whatever was
* there before.
*
* The return value is the number of words extracted.
*/
int
extract_words(const string &str, vector_string &words) {
int num_words = 0;
size_t pos = 0;
while (pos < str.length() && isspace((unsigned int)str[pos])) {
pos++;
}
while (pos < str.length()) {
size_t word_start = pos;
while (pos < str.length() && !isspace((unsigned int)str[pos])) {
pos++;
}
words.push_back(str.substr(word_start, pos - word_start));
num_words++;
while (pos < str.length() && isspace((unsigned int)str[pos])) {
pos++;
}
}
return num_words;
}
/**
* Divides the string into a number of words according to whitespace. The
* words vector should be cleared by the user before calling; otherwise, the
* list of words in the string will be appended to the end of whatever was
* there before.
*
* The return value is the number of words extracted.
*/
int
extract_words(const wstring &str, pvector<wstring> &words) {
int num_words = 0;
size_t pos = 0;
while (pos < str.length() && TextEncoder::unicode_isspace(str[pos])) {
pos++;
}
while (pos < str.length()) {
size_t word_start = pos;
while (pos < str.length() && !TextEncoder::unicode_isspace(str[pos])) {
pos++;
}
words.push_back(str.substr(word_start, pos - word_start));
num_words++;
while (pos < str.length() && TextEncoder::unicode_isspace(str[pos])) {
pos++;
}
}
return num_words;
}
/**
* Chops the source string up into pieces delimited by any of the characters
* specified in delimiters. Repeated delimiter characters represent zero-
* length tokens.
*
* It is the user's responsibility to ensure the output vector is cleared
* before calling this function; the results will simply be appended to the
* end of the vector.
*/
void
tokenize(const string &str, vector_string &words, const string &delimiters,
bool discard_repeated_delimiters) {
size_t p = 0;
while (p < str.length()) {
size_t q = str.find_first_of(delimiters, p);
if (q == string::npos) {
if (q - p || !discard_repeated_delimiters){
words.push_back(str.substr(p));
}
return;
}
if (q - p || !discard_repeated_delimiters){
words.push_back(str.substr(p, q - p));
}
p = q + 1;
}
words.push_back(string());
}
/**
* Chops the source string up into pieces delimited by any of the characters
* specified in delimiters. Repeated delimiter characters represent zero-
* length tokens.
*
* It is the user's responsibility to ensure the output vector is cleared
* before calling this function; the results will simply be appended to the
* end of the vector.
*/
void
tokenize(const wstring &str, pvector<wstring> &words, const wstring &delimiters,
bool discard_repeated_delimiters) {
size_t p = 0;
while (p < str.length()) {
size_t q = str.find_first_of(delimiters, p);
if (q == string::npos) {
if (q - p || !discard_repeated_delimiters){
words.push_back(str.substr(p));
}
return;
}
if (q - p || !discard_repeated_delimiters){
words.push_back(str.substr(p, q - p));
}
p = q + 1;
}
words.push_back(wstring());
}
/**
* Returns a new string representing the contents of the given string with the
* leading whitespace removed.
*/
string
trim_left(const string &str) {
size_t begin = 0;
while (begin < str.size() && isspace((unsigned int)str[begin])) {
begin++;
}
return str.substr(begin);
}
/**
* Returns a new string representing the contents of the given string with the
* leading whitespace removed.
*/
wstring
trim_left(const wstring &str) {
size_t begin = 0;
while (begin < str.size() && TextEncoder::unicode_isspace(str[begin])) {
begin++;
}
return str.substr(begin);
}
/**
* Returns a new string representing the contents of the given string with the
* trailing whitespace removed.
*/
string
trim_right(const string &str) {
size_t begin = 0;
size_t end = str.size();
while (end > begin && isspace((unsigned int)str[end - 1])) {
end--;
}
return str.substr(begin, end - begin);
}
/**
* Returns a new string representing the contents of the given string with the
* trailing whitespace removed.
*/
wstring
trim_right(const wstring &str) {
size_t begin = 0;
size_t end = str.size();
while (end > begin && TextEncoder::unicode_isspace(str[end - 1])) {
end--;
}
return str.substr(begin, end - begin);
}
/**
* Returns a new string representing the contents of the given string with
* both leading and trailing whitespace removed.
*/
string
trim(const string &str) {
size_t begin = 0;
while (begin < str.size() && isspace((unsigned int)str[begin])) {
begin++;
}
size_t end = str.size();
while (end > begin && isspace((unsigned int)str[end - 1])) {
end--;
}
return str.substr(begin, end - begin);
}
/**
* Returns a new string representing the contents of the given string with
* both leading and trailing whitespace removed.
*/
wstring
trim(const wstring &str) {
size_t begin = 0;
while (begin < str.size() && TextEncoder::unicode_isspace(str[begin])) {
begin++;
}
size_t end = str.size();
while (end > begin && TextEncoder::unicode_isspace(str[end - 1])) {
end--;
}
return str.substr(begin, end - begin);
}
/**
* A string-interface wrapper around the C library strtol(). This parses the
* ASCII representation of an integer, and then sets tail to everything that
* follows the first valid integer read. If, on exit, str == tail, there was
* no valid integer in the source string; if !tail.empty(), there was garbage
* after the integer.
*
* It is legal if str and tail refer to the same string.
*/
int
string_to_int(const string &str, string &tail) {
const char *nptr = str.c_str();
char *endptr;
int result = strtol(nptr, &endptr, 10);
tail = endptr;
return result;
}
/**
* Another flavor of string_to_int(), this one returns true if the string is a
* perfectly valid integer (and sets result to that value), or false
* otherwise.
*/
bool
string_to_int(const string &str, int &result) {
string tail;
result = string_to_int(str, tail);
return tail.empty();
}
/**
* A string-interface wrapper around the C library strtol(). This parses the
* ASCII representation of an floating-point number, and then sets tail to
* everything that follows the first valid integer read. If, on exit, str ==
* tail, there was no valid integer in the source string; if !tail.empty(),
* there was garbage after the number.
*
* It is legal if str and tail refer to the same string.
*/
double
string_to_double(const string &str, string &tail) {
const char *nptr = str.c_str();
char *endptr;
double result = pstrtod(nptr, &endptr);
tail = endptr;
return result;
}
/**
* Another flavor of string_to_double(), this one returns true if the string
* is a perfectly valid number (and sets result to that value), or false
* otherwise.
*/
bool
string_to_double(const string &str, double &result) {
string tail;
result = string_to_double(str, tail);
return tail.empty();
}
/**
*
*/
bool
string_to_float(const string &str, float &result) {
string tail;
result = (float)string_to_double(str, tail);
return tail.empty();
}
/**
*
*/
bool
string_to_stdfloat(const string &str, PN_stdfloat &result) {
string tail;
result = (PN_stdfloat)string_to_double(str, tail);
return tail.empty();
}