sources/mystring.cpp

Fri, 05 Feb 2021 11:36:38 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Fri, 05 Feb 2021 11:36:38 +0200
changeset 200
3fb775db4829
parent 196
58d4a48f0904
child 197
819fdef70d68
permissions
-rw-r--r--

refactor

/*
	Copyright 2014 - 2021 Teemu Piippo
	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

	1. Redistributions of source code must retain the above copyright
	   notice, this list of conditions and the following disclaimer.
	2. Redistributions in binary form must reproduce the above copyright
	   notice, this list of conditions and the following disclaimer in the
	   documentation and/or other materials provided with the distribution.
	3. Neither the name of the copyright holder nor the names of its
	   contributors may be used to endorse or promote products derived from
	   this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
	PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
	OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
	PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
	LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <cstring>
#include "main.h"
#include "mystring.h"

BEGIN_ZFC_NAMESPACE

/*!
 * \brief Converts the given string to lowercase.
 * \param string string to convert
 * \return converted string
 */
std::string to_lowercase(const std::string& string)
{
	std::string result = string;

	for (char& ch : result)
	{
		if (isupper(ch))
			ch += 'a' - 'A';
	}

	return result;
}

/*!
 * \brief Joins a list of strings to a single string.
 * \param strings strings to join together
 * \param delimeter delimeter to join the strings together with
 * \return joined string
 */
std::string join_string_list(const std::vector<std::string>& strings, const std::string& delimeter)
{
	std::string result;

	for (const std::string &item : strings)
	{
		if (not result.empty())
			result += delimeter;

		result += item;
	}

	return result;
}

/*!
 * \brief Extracts a substring from the middle of the given string
 * \param str string to extract from
 * \param rangeBegin starting index of the substring
 * \param rangeEnd end index of the substring
 * \return substring
 */
std::string mid(const std::string& str, int rangeBegin, int rangeEnd)
{
	rangeBegin = max(rangeBegin, 0);
	rangeEnd = min(rangeEnd, static_cast<signed>(str.length()));
	std::string result;
	if (rangeEnd > rangeBegin)
	{
		result = str.substr(rangeBegin, rangeEnd - rangeBegin);
	}
	return result;
}

/*!
 * \brief right Extracts a substring from the end of the substring
 * \param str string to extract from
 * \param length desired length of the new substring
 * \return substring
 */
std::string right(const std::string& str, int length)
{
	if (length >= static_cast<signed>(str.length()))
		return str;
	else
		return std::string{str.data() + str.length() - length};
}

/*!
 * \brief Formats a string using \c vsnprintf, using a va_list argument list
 * \param formatString formatting string
 * \param args argument list
 * \return formatted string
 */
std::string vsprintf(const char* formatString, va_list args)
{
	std::string result;
	// Copy the argument list so that we have something to provide to vsnprintf in case we have to call it again.
	va_list argsCopy;
	va_copy(argsCopy, args);
	// First, attempt to format using a fixed-size buffer.
	static char buffer[1024];
	const std::size_t length = std::vsnprintf(buffer, countof(buffer), formatString, args);
	if (length < sizeof buffer)
	{
		// vsnprintf succeeded in fitting the formatted string into the buffer, so we're done.
		result = buffer;
	}
	else
	{
		// vsnprintf needs more space, so we have to allocate a new buffer and try again.
		result.resize(length + 1);
		std::vsnprintf(result.data(), length + 1, formatString, argsCopy);
	}
	return result;
}

/*!
 * \brief Formats a string using \c printf -like syntax
 * \param formatString formatting string
 * \param ... printf-like arguments
 * \return formatted string
 */
std::string __cdecl sprintf(const char* formatString, ...)
{
	va_list args;
	va_start (args, formatString);
	std::string result = vsprintf(formatString, args);
	va_end (args);
	return result;
}

/*!
 * \brief Removes a substring from the middle of a string
 * \param string original string
 * \param start start index to remove
 * \param end end index to remove
 * \return modified string
 */
std::string remove_range(const std::string &string, int start, int end)
{
	std::string result;
	result.reserve(string.length() - (end - start));
	std::copy(string.begin(), string.begin() + start, std::back_inserter(result));
	std::copy(string.begin() + end, string.end(), std::back_inserter(result));
	return result;
}

/*!
 * \brief Finds out whether the specified string starts with the specified substring.
 * \param string string to test
 * \param substring substring to look for
 * \return bool
 */
bool starts_with(const std::string& string, const std::string& substring)
{
	if (string.length() < substring.length())
		return false;
	else
		return std::strncmp(string.data(), substring.data(), substring.length()) == 0;
}

/*!
 * \brief Replaces all instances of \c text with \c replacement in place.
 * \param text Text to replace away.
 * \param replacement Text to replace \c text with.
 */
void replace_all(std::string& str, const char* text, const char* replacement)
{
	int position;
	while ((position = str.find(text)) != -1)
	{
		str.replace(position, std::strlen(text), replacement);
	}
}

/*!
 * \brief Splits this string using the provided delimeter.
 * \param delimeter Delimeter to use for splitting.
 * \returns a string list containing the split strings.
 */
std::vector<std::string> split(const std::string& string, const std::string& delimeter)
{
	std::vector<std::string> result;
	int a = 0;
	int b;

	// Find all separators and store the text left to them.
	while ((b = string.find(delimeter, a)) != -1)
	{
		std::string sub = mid(string, a, b);

		if (sub.length() > 0)
			result.push_back(sub);

		a = b + delimeter.length();
	}

	// Add the string at the right of the last separator
	if (a < static_cast<int>(string.length()))
		result.push_back(mid(string, a, string.length()));

	return result;
}

/*!
 * \brief Attempts to convert the specified string to an integer.
 * \param str string to convert
 * \param base numeric base to convert using.
 * \return the integer if conversion is successful.
 */
std::optional<long> to_int(const char* str, int base)
{
	errno = 0;
	char* endPointer;
	long result = strtol(str, &endPointer, base);
	if (errno == 0 and *endPointer == '\0')
	{
		return result;
	}
	else
	{
		return {};
	}
}

/*!
 * \brief Removes unwanted characters from the specified string. Modification is done in place.
 * \param string String to modify.
 * \param filter The filtering function to use, defaults to std::isspace in order to remove whitespace.
 */
void normalize(std::string& string, int (*filter)(int))
{
	int a = 0;
	int b = string.length() - 1;
	while ((*filter)(string[a]) and a != b)
	{
		++a;
	}
	while ((*filter)(string[b]) and a != b)
	{
		--b;
	}
	if (a == b)
	{
		string = "";
	}
	else if (a != 0 or b != static_cast<signed>(string.length() - 1))
	{
		string = string.substr (a, b - a + 1);
	}
}

END_ZFC_NAMESPACE

mercurial