#pragma once #include "ascii.h" #include #include #include #include template struct TIsAsciiSpaceAdapter { bool operator()(const It& it) const noexcept { return IsAsciiSpace(*it); } }; template TIsAsciiSpaceAdapter IsAsciiSpaceAdapter(It) { return {}; } template struct TEqualsStripAdapter { TEqualsStripAdapter(TChar ch) : Ch(ch) { } template bool operator()(const It& it) const noexcept { return *it == Ch; } const TChar Ch; }; template TEqualsStripAdapter EqualsStripAdapter(TChar ch) { return {ch}; } template inline void StripRangeBegin(It& b, const It& e, TStripCriterion&& criterion) noexcept { while (b < e && criterion(b)) { ++b; } } template inline void StripRangeBegin(It& b, const It& e) noexcept { StripRangeBegin(b, e, IsAsciiSpaceAdapter(b)); } template inline void StripRangeEnd(const It& b, It& e, TStripCriterion&& criterion) noexcept { while (b < e && criterion(e - 1)) { --e; } } template inline void StripRangeEnd(const It& b, It& e) noexcept { StripRangeEnd(b, e, IsAsciiSpaceAdapter(b)); } template struct TStripImpl { template static inline bool StripRange(It& b, It& e, TStripCriterion&& criterion) noexcept { const size_t oldLen = e - b; if (stripBeg) { StripRangeBegin(b, e, criterion); } if (stripEnd) { StripRangeEnd(b, e, criterion); } const size_t newLen = e - b; return newLen != oldLen; } template static inline bool StripString(const T& from, T& to, TStripCriterion&& criterion) { auto b = from.begin(); auto e = from.end(); if (StripRange(b, e, criterion)) { if constexpr (::TIsTemplateBaseOf::value) { to = T(b, e - b); } else { to.assign(b, e - b); } return true; } to = from; return false; } template [[nodiscard]] static inline T StripString(const T& from, TStripCriterion&& criterion) { T ret; StripString(from, ret, criterion); return ret; } template [[nodiscard]] static inline T StripString(const T& from) { return StripString(from, IsAsciiSpaceAdapter(from.begin())); } }; template inline bool StripRange(It& b, It& e, TStripCriterion&& criterion) noexcept { return TStripImpl::StripRange(b, e, criterion); } template inline bool StripRange(It& b, It& e) noexcept { return StripRange(b, e, IsAsciiSpaceAdapter(b)); } template inline bool Strip(It& b, size_t& len, TStripCriterion&& criterion) noexcept { It e = b + len; if (StripRange(b, e, criterion)) { len = e - b; return true; } return false; } template inline bool Strip(It& b, size_t& len) noexcept { return Strip(b, len, IsAsciiSpaceAdapter(b)); } template static inline bool StripString(const T& from, T& to, TStripCriterion&& criterion) { return TStripImpl::StripString(from, to, criterion); } template static inline bool StripString(const T& from, T& to) { return StripString(from, to, IsAsciiSpaceAdapter(from.begin())); } template [[nodiscard]] static inline T StripString(const T& from, TStripCriterion&& criterion) { return TStripImpl::StripString(from, criterion); } template [[nodiscard]] static inline T StripString(const T& from) { return TStripImpl::StripString(from); } template [[nodiscard]] static inline T StripStringLeft(const T& from) { return TStripImpl::StripString(from); } template [[nodiscard]] static inline T StripStringRight(const T& from) { return TStripImpl::StripString(from); } template [[nodiscard]] static inline T StripStringLeft(const T& from, TStripCriterion&& criterion) { return TStripImpl::StripString(from, criterion); } template [[nodiscard]] static inline T StripStringRight(const T& from, TStripCriterion&& criterion) { return TStripImpl::StripString(from, criterion); } /// Copies the given string removing leading and trailing spaces. static inline bool Strip(const TString& from, TString& to) { return StripString(from, to); } /// Removes leading and trailing spaces from the string. inline TString& StripInPlace(TString& s) { Strip(s, s); return s; } template inline void StripInPlace(T& s) { StripString(s, s); } /// Returns a copy of the given string with removed leading and trailing spaces. [[nodiscard]] inline TString Strip(const TString& s) { TString ret = s; Strip(ret, ret); return ret; } template size_t CollapseImpl(TChar* s, size_t n, const TWhitespaceFunc& isWhitespace) { size_t newLen = 0; for (size_t i = 0; i < n; ++i, ++newLen) { size_t nextNonSpace = i; while (nextNonSpace < n && isWhitespace(s[nextNonSpace])) { ++nextNonSpace; } size_t numSpaces = nextNonSpace - i; if (numSpaces > 1 || (numSpaces == 1 && s[i] != ' ')) { s[newLen] = ' '; i = nextNonSpace - 1; } else { s[newLen] = s[i]; } } return newLen; } template bool CollapseImpl(const TStringType& from, TStringType& to, size_t maxLen, const TWhitespaceFunc& isWhitespace) { to = from; maxLen = maxLen ? Min(maxLen, to.size()) : to.size(); for (size_t i = 0; i < maxLen; ++i) { if (isWhitespace(to[i]) && (to[i] != ' ' || isWhitespace(to[i + 1]))) { size_t tailSize = maxLen - i; size_t newTailSize = CollapseImpl(to.begin() + i, tailSize, isWhitespace); to.remove(i + newTailSize, tailSize - newTailSize); return true; } } return false; } template std::enable_if_t, bool> Collapse( const TStringType& from, TStringType& to, TWhitespaceFunc isWhitespace, size_t maxLen = 0) { return CollapseImpl(from, to, maxLen, isWhitespace); } template inline bool Collapse(const TStringType& from, TStringType& to, size_t maxLen = 0) { return Collapse(from, to, IsAsciiSpace, maxLen); } /// Replaces several consequtive space symbols with one (processing is limited to maxLen bytes) template inline TStringType& CollapseInPlace(TStringType& s, size_t maxLen = 0) { Collapse(s, s, maxLen); return s; } template inline TStringType& CollapseInPlace(TStringType& s, TWhitespaceFunc isWhitespace, size_t maxLen = 0) { Collapse(s, s, isWhitespace, maxLen); return s; } /// Replaces several consequtive space symbols with one (processing is limited to maxLen bytes) template [[nodiscard]] inline TStringType Collapse(const TStringType& s, size_t maxLen = 0) { TStringType ret; Collapse(s, ret, maxLen); return ret; } void CollapseText(const TString& from, TString& to, size_t maxLen); /// The same as Collapse() + truncates the string to maxLen. /// @details An ellipsis is inserted at the end of the truncated line. inline void CollapseText(TString& s, size_t maxLen) { TString to; CollapseText(s, to, maxLen); s = to; }