string_algorithms.hpp

Back to String algorithms

pastel/sys/string/

#ifndef PASTELSYS_STRING_ALGORITHMS_HPP
#define PASTELSYS_STRING_ALGORITHMS_HPP

#include "pastel/sys/string/string_algorithms.h"
#include "pastel/sys/ensure.h"
#include "pastel/sys/math/constants.h"
#include "pastel/sys/real/real_concept.h"

#include <algorithm>
#include <sstream>
#include <iomanip>
#include <cctype>
#include <functional>

namespace Pastel
{

    inline bool startsWith(const std::string& text, const std::string& prologue)
    {
        if (prologue.size() > text.size())
        {
            return false;
        }

        for (integer i = 0;i < prologue.size();++i)
        {
            if (text[i] != prologue[i])
            {
                return false;
            }
        }

        return true;
    }

    inline std::string& makeLowercase(std::string& text)
    {
        // See the makeUppercase() function for some notes.
        for (integer i = 0;i < text.size();++i)
        {
            text[i] = std::tolower(text[i]);
        }

        return text;
    }

    inline std::string lowercase(const std::string& text)
    {
        std::string result(text);
        return makeLowercase(result);
    }

    inline std::string& makeUppercase(std::string& text)
    {
        // See the makeUppercase() function for some notes.
        for (integer i = 0;i < text.size();++i)
        {
            text[i] = std::toupper(text[i]);
        }

        // I'd use the following, but it doesn't compile in GCC.
        // The problem may be in the definition of the
        // toupper() function (e.g. a macro).

        //std::transform(result.begin(), result.end(), 
        // result.begin(), std::ptr_fun(&std::toupper));

        return text;
    }

    inline std::string uppercase(const std::string& text)
    {
        std::string result(text);
        return makeUppercase(result);
    }

    inline std::string repeat(const std::string& that, integer times)
    {
        std::string result;
        result.reserve(that.length() * times);

        for (integer i = 0;i < times;++i)
        {
            result += that;
        }

        return result;
    }

    inline std::string ltrim(const std::string& that, 
        integer *indexBegin)
    {
        std::string result;

        integer begin = that.find_first_not_of(" \t\n");
        if (begin == std::string::npos)
        {
            // Everything is trimmed away.
            begin = that.size();
        }
        else
        {
            result = that.substr(begin);
        }

        if (indexBegin)
        {
            *indexBegin = begin;
        }

        return result;
    }

    inline std::string rtrim(const std::string& that, 
        integer *indexEnd)
    {
        std::string result;

        integer end = that.find_last_not_of(" \t\n");
        if (end == std::string::npos)
        {
            // Nothing is trimmed away.
            result = that;
            end = that.size();
        }
        else
        {
            result = that.substr(0, end);
        }

        if (indexEnd)
        {
            *indexEnd = end;
        }

        return result;
    }

    inline std::string trim(const std::string& that, 
        integer* indexBegin, integer* indexEnd)
    {
        std::string result;

        integer begin = that.find_first_not_of(" \t\n");
        integer end = that.size();
        if (begin == std::string::npos)
        {
            // Everything is trimmed away.
            begin = that.size();
        }
        else
        {
            end = that.find_last_not_of(" \t\n");
            if (end == std::string::npos)
            {
                end = that.size();
            }

            result = that.substr(begin, (end - begin) + 1);
        }

        if (indexBegin)
        {
            *indexBegin = begin;
        }
        if (indexEnd)
        {
            *indexEnd = end;
        }

        return result;
    }

    inline std::string firstWord(const std::string& that)
    {
        integer begin = that.find_first_not_of(" \t\n");
        integer end = that.find_first_of(" \t\n", begin);
        if (end == std::string::npos)
        {
            end = that.size();
        }

        std::string result;

        if (begin != std::string::npos &&
            end != std::string::npos)
        {
            result = that.substr(begin, end - begin);

        }

        return result;
    }

