/***************************************************************************
String.cpp - A C++ version of java.lang.String with added features
-------------------
begin : Sun Aug 31 2003
copyright : (C) 2003 by rizzix
email :
rizzixs@fastmail.fm
***************************************************************************/
#include "String.h"
// Constructors and Destructors
String::String()
{
len = 0;
str = new char[1];
}
String::String(const char* const pstr)
{
len = 0;
while (true) {
if (pstr != 0 && *(pstr + len) != '\0') {
len++;
} else {
break;
}
}
len += 1; // allocate space for '\0'
if (len != 0) {
str = new char[len];
for (int i = 0; i < len; i++)
str[i] = pstr[i];
str[len - 1] = '\0';
}
}
String::String(const String& pstr)
{
str = pstr.toCharArray();
len = pstr.length() + 1;
}
String::~String()
{
len = 0;
delete [] str;
}
// returns the length of the string
inline int String::length() const
{
return len - 1 ;
}
// returns a const char* const representation of the String
const char* const String::toString() const
{
return (const char* const) str;
}
// returns a new String object with the argument appended
String& String::concat(const char* const pstr) const
{
int argLength = 0; // length of the argument str
while (true) {
if (pstr != 0 && *(pstr + argLength) != '\0') {
argLength++;
} else {
break;
}
}
int newLength = length() + argLength; // length of the new concat str
newLength += 1; // allocate space for '\0'
char tmpStr[newLength];
if (newLength != 0) { // if there is something to add
for (int i = 0; i < length(); i++)
tmpStr[i] = str[i];
for (int i = 0; i + length() < newLength; i++)
tmpStr[i + length()] = pstr[i];
}
tmpStr[newLength - 1] = '\0';
return *(new String(tmpStr));
}
// returns a new String object with the argument appended
String& String::concat(const String& pstr) const
{
int newLength = length() + pstr.length() + 1;
char tmpStr[newLength];
if (newLength != 0) { // if there is something to add
for (int i = 0; i < length(); i++)
tmpStr[i] = str[i];
for (int i = 0; i + length() < newLength; i++)
tmpStr[i + length()] = pstr.charAt(i);
}
tmpStr[newLength - 1] = '\0';
return *(new String(tmpStr));
}
// returns true if ends with argument
bool String::endsWith(const String& pstr) const
{
if (pstr.length() > length()) return false;
return startsWith(pstr, length() - (length() - pstr.length()));
}
bool String::endsWith(const char* const pstr) const
{
bool matches = true;
int tmplen = 0;
while (true) {
if (pstr != 0 && *(pstr + tmplen) != '\0') {
tmplen++;
} else {
break;
}
}
if (tmplen > length()) return false;
for (int i = length() - 1; i >= length() - tmplen; i--)
if (charAt(i) != pstr[tmplen - ((length() - 1) - i) - 1]) {
matches = false;
break;
}
return matches;
}
// returns true if starts with argument String object
bool String::startsWith(const String& pstr) const
{
return startsWith(pstr, 0);
}
// returns true if starts with argument const char*
bool String::startsWith(const char* const pstr) const
{
return startsWith(pstr, 0);
}
// returns true if starts with argument String
// (from offset in this String object)
bool String::startsWith(const String& pstr, int offset) const
{
if (offset > length() || pstr.length() > (length() - offset))
return false;
bool matches = true;
for (int i = 0; i < pstr.length(); i++)
if (charAt(i + offset) != pstr.charAt(i)) {
matches = false;
break;
}
return matches;
}
// returns true if starts with argument const char*
// (from offset in this String object)
bool String::startsWith(const char* const pstr, int offset) const
{
bool matches = true;
int tmplen = 0;
while (true) {
if (pstr != 0 && *(pstr + tmplen) != '\0') {
tmplen++;
} else {
break;
}
}
if (offset > length() || tmplen > (length() - offset))
return false;
for (int i = 0; i < tmplen; i++)
if (charAt(i + offset) != pstr[i]) {
matches = false;
break;
}
return matches;
}
// returns 1 if greater, 0 if equals and -1 if less than
int String::compareTo(const String& pstr) const
{
if (pstr.length() > length()) return 1;
if (pstr.length() < length()) return -1;
int psum = 0, sum = 0;
for (int i = 0; i < pstr.length(); i++)
psum += (int) pstr.charAt(i);
for (int i = 0; i < length(); i++)
sum += (int) charAt(i);
if (psum > sum) {
return 1;
} else if (psum == sum) {
return 0;
} else {
return -1;
}
}
int String::compareTo(const char* const pstr) const
{
int psum = 0, sum = 0;
for (int i = 0; pstr[i] != '\0'; i++)
psum += (int) pstr[i];
for (int i = 0; i < length(); i++)
sum += (int) charAt(i);
if (psum > sum) {
return 1;
} else if (psum == sum) {
return 0;
} else {
return -1;
}
}
// same as compareTo, but ignoring the case
int String::compareToIgnoreCase(const String& pstr) const
{
if (pstr.length() > length()) return 1;
if (pstr.length() < length()) return -1;
int psum = 0, sum = 0;
for (int i = 0; i < pstr.length(); i++) {
if (pstr.charAt(i) >= 97 && pstr.charAt(i) <= 122) {
psum += (int) (pstr.charAt(i) - 32);
} else {
psum += (int) pstr.charAt(i);
}
}
for (int i = 0; i < length(); i++) {
if (charAt(i) >= 97 && charAt(i) <= 122) {
sum += (int) (charAt(i) - 32);
} else {
sum += (int) charAt(i);
}
}
if (psum > sum) {
return 1;
} else if (psum == sum) {
return 0;
} else {
return -1;
}
}
int String::compareToIgnoreCase(const char* const pstr) const
{
int psum = 0, sum = 0;
for (int i = 0; pstr[i] != '\0'; i++) {
if (pstr[i] >= 97 && pstr[i] <= 122) {
psum += (int) (pstr[i] - 32);
} else {
psum += (int) pstr[i];
}
}
for (int i = 0; i < length(); i++) {
if (charAt(i) >= 97 && charAt(i) <= 122) {
sum += (int) (charAt(i) - 32);
} else {
sum += (int) charAt(i);
}
}
if (psum > sum) {
return 1;
} else if (psum == sum) {
return 0;
} else {
return -1;
}
}
// returns true if this object's contents equals that of the argument
bool String::equals(const String& pstr) const
{
return (compareTo(pstr) == 0);
}
bool String::equals(const char* const pstr) const
{
return (compareTo(pstr) == 0);
}
// same as equals but ignoring the case
bool String::equalsIgnoreCase(const String& pstr) const
{
return (compareToIgnoreCase(pstr) == 0);
}
bool String::equalsIgnoreCase(const char* const pstr) const
{
return (compareToIgnoreCase(pstr) == 0);
}
// returns the index of char in the String, -1 if error
int String::indexOf(char ch) const
{
return indexOf(ch, 0);
}
// returns the index of char in the sting from fromIndex onwards, -1 if error
int String::indexOf(char ch, int fromIndex) const
{
if (fromIndex > length() || fromIndex < 0)
return -1;
int result = -1;
for (int i = fromIndex; i < length(); i++)
if (charAt(i) == ch) {
result = i;
break;
}
return result;
}
/*TODO: implement this
// returns the index of the substring pstr in the string, -1 if error
int String::indexOf(const String& pstr) const
{
}
int String::indexOf(const char* const pstr) const
{
}
// same as indexOf for substrings but from fromIndex onwards
int String::indexOf(const char* const pstr, int fromIndex) const
{
}
int String::indexOf(const String& pstr, int fromIndex) const
{
}
*/
// returns the index of char in the string,
// the string is read backwards. (this index is given as though you
// were reading the string forward, not backwards)
int String::lastIndexOf(char ch) const
{
return lastIndexOf(ch, length() - 1);
}
int String::lastIndexOf(char ch, int fromIndex) const
{
if (fromIndex > length() || fromIndex < 0)
return -1;
int result = -1;
for (int i = fromIndex; i >= 0; i--)
if (charAt(i) == ch) {
result = i;
break;
}
return result;
}
/*TODO: implement this
int String::lastIndexOf(const char* const pstr) const
{
}
int String::lastIndexOf(const char* const pstr, int fromIndex) const
{
}
int String::lastIndexOf(const String& pstr) const
{
}
int String::lastIndexOf(const String& pstr, int fromIndex) const
{
}
*/
// returns a new String that is a substring from beginIndex onwards,
// null if error
String* String::substring(int beginIndex) const
{
return substring(beginIndex, length() - 1);
}
// returns a new String that is a substring from beginIndex to endIndex,
// null if error
String* String::substring(int beginIndex, int endIndex) const
{
if (beginIndex > endIndex || beginIndex < 0 || beginIndex > length())
return (String*) 0;
if (endIndex < beginIndex || endIndex < 0 || endIndex > length())
return (String*) 0;
int pLength = endIndex - beginIndex + 2; // allocate space for '\0' aswell
char tmpStr[pLength];
for (int i = beginIndex; i <= endIndex; i++)
tmpStr[i - beginIndex] = charAt(i);
tmpStr[pLength - 1] = '\0';
return new String(tmpStr);
}
// returns a new String that is the UPPER case version of this string
String& String::toUpperCase() const
{
char tmpStr[length() + 1];
for (int i = 0; i < length(); i++) {
if (charAt(i) >= 97 && charAt(i) <= 122)
tmpStr[i] = (char) (charAt(i) - 32);
else
tmpStr[i] = charAt(i);
}
tmpStr[length()] = '\0';
return *(new String(tmpStr));
}
// returns a new String that is the lower case version of this string
String& String::toLowerCase() const
{
char tmpStr[length() + 1];
for (int i = 0; i < length(); i++) {
if (charAt(i) >= 65 && charAt(i) <= 90)
tmpStr[i] = (char) (charAt(i) + 32);
else
tmpStr[i] = charAt(i);
}
tmpStr[length()] = '\0';
return *(new String(tmpStr));
}
// returns a new String object that is a trimmed version of this string
String& String::trim() const
{
int begin = -1;
int end = length() + 1;
for (int i = 0; i < length(); i++)
if (charAt(i) != ' ') { // dot = space
begin = i; // "....test...."
break; // ^-- thats where begin points to
}
for (int i = length() - 1; i >= 0; i--)
if (charAt(i) != ' ') { // dot = space
end = i + 1; // "....test...."
break; // ^-- where end points to
}
int newLength = (end - begin) + 1;
if (end > begin) {
char tmpStr[newLength];
for (int i = 0; i < newLength; i++)
tmpStr[i] = charAt(begin + i);
tmpStr[newLength - 1] = '\0';
return *(new String(tmpStr));
} else { // if end <= begin then there is no str
return *(new String(*this)); // or there are only spaces, so return
} // a copy of what we have.
}
//returns a new char* that has the same contents as that of this string object
char* String::toCharArray() const
{
char* tmpStr = new char[length() + 1];
for (int i = 0; i < length(); i++)
tmpStr[i] = str[i];
tmpStr[length()] = '\0';
return tmpStr;
}
// returns the char at int index, returns -1 if out of bounds
char String::charAt(int index) const
{
if (index >= length() || index < 0)
return -1;
else
return str[index];
}
// returns a new string that has the same contents of this String object
// with oldChar replaced with newChar
String& String::replace(char oldChar, char newChar) const
{
char tmpStr[length() + 1];
for (int i = 0; i < length(); i++) {
if (charAt(i) == oldChar)
tmpStr[i] = newChar;
else
tmpStr[i] = charAt(i);
}
tmpStr[length()] = '\0';
return *(new String(tmpStr));
}
// overloaded operators
String& String::operator=(const String& pstr)
{
delete [] str;
str = pstr.toCharArray();
len = pstr.length() + 1;
return *this;
}
String& String::operator=(const char* const pstr)
{
delete [] str;
len = 0;
while (true) {
if (pstr != 0 && *(pstr + len) != '\0') {
len++;
} else {
break;
}
}
len += 1; // allocate space for '\0'
if (len != 0) {
str = new char[len];
for (int i = 0; i < len; i++)
str[i] = pstr[i];
str[len - 1] = '\0';
}
return *this;
}