Wed, 27 Jan 2021 23:11:41 +0200
updated the documentation of the string functions
/* 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