1 #ifndef CONVERSION_UTILITIES_STRINGCONVERSION_H
2 #define CONVERSION_UTILITIES_STRINGCONVERSION_H
7 #include "../misc/traits.h"
11 #include <initializer_list>
31 std::free(stringData);
38 using StringData = std::pair<std::unique_ptr<char[], StringDataDeleter>, std::size_t>;
42 const char *fromCharset,
const char *toCharset,
const char *inputBuffer, std::size_t inputBufferSize,
float outputBufferSizeFactor = 1.0f);
50 #ifdef PLATFORM_WINDOWS
51 using WideStringData = std::pair<std::unique_ptr<wchar_t[]>,
int>;
52 CPP_UTILITIES_EXPORT WideStringData convertMultiByteToWide(
const char *inputBuffer,
int inputBufferSize = -1);
71 template <
class Container = std::initializer_list<std::
string>>
72 typename Container::value_type
joinStrings(
const Container &strings,
73 const typename Container::value_type &delimiter =
typename Container::value_type(),
bool omitEmpty =
false,
74 const typename Container::value_type &leftClosure =
typename Container::value_type(),
75 const typename Container::value_type &rightClosure =
typename Container::value_type())
77 typename Container::value_type res;
78 if (!strings.size()) {
81 std::size_t entries = 0, size = 0;
82 for (
const auto &str : strings) {
83 if (omitEmpty && str.empty()) {
92 size += (entries * leftClosure.size()) + (entries * rightClosure.size()) + ((entries - 1) * delimiter.size());
94 for (
const auto &str : strings) {
95 if (omitEmpty && str.empty()) {
99 res.append(delimiter);
101 res.append(leftClosure);
103 res.append(rightClosure);
111 template <
class Container = std::initializer_list<std::
string>>
inline std::vector<std::string>
toMultiline(
const Container &arrayOfLines)
134 template <
class Container = std::list<std::
string>>
135 Container
splitString(
const typename Container::value_type &
string,
const typename Container::value_type &delimiter,
141 for (
typename Container::value_type::size_type
i = 0, end =
string.size(), delimPos;
i < end;
i = delimPos + delimiter.size()) {
142 delimPos =
string.find(delimiter,
i);
143 if (!merge && maxParts >= 0 && res.size() ==
static_cast<typename Container::value_type::size_type
>(maxParts)) {
150 delimPos = Container::value_type::npos;
152 if (delimPos == Container::value_type::npos) {
153 delimPos =
string.size();
157 res.back().append(delimiter);
158 res.back().append(
string.substr(
i, delimPos -
i));
161 res.emplace_back(
string.substr(
i, delimPos -
i));
181 template <
class Container = std::list<std::
string>>
182 Container
splitStringSimple(
const typename Container::value_type &
string,
const typename Container::value_type &delimiter,
int maxParts = -1)
186 for (
typename Container::value_type::size_type
i = 0, end =
string.size(), delimPos;
i < end;
i = delimPos + delimiter.size()) {
187 delimPos =
string.find(delimiter,
i);
188 if (maxParts >= 0 && res.size() ==
static_cast<typename Container::value_type::size_type
>(maxParts)) {
189 delimPos = Container::value_type::npos;
191 if (delimPos == Container::value_type::npos) {
192 delimPos =
string.size();
194 res.emplace_back(
string.substr(
i, delimPos -
i));
202 template <
class Container = std::vector<std::
string>>
inline std::vector<std::string>
toArrayOfLines(
const std::string &multilineString)
210 template <
typename StringType>
bool startsWith(
const StringType &str,
const StringType &phrase)
212 if (str.size() < phrase.size()) {
215 for (
auto stri = str.cbegin(), strend = str.cend(), phrasei = phrase.cbegin(), phraseend = phrase.cend();; ++stri, ++phrasei) {
216 if (phrasei == phraseend) {
218 }
else if (stri == strend) {
220 }
else if (*stri != *phrasei) {
230 template <
typename StringType>
bool startsWith(
const StringType &str,
const typename StringType::value_type *phrase)
232 for (
auto stri = str.cbegin(), strend = str.cend();; ++stri, ++phrase) {
235 }
else if (stri == strend) {
237 }
else if (*stri != *phrase) {
247 template <
typename StringType>
bool endsWith(
const StringType &str,
const StringType &phrase)
249 if (str.size() < phrase.size()) {
252 for (
auto stri = str.cend() - phrase.size(), strend = str.cend(), phrasei = phrase.cbegin(); stri != strend; ++stri, ++phrasei) {
253 if (*stri != *phrasei) {
263 template <
typename StringType>
bool endsWith(
const StringType &str,
const typename StringType::value_type *phrase)
265 const auto phraseSize = std::strlen(phrase);
266 if (str.size() < phraseSize) {
269 for (
auto stri = str.cend() - phraseSize, strend = str.cend(); stri != strend; ++stri, ++phrase) {
270 if (*stri != *phrase) {
281 template <
typename StringType>
bool containsSubstrings(
const StringType &str, std::initializer_list<StringType> substrings)
283 typename StringType::size_type currentPos = 0;
284 for (
const auto &substr : substrings) {
285 if ((currentPos = str.find(substr, currentPos)) == StringType::npos) {
288 currentPos += substr.size();
297 template <
typename StringType>
298 bool containsSubstrings(
const StringType &str, std::initializer_list<const typename StringType::value_type *> substrings)
300 typename StringType::size_type currentPos = 0;
301 for (
const auto *substr : substrings) {
302 if ((currentPos = str.find(substr, currentPos)) == StringType::npos) {
305 currentPos += std::strlen(substr);
313 template <
typename StringType>
void findAndReplace(StringType &str,
const StringType &find,
const StringType &replace)
315 for (
typename StringType::size_type
i = 0; (
i = str.find(find,
i)) != StringType::npos;
i += replace.size()) {
316 str.replace(
i, find.size(), replace);
326 template <
typename CharType> constexpr CharType
digitToChar(CharType digit)
328 return digit <= 9 ? (digit +
'0') : (digit +
'A' - 10);
337 template <
typename IntegralType,
class StringType = std::string,
339 StringType
numberToString(IntegralType number,
typename StringType::value_type base = 10)
341 std::size_t resSize = 0;
342 for (
auto n = number; n; n /= base, ++resSize)
345 res.reserve(resSize);
347 res.insert(res.begin(), digitToChar<typename StringType::value_type>(number % base));
359 template <
typename IntegralType,
class StringType = std::string,
360 Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>> * =
nullptr>
361 StringType
numberToString(IntegralType number,
typename StringType::value_type base = 10)
363 const bool negative = number < 0;
366 number = -number, resSize = 1;
370 for (
auto n = number; n; n /= base, ++resSize)
373 res.reserve(resSize);
375 res.insert(res.begin(), digitToChar<typename StringType::value_type>(number % base));
379 res.insert(res.begin(),
'-');
392 template <
typename FloatingType,
class StringType = std::
string, Traits::EnableIf<std::is_
floating_po
int<FloatingType>> * =
nullptr>
393 StringType
numberToString(FloatingType number,
typename StringType::value_type base = 10)
395 std::basic_stringstream<typename StringType::value_type> ss;
396 ss << std::setbase(base) << number;
405 template <
typename CharType> CharType
charToDigit(CharType character, CharType base)
408 if (character >=
'0' && character <=
'9') {
409 res = character -
'0';
410 }
else if (character >=
'a' && character <=
'z') {
411 res = character -
'a' + 10;
412 }
else if (character >=
'A' && character <=
'Z') {
413 res = character -
'A' + 10;
418 std::string errorMsg;
419 errorMsg.reserve(36);
420 errorMsg +=
"The character \"";
421 errorMsg += character;
422 errorMsg +=
"\" is no valid digit.";
434 template <
typename IntegralType,
typename StringType, Traits::EnableIf<std::is_
integral<IntegralType>, std::is_
unsigned<IntegralType>> * =
nullptr>
435 IntegralType
stringToNumber(
const StringType &
string,
typename StringType::value_type base = 10)
437 IntegralType result = 0;
438 for (
const auto &c :
string) {
443 result += charToDigit<typename StringType::value_type>(c, base);
456 template <
typename IntegralType,
class StringType, Traits::EnableIf<std::is_
integral<IntegralType>, std::is_
signed<IntegralType>> * =
nullptr>
457 IntegralType
stringToNumber(
const StringType &
string,
typename StringType::value_type base = 10)
459 auto i =
string.begin();
460 auto end =
string.end();
461 for (;
i != end && *
i ==
' '; ++
i)
466 const bool negative = (*
i ==
'-');
470 IntegralType result = 0;
471 for (;
i != end; ++
i) {
476 result += charToDigit<typename StringType::value_type>(*
i, base);
478 return negative ? -result : result;
491 template <
typename FloatingType,
class StringType, Traits::EnableIf<std::is_
floating_po
int<FloatingType>> * =
nullptr>
492 FloatingType
stringToNumber(
const StringType &
string,
typename StringType::value_type base = 10)
494 std::basic_stringstream<typename StringType::value_type> ss;
495 ss << std::setbase(base) << string;
497 if ((ss >> result) && ss.eof()) {
500 std::string errorMsg;
501 errorMsg.reserve(42 +
string.size());
502 errorMsg +=
"The string \"";
504 errorMsg +=
"\" is no valid floating number.";
516 template <
typename IntegralType,
class CharType, Traits::EnableIf<std::is_
integral<IntegralType>, std::is_
unsigned<IntegralType>> * =
nullptr>
519 IntegralType result = 0;
520 for (; *string; ++string) {
521 if (*
string ==
' ') {
525 result += charToDigit<CharType>(*
string, base);
540 template <
typename FloatingType,
class CharType, Traits::EnableIf<std::is_
floating_po
int<FloatingType>> * =
nullptr>
543 std::basic_stringstream<CharType> ss;
544 ss << std::setbase(base) << string;
546 if ((ss >> result) && ss.eof()) {
549 std::string errorMsg;
550 errorMsg.reserve(42 + std::char_traits<CharType>::length(
string));
551 errorMsg +=
"The string \"";
553 errorMsg +=
"\" is no valid floating number.";
564 template <
typename IntegralType,
class CharType, Traits::EnableIf<std::is_
integral<IntegralType>, std::is_
unsigned<IntegralType>> * =
nullptr>
565 IntegralType
bufferToNumber(
const CharType *
string, std::size_t size,
unsigned char base = 10)
567 IntegralType result = 0;
568 for (
const CharType *end =
string + size;
string != end; ++string) {
569 if (*
string ==
' ') {
573 result += charToDigit<CharType>(*
string, base);
585 template <
typename IntegralType,
class CharType, Traits::EnableIf<std::is_
integral<IntegralType>, std::is_
signed<IntegralType>> * =
nullptr>
586 IntegralType
stringToNumber(
const CharType *
string,
unsigned char base = 10)
591 for (; *
string && *
string ==
' '; ++string)
596 const bool negative = (*
string ==
'-');
600 IntegralType result = 0;
601 for (; *string; ++string) {
602 if (*
string ==
' ') {
606 result += charToDigit<CharType>(*
string, base);
608 return negative ? -result : result;
618 template <
typename IntegralType,
class CharType, Traits::EnableIf<std::is_
integral<IntegralType>, std::is_
signed<IntegralType>> * =
nullptr>
619 IntegralType
bufferToNumber(
const CharType *
string, std::size_t size,
unsigned char base = 10)
624 const CharType *end =
string + size;
625 for (;
string != end && *
string ==
' '; ++string)
630 const bool negative = (*
string ==
'-');
634 IntegralType result = 0;
635 for (;
string != end; ++string) {
636 if (*
string ==
' ') {
640 result += charToDigit<CharType>(*
string, base);
642 return negative ? -result : result;
656 char buffer[
sizeof(T)];
657 BE::getBytes(integer, buffer);
658 return std::string(buffer + startOffset,
sizeof(T) - startOffset);
667 #endif // CONVERSION_UTILITIES_STRINGCONVERSION_H