    inline std::string removeWhiteSpace(const std::string& that)
    {
        std::string result;
        integer thatSize = that.size();
        for (integer i = 0;i < thatSize;++i)
        {

            if (that[i] != ' ' &&
                that[i] != '\t' &&
                that[i] != '\n')
            {
                result.push_back(that[i]);
            }
        }
        return result;
    }

    inline bool separateBlocks(const std::string& that,
        char beginSymbol, char endSymbol,
        std::vector<std::string>& blocks)
    {
        integer thatSize = that.size();
        integer position = 0;
        while (position < thatSize)
        {
            integer begin =
                that.find_first_of(beginSymbol, position);
            if (begin == std::string::npos ||
                begin + 1 == thatSize)
            {
                break;
            }
            ++begin;

            integer end =
                that.find_first_of(endSymbol, begin);
            if (end == std::string::npos)
            {
                return false;
            }

            blocks.push_back(that.substr(begin, end - begin));

            position = end + 1;
        }

        return true;
    }

    inline void getWords(const std::string& sentence,
        std::vector<std::string>& words)
    {
        std::stringstream stream;
        stream << sentence;

        words.clear();

        std::string word;
        while (true)
        {
            stream >> word;
            if (!stream)
            {
                break;
            }
            words.push_back(word);
        }
    }

    inline integer stringToInteger(const std::string& text)
    {
        std::stringstream stream;
        stream << text;
        integer number = 0;
        stream >> number;
        if (!stream)
        {
            throw std::string("stringToInteger: could not convert to a number.");
        }

        return number;
    }

    inline real stringToReal(const std::string& text, integer* indexEnd)
    {
        integer trimmed = 0;
        std::string nText = lowercase(ltrim(text, &trimmed));

        real result = (real)Nan();
        integer matchSize = trimmed;
        bool foundMatch = false;
        bool positive = true;

        if (startsWith(nText, "-"))
        {
            positive = false;
            nText = nText.substr(1);
            matchSize += 1;
        }
        else if (startsWith(nText, "+"))
        {
            nText = nText.substr(1);
            matchSize += 1;
        }

        if (startsWith(nText, "nan"))
        {
            matchSize += 3;
            result = (real)Nan();
            foundMatch = true;
        }
        else if (startsWith(nText, "inf"))
        {
            matchSize += 3;
            result = (real)Infinity();
            foundMatch = true;
        }
        else
        {
            std::stringstream stream;
            stream << nText;
            real number = 0;
            stream >> number;
            if (stream)
            {
                result = number;
                matchSize = (integer)stream.tellg();
                foundMatch = true;
            }
        }

        if (!foundMatch)
        {
            matchSize = 0;
        }

        if (indexEnd)
        {
            *indexEnd = matchSize;
        }

        if (!positive)
        {
            return -result;
        }

        return result;
    }

    inline std::string integerToString(integer number,
        integer digits, char padding)
    {
        std::stringstream stream;
        stream << number;

        std::string text;
        stream >> text;

        if (!stream)
        {
            throw std::string("intgerToString: could not convert to an integer.");
        }

        std::string padText;
        if (digits > 0)
        {
            // Pad or trim.

            integer length = text.size();
            if (length < digits)
            {
                integer toPad = digits - length;
                for (integer i = 0;i < toPad;++i)
                {
                    padText += padding;
                }
            }
            else if (length > digits)
            {
                text = text.substr(length - digits);
            }
        }

        return padText + text;
    }

    inline std::string realToString(real number,
        integer digits)
    {
        if (number == (real)Infinity())
        {
            return std::string("inf");
        }
        else if (number == -(real)Infinity())
        {
            return std::string("-inf");
        }
        else if (isNan(number))
        {
            return std::string("nan");
        }

        std::stringstream stream;
        if (digits > 0)
        {
            stream << std::setprecision(digits);
        }
        stream << number;

        std::string text;
        stream >> text;

        return text;
    }

}

#endif