strip.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #pragma once
  2. #include "ascii.h"
  3. #include <util/generic/string.h>
  4. #include <util/generic/strbuf.h>
  5. #include <util/generic/typetraits.h>
  6. #include <utility>
  7. template <class It>
  8. struct TIsAsciiSpaceAdapter {
  9. bool operator()(const It& it) const noexcept {
  10. return IsAsciiSpace(*it);
  11. }
  12. };
  13. template <class It>
  14. TIsAsciiSpaceAdapter<It> IsAsciiSpaceAdapter(It) {
  15. return {};
  16. }
  17. template <class TChar>
  18. struct TEqualsStripAdapter {
  19. TEqualsStripAdapter(TChar ch)
  20. : Ch(ch)
  21. {
  22. }
  23. template <class It>
  24. bool operator()(const It& it) const noexcept {
  25. return *it == Ch;
  26. }
  27. const TChar Ch;
  28. };
  29. template <class TChar>
  30. TEqualsStripAdapter<TChar> EqualsStripAdapter(TChar ch) {
  31. return {ch};
  32. }
  33. template <class It, class TStripCriterion>
  34. inline void StripRangeBegin(It& b, const It& e, TStripCriterion&& criterion) noexcept {
  35. while (b < e && criterion(b)) {
  36. ++b;
  37. }
  38. }
  39. template <class It>
  40. inline void StripRangeBegin(It& b, const It& e) noexcept {
  41. StripRangeBegin(b, e, IsAsciiSpaceAdapter(b));
  42. }
  43. template <class It, class TStripCriterion>
  44. inline void StripRangeEnd(const It& b, It& e, TStripCriterion&& criterion) noexcept {
  45. while (b < e && criterion(e - 1)) {
  46. --e;
  47. }
  48. }
  49. template <class It>
  50. inline void StripRangeEnd(const It& b, It& e) noexcept {
  51. StripRangeEnd(b, e, IsAsciiSpaceAdapter(b));
  52. }
  53. template <bool stripBeg, bool stripEnd>
  54. struct TStripImpl {
  55. template <class It, class TStripCriterion>
  56. static inline bool StripRange(It& b, It& e, TStripCriterion&& criterion) noexcept {
  57. const size_t oldLen = e - b;
  58. if (stripBeg) {
  59. StripRangeBegin(b, e, criterion);
  60. }
  61. if (stripEnd) {
  62. StripRangeEnd(b, e, criterion);
  63. }
  64. const size_t newLen = e - b;
  65. return newLen != oldLen;
  66. }
  67. template <class T, class TStripCriterion>
  68. static inline bool StripString(const T& from, T& to, TStripCriterion&& criterion) {
  69. auto b = from.begin();
  70. auto e = from.end();
  71. if (StripRange(b, e, criterion)) {
  72. if constexpr (::TIsTemplateBaseOf<std::basic_string_view, T>::value) {
  73. to = T(b, e);
  74. } else {
  75. to.assign(b, e);
  76. }
  77. return true;
  78. }
  79. to = from;
  80. return false;
  81. }
  82. template <class T, class TStripCriterion>
  83. [[nodiscard]] static inline T StripString(const T& from, TStripCriterion&& criterion) {
  84. T ret;
  85. StripString(from, ret, criterion);
  86. return ret;
  87. }
  88. template <class T>
  89. [[nodiscard]] static inline T StripString(const T& from) {
  90. return StripString(from, IsAsciiSpaceAdapter(from.begin()));
  91. }
  92. };
  93. template <class It, class TStripCriterion>
  94. inline bool StripRange(It& b, It& e, TStripCriterion&& criterion) noexcept {
  95. return TStripImpl<true, true>::StripRange(b, e, criterion);
  96. }
  97. template <class It>
  98. inline bool StripRange(It& b, It& e) noexcept {
  99. return StripRange(b, e, IsAsciiSpaceAdapter(b));
  100. }
  101. template <class It, class TStripCriterion>
  102. inline bool Strip(It& b, size_t& len, TStripCriterion&& criterion) noexcept {
  103. It e = b + len;
  104. if (StripRange(b, e, criterion)) {
  105. len = e - b;
  106. return true;
  107. }
  108. return false;
  109. }
  110. template <class It>
  111. inline bool Strip(It& b, size_t& len) noexcept {
  112. return Strip(b, len, IsAsciiSpaceAdapter(b));
  113. }
  114. template <class T, class TStripCriterion>
  115. static inline bool StripString(const T& from, T& to, TStripCriterion&& criterion) {
  116. return TStripImpl<true, true>::StripString(from, to, criterion);
  117. }
  118. template <class T>
  119. static inline bool StripString(const T& from, T& to) {
  120. return StripString(from, to, IsAsciiSpaceAdapter(from.begin()));
  121. }
  122. template <class T, class TStripCriterion>
  123. [[nodiscard]] static inline T StripString(const T& from, TStripCriterion&& criterion) {
  124. return TStripImpl<true, true>::StripString(from, criterion);
  125. }
  126. template <class T>
  127. [[nodiscard]] static inline T StripString(const T& from) {
  128. return TStripImpl<true, true>::StripString(from);
  129. }
  130. template <class T>
  131. [[nodiscard]] static inline T StripStringLeft(const T& from) {
  132. return TStripImpl<true, false>::StripString(from);
  133. }
  134. template <class T>
  135. [[nodiscard]] static inline T StripStringRight(const T& from) {
  136. return TStripImpl<false, true>::StripString(from);
  137. }
  138. template <class T, class TStripCriterion>
  139. [[nodiscard]] static inline T StripStringLeft(const T& from, TStripCriterion&& criterion) {
  140. return TStripImpl<true, false>::StripString(from, criterion);
  141. }
  142. template <class T, class TStripCriterion>
  143. [[nodiscard]] static inline T StripStringRight(const T& from, TStripCriterion&& criterion) {
  144. return TStripImpl<false, true>::StripString(from, criterion);
  145. }
  146. /// Copies the given string removing leading and trailing spaces.
  147. static inline bool Strip(const TString& from, TString& to) {
  148. return StripString(from, to);
  149. }
  150. /// Removes leading and trailing spaces from the string.
  151. inline TString& StripInPlace(TString& s) {
  152. Strip(s, s);
  153. return s;
  154. }
  155. template <typename T>
  156. inline void StripInPlace(T& s) {
  157. StripString(s, s);
  158. }
  159. /// Returns a copy of the given string with removed leading and trailing spaces.
  160. [[nodiscard]] inline TString Strip(const TString& s) {
  161. TString ret = s;
  162. Strip(ret, ret);
  163. return ret;
  164. }
  165. template <class TChar, class TWhitespaceFunc>
  166. size_t CollapseImpl(TChar* s, size_t n, const TWhitespaceFunc& isWhitespace) {
  167. size_t newLen = 0;
  168. for (size_t i = 0; i < n; ++i, ++newLen) {
  169. size_t nextNonSpace = i;
  170. while (nextNonSpace < n && isWhitespace(s[nextNonSpace])) {
  171. ++nextNonSpace;
  172. }
  173. size_t numSpaces = nextNonSpace - i;
  174. if (numSpaces > 1 || (numSpaces == 1 && s[i] != ' ')) {
  175. s[newLen] = ' ';
  176. i = nextNonSpace - 1;
  177. } else {
  178. s[newLen] = s[i];
  179. }
  180. }
  181. return newLen;
  182. }
  183. template <class TStringType, class TWhitespaceFunc>
  184. bool CollapseImpl(const TStringType& from, TStringType& to, size_t maxLen, const TWhitespaceFunc& isWhitespace) {
  185. to = from;
  186. maxLen = maxLen ? Min(maxLen, to.size()) : to.size();
  187. for (size_t i = 0; i < maxLen; ++i) {
  188. if (isWhitespace(to[i]) && (to[i] != ' ' || isWhitespace(to[i + 1]))) {
  189. size_t tailSize = maxLen - i;
  190. size_t newTailSize = CollapseImpl(to.begin() + i, tailSize, isWhitespace);
  191. to.remove(i + newTailSize, tailSize - newTailSize);
  192. return true;
  193. }
  194. }
  195. return false;
  196. }
  197. template <class TStringType, class TWhitespaceFunc>
  198. std::enable_if_t<std::is_invocable_v<TWhitespaceFunc, typename TStringType::value_type>, bool> Collapse(
  199. const TStringType& from, TStringType& to, TWhitespaceFunc isWhitespace, size_t maxLen = 0)
  200. {
  201. return CollapseImpl(from, to, maxLen, isWhitespace);
  202. }
  203. template <class TStringType>
  204. inline bool Collapse(const TStringType& from, TStringType& to, size_t maxLen = 0) {
  205. return Collapse(from, to, IsAsciiSpace<typename TStringType::value_type>, maxLen);
  206. }
  207. /// Replaces several consequtive space symbols with one (processing is limited to maxLen bytes)
  208. template <class TStringType>
  209. inline TStringType& CollapseInPlace(TStringType& s, size_t maxLen = 0) {
  210. Collapse(s, s, maxLen);
  211. return s;
  212. }
  213. template <class TStringType, class TWhitespaceFunc>
  214. inline TStringType& CollapseInPlace(TStringType& s, TWhitespaceFunc isWhitespace, size_t maxLen = 0) {
  215. Collapse(s, s, isWhitespace, maxLen);
  216. return s;
  217. }
  218. /// Replaces several consequtive space symbols with one (processing is limited to maxLen bytes)
  219. template <class TStringType>
  220. [[nodiscard]] inline TStringType Collapse(const TStringType& s, size_t maxLen = 0) {
  221. TStringType ret;
  222. Collapse(s, ret, maxLen);
  223. return ret;
  224. }
  225. void CollapseText(const TString& from, TString& to, size_t maxLen);
  226. /// The same as Collapse() + truncates the string to maxLen.
  227. /// @details An ellipsis is inserted at the end of the truncated line.
  228. inline void CollapseText(TString& s, size_t maxLen) {
  229. TString to;
  230. CollapseText(s, to, maxLen);
  231. s = to;
  232. }