StringExt.h
// StringExt.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2004
#pragma once
#ifndef Ceda_cxUtils_StringExt_H
#define Ceda_cxUtils_StringExt_H
#include "cxUtils.h"
#include "xvector.h"
#include "xstring.h"
#include "xostream.h"
#include "StringStream.h"
#include "SubString.h"
#include "Hex.h"
namespace ceda
{
cxUtils_API void WriteIndent(xostream& os, ssize_t indent);
inline bool IsWhiteSpace(xchar c)
{
return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\f';
}
inline bool IsWhiteSpaceWithoutLinefeed(xchar c)
{
return c == ' ' || c == '\r' || c == '\t' || c == '\v' || c == '\f';
}
/*
inline bool IsWhiteSpaceWithoutLinefeedOrCarriageReturn(xchar c)
{
return c == ' ' || c == '\t' || c == '\v' || c == '\f';
}
*/
inline int MapDecDigit(xchar c)
{
if ('0' <= c && c <= '9') return c - '0';
return -1;
}
inline void DeleteChar(xstring& s, ssize_t index)
{
s.erase(s.begin() + index);
}
inline void DeleteChars(xstring& s, ssize_t i1, ssize_t i2)
{
s.erase(s.begin() + i1, s.begin() + i2);
}
// Returns the index position of the first character c in s or -1 if not found
cxUtils_API ssize_t StringFind(const xstring& s, xchar c);
// Returns the index position of the last character c in s or -1 if not found
cxUtils_API ssize_t StringReverseFind(const xstring& s, xchar c);
// Split string s into pieces using the given delimiter characters. The pieces are pushed into
// the vector list.
cxUtils_API void SplitStringUsingDelimiters(const xstring& s, xvector<xstring>& list, const xstring& delimiters);
// Remove all characters from s starting from the first occurence of the given delimiter character
cxUtils_API void TruncateStringPastDelimiter(xstring& s, xchar delimiter);
// Copy src string to dst string, removing any characters that appear in 'charsToRemove'
cxUtils_API void RemoveCharsFromString(const xstring& src, xstring* dst, const xstring& charsToRemove);
// Remove any characters in s that appear in 'charsToRemove'
inline void RemoveCharsFromString(xstring& s, const xstring& charsToRemove)
{
xstring src = s;
RemoveCharsFromString(src, &s, charsToRemove);
}
// Write src string to dst string changing every instance of character cfind with creplace,
cxUtils_API void FindAndReplaceCharInString(const xstring& src, xstring* dst, xchar cfind, xchar creplace);
// Replace occurrences of string sfind found in src with sreplace
cxUtils_API void StringFindAndReplace(xstring& src, const xstring& sfind, const xstring& sreplace);
// Changing every instance of character cfind with creplace in s
inline void FindAndReplaceCharInString(xstring& s, xchar cfind, xchar creplace)
{
xstring src = s;
FindAndReplaceCharInString(src,&s,cfind,creplace);
}
// Write src string to dst string, replacing each tab character with the given number of spaces
cxUtils_API void ReplaceTabsWithSpacesInString(const xstring& src, xstring* dst, ssize_t tabSize);
// Returns true if s has some repeated characters
// This implementation actually tests for repeated bytes, so can't be expected to work properly
// with general UTF-8 strings
cxUtils_API bool AsciiStringHasRepeatedChars(const xstring& s);
// Returns true if string s only contains characters drawn from string t
// This implementation only works for ASCII characters in t
cxUtils_API bool AsciiStringOnlyContainsGivenChars(const xstring& s, const xstring& t);
// Returns true if string s contains any characters drawn from string t
// This implementation only works for ASCII characters in t
cxUtils_API bool AsciiStringContainsAnyGivenChars(const xstring& s, const xstring& t);
// Eat characters at the start or end of string s that are drawn from string t
cxUtils_API void EatFirstCharsInString(xstring& s, const xstring& t);
cxUtils_API void EatLastCharsInString(xstring& s, const xstring& t);
// If string s contains spaces then returns double quoted version of s else merely returns a
// copy of s
cxUtils_API xstring AddQuotesToStringIfHaveSpaces(const xstring& s);
// Eat all spaces, tabs, line feeds and carriage returns
cxUtils_API void EatWhiteSpaceInString(xstring& s);
// Perform a basic lexical scan on string s, breaking it up according to the white space
cxUtils_API void BasicLexicalScan(const xstring& s, xvector<xstring>& list);
// Format string s using printf style syntax
cxUtils_API void FormatString(xstring& s, ConstStringZ format, ...);
// Add the given number of spaces to the front of every line in s
cxUtils_API void StringIndent(xstring& s, ssize_t numSpaces);
// Convert any upper case characters to lower case characters
cxUtils_API void StringToLower(xstring& s);
// Convert any lower case characters to upper case characters
cxUtils_API void StringToUpper(xstring& s);
// Read string s from a text file. Returns false if file not found
cxUtils_API bool ReadStringFromFile(xstring& s, const xstring& filename, bool textmode = true);
// Write string to a text file. Returns false if could not write the file
cxUtils_API bool WriteStringToFile(const xstring& s, const xstring& filename, bool textmode = true);
// Conversions between Unicode and ANSI
cxUtils_API void StrcpyANSItoUnicode(char16* dst, const char8* src);
cxUtils_API void StrcpyUnicodeToANSI(char8* dst, const char16* src);
// Append the range [s1,s2) to the given destination string
cxUtils_API void StringAppend(xstring& dst, const xchar* s1, const xchar* s2);
cxUtils_API void SearchAndReplace(const xstring& src, xstring& dst, const xstring& findStr, const xstring& repStr);
cxUtils_API void SearchAndReplace(const xstring& src, xostream& os, const xstring& findStr, const xstring& repStr);
cxUtils_API bool IsEqualNoCase(const xstring& s1, const xstring& s2);
///////////////////////////////////////////////////////////////////////////////////////////////////
// StringToNumber
template <typename T> bool StringToNumber(const xstring& str, T& value, xstring& reasonInvalid, int base = 10);
#define cxDefine_StringToInteger(T,Name) \
cxUtils_API bool StringTo ## Name(const xstring& str, T& value, xstring& reasonInvalid, int base = 10); \
template <> inline bool StringToNumber(const xstring& str, T& value, xstring& reasonInvalid, int base) \
{ return StringTo ## Name(str, value, reasonInvalid, base); }
cxDefine_StringToInteger(int8,Int8)
cxDefine_StringToInteger(uint8,UInt8)
cxDefine_StringToInteger(int16,Int16)
cxDefine_StringToInteger(uint16,UInt16)
cxDefine_StringToInteger(int32,Int32)
cxDefine_StringToInteger(uint32,UInt32)
cxDefine_StringToInteger(int64,Int64)
cxDefine_StringToInteger(uint64,UInt64)
cxUtils_API bool StringToFloat(const xstring& str, float& value, xstring& reasonInvalid);
cxUtils_API bool StringToDouble(const xstring& str, double& value, xstring& reasonInvalid);
template <> inline bool StringToNumber(const xstring& str, float& value, xstring& reasonInvalid, int base)
{
cxAssert(base == 10);
return StringToFloat(str, value, reasonInvalid);
}
template <> inline bool StringToNumber(const xstring& str, double& value, xstring& reasonInvalid, int base)
{
cxAssert(base == 10);
return StringToDouble(str, value, reasonInvalid);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// NumberToString
template <typename T> inline xstring NumberToString( const T& value )
{
StringStream os;
os << value;
return os.GetString();
}
/*
It is necessary to deal with 8 bit integers specially because unfortunately 'char' isn't a
distinct type
*/
template <> inline xstring NumberToString( const int8& value )
{
StringStream os;
os << (int) value;
return os.GetString();
}
template <> inline xstring NumberToString( const uint8& value )
{
StringStream os;
os << (int) value;
return os.GetString();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Convenient wrapper for writing a size in kilobytes / megabytes / gigabytes / terrabytes
cxUtils_API void WriteByteSizeNumber(xostream& os, double x);
template <typename T>
struct ByteSizeNumber
{
ByteSizeNumber(T value) : m_value(value) {}
T m_value;
};
template <typename T>
ByteSizeNumber<T> AsByteSize(T value) { return ByteSizeNumber<T>(value); }
template <typename T>
xostream& operator<<(xostream& os, ByteSizeNumber<T> bsn)
{
WriteByteSizeNumber(os,static_cast<double>(bsn.m_value));
return os;
}
template<typename T>
void SubStringToHexInt(SubString str, T& value, bool expect0x = true)
{
ssize_t startPos;
ssize_t n = str.size();
if (expect0x)
{
cxAssert(n > 2);
cxAssert(str[0] == '0');
cxAssert(str[1] == 'x' || str[1] == 'X');
startPos = 2;
}
else
{
startPos = 0;
}
value = 0;
for (ssize_t i=startPos ; i < n ; ++i)
{
int d = MapHexDigit(str[i]);
cxAssert(d != -1);
value = (T) ((value << 4) | d);
}
}
template<typename T>
void SubStringToInt(SubString str, T& value)
{
ssize_t n = str.size();
cxAssert(n > 0);
value = 0;
for (ssize_t i=0 ; i < n ; ++i)
{
int d = MapDecDigit(str[i]);
cxAssert(d != -1);
value = value * 10 + d;
}
}
template <typename T>
bool SubStringToHex(SubString& s, T& x)
{
const xchar* start = s.begin();
x = 0;
int d;
while(s && (d = MapHexDigit(*s)) != -1)
{
x = (x << 4) | d;
++s;
}
return s.begin() != start; // Return true if read one or more digits
}
} // namespace ceda
#endif // include guard