Hazelnupp/Hazelnupp/StringTools.cpp
2021-08-04 21:17:34 +02:00

187 lines
4.9 KiB
C++

#include "StringTools.h"
using namespace Hazelnp;
bool Internal::StringTools::Contains(const std::string& str, const char c)
{
for (const char& i : str)
if (i == c)
return true;
return false;
}
std::string Internal::StringTools::Replace(const std::string& str, const char find, const std::string& subst)
{
std::stringstream ss;
for (std::size_t i = 0; i < str.length(); i++)
{
if (str[i] != find) ss << str[i];
else ss << subst;
}
return ss.str();
}
std::string Internal::StringTools::Replace(const std::string& str, const std::string& find, const std::string& subst)
{
if (find.length() == 0) return str;
std::stringstream ss;
std::size_t posFound = 0;
std::size_t lastFound = 0;
while (posFound != std::string::npos)
{
lastFound = posFound;
posFound = str.find(find, posFound);
if (posFound != std::string::npos)
{
ss << str.substr(lastFound, posFound - lastFound) << subst;
posFound += find.length();
}
else
{
ss << str.substr(lastFound, (str.length()) - lastFound);
}
}
return ss.str();
}
bool Internal::StringTools::IsNumeric(const std::string& str, const bool allowDecimalPoint)
{
if (str.length() == 0) return false;
bool alreadyParsedDecimalPoint = false;
std::size_t digitCount = 0;
for (std::size_t i = 0; i < str.length(); i++)
{
if (!(
((str[i] >= '0') && (str[i] <= '9')) ||
((str[i] == '-') && (i == 0)) ||
((str[i] == '.') && (allowDecimalPoint) && (!alreadyParsedDecimalPoint) && (digitCount > 0))
)) return false;
// Here we just have to check for the character. Not for any other conditions.
// Why? Because if these conditions failed, the function would have already returned false.
if (((str[i] >= '0') && (str[i] <= '9'))) digitCount++;
if (str[i] == '.') alreadyParsedDecimalPoint = true;
}
// Even if we did not find any invalid chars, we should still return false, if we found no digits at all.
return digitCount > 0;
}
bool Internal::StringTools::ParseNumber(const std::string& str, bool& out_isInt, long double& out_number)
{
bool isDecimal = false;
if (str.length() == 0) return false;
if (Contains(str, '.')) isDecimal = true;
if (isDecimal)
{
try
{
out_number = std::stold(str);
out_isInt = false;
}
catch (std::invalid_argument&)
{
return false;
}
catch (std::out_of_range&)
{
return false;
}
}
else
{
try
{
out_number = (long double)std::stoll(str);
out_isInt = true;
}
catch (std::invalid_argument&)
{
return false;
}
catch (std::out_of_range&)
{
return false;
}
}
return true;
}
std::vector<std::string> Internal::StringTools::SplitString(const std::string& str, const char delimiter)
{
if (str.length() == 0) return std::vector<std::string>();
return SplitString(str, delimiter);
}
std::vector<std::string> Internal::StringTools::SplitString(const std::string& str, const std::string& delimiter)
{
if (str.length() == 0) return std::vector<std::string>();
std::vector<std::string> parts;
if (delimiter.length() == 0) // If the delimiter is "" (empty), just split between every single char. Not useful, but logical
{
for (std::size_t i = 0; i < str.length(); i++)
{
parts.push_back(std::string({ str[i] }));
}
return parts;
}
std::size_t posFound = 0;
std::size_t lastFound = 0;
while (posFound != std::string::npos)
{
lastFound = posFound;
posFound = str.find(delimiter, posFound);
std::string found;
if (posFound != std::string::npos)
{
found = str.substr(lastFound, posFound - lastFound);
posFound += delimiter.length();
}
else
{
found = str.substr(lastFound, str.length() - lastFound);
}
parts.push_back(found);
}
return parts;
}
std::string Internal::StringTools::ToLower(const std::string& str)
{
std::stringstream ss;
for (std::size_t i = 0; i < str.length(); i++)
{
if ((str[i] >= 'A') && (str[i] <= 'Z')) ss << (char)(((int)str[i]) + 32);
else if (str[i] == -60) ss << (char)-28; // AE => ae
else if (str[i] == -42) ss << (char)-10; // OE => oe
else if (str[i] == -36) ss << (char)-4; // UE => ue
else ss << str[i];
}
return ss.str();
}