Line data Source code
1 : // Copyright (c) 2011-2023 Made to Order Software Corp. All Rights Reserved 2 : // 3 : // https://snapwebsites.org/project/snapdev 4 : // contact@m2osw.com 5 : // 6 : // This program is free software: you can redistribute it and/or modify 7 : // it under the terms of the GNU General Public License as published by 8 : // the Free Software Foundation, either version 3 of the License, or 9 : // (at your option) any later version. 10 : // 11 : // This program is distributed in the hope that it will be useful, 12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : // GNU General Public License for more details. 15 : // 16 : // You should have received a copy of the GNU General Public License 17 : // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 : #pragma once 19 : 20 : /** \file 21 : * \brief Template used to trim a string. 22 : * 23 : * This function will trim the start, end, and inside of a string. 24 : * 25 : * The function works with any standard string. The characters to trim 26 : * are themselves to be defined in a string. 27 : * 28 : * The function also takes three flags to determine where the trimming 29 : * is to happen. 30 : */ 31 : 32 : // self 33 : // 34 : #include <snapdev/reverse_cstring.h> 35 : 36 : 37 : // C++ 38 : // 39 : #include <algorithm> 40 : #include <cwctype> 41 : #include <string> 42 : 43 : 44 : 45 : namespace snapdev 46 : { 47 : 48 : 49 : /** \brief Trim a string. 50 : * 51 : * This function goes through the input string and remove 52 : * \p trim_characters from the \p trim_start, the \p trim_end, and the 53 : * \p trim_inside. 54 : * 55 : * If no \p trim_characters are specified (empty string) then the default 56 : * applies. The default uses the `iswspace()` on each character. 57 : * 58 : * \todo 59 : * Add support for UTF-8 (in which case we need to move this to our 60 : * libutf8 library?). 61 : * 62 : * \tparam StringT The type of container used to output the tokens. 63 : * \param[in] str The string to trim. 64 : * \param[in] trim_start Trim the start of the input string. 65 : * \param[in] trim_end Trim the end of the input string. 66 : * \param[in] trim_inside Trim the inside of the input string. 67 : * \param[in] trim_characters Trim those characters from the start/inside/end. 68 : * 69 : * \return The trimmed string. 70 : */ 71 : template<class StringT> 72 48 : StringT trim_string( 73 : StringT const & str 74 : , bool const trim_start = true 75 : , bool const trim_end = true 76 : , bool const trim_inside = false 77 : , StringT const & trim_characters = StringT()) 78 : { 79 48 : typename StringT::value_type const * start(str.data()); 80 48 : typename StringT::value_type const * end(str.data() + str.length()); 81 : 82 48 : if(trim_start) 83 : { 84 24 : start = std::find_if_not( 85 : start 86 : , end 87 96 : , [&trim_characters](auto const c) 88 : { 89 64 : if(trim_characters.empty()) 90 : { 91 32 : return std::iswspace(c) != 0; 92 : } 93 32 : return trim_characters.find(c) != StringT::npos; 94 : }); 95 : } 96 : 97 48 : if(start < end 98 48 : && trim_end) 99 : { 100 24 : reverse_cstring<typename StringT::value_type const> const rstr(start, end); 101 24 : auto const p(std::find_if_not( 102 : rstr.begin() 103 : , rstr.end() 104 80 : , [&trim_characters](auto const c) 105 : { 106 56 : if(trim_characters.empty()) 107 : { 108 32 : return std::iswspace(c) != 0; 109 : } 110 24 : return trim_characters.find(c) != StringT::npos; 111 : })); 112 24 : end = p.get(); 113 : } 114 : 115 48 : if(!trim_inside) 116 : { 117 24 : return StringT(start, end); 118 : } 119 : 120 : // in this case, we want to copy the characters one by one 121 : // 122 24 : bool space(false); 123 24 : StringT result; 124 24 : result.reserve(end - start); 125 : 126 24 : if(!trim_start) 127 : { 128 88 : for(; start < end && !space; ++start) 129 : { 130 76 : result += *start; 131 76 : if(trim_characters.empty()) 132 : { 133 38 : space = std::iswspace(*start); 134 : } 135 : else 136 : { 137 38 : space = trim_characters.find(*start) != StringT::npos; 138 : } 139 : } 140 : } 141 : 142 24 : if(trim_characters.empty()) 143 : { 144 418 : for(; start < end; ++start) 145 : { 146 406 : if(space) 147 : { 148 180 : space = std::iswspace(*start); 149 180 : if(!space) 150 : { 151 40 : result += *start; 152 : } 153 : } 154 : else 155 : { 156 226 : space = std::iswspace(*start); 157 226 : if(space) 158 : { 159 40 : result += ' '; 160 : } 161 : else 162 : { 163 186 : result += *start; 164 : } 165 : } 166 : } 167 : } 168 : else 169 : { 170 422 : for(; start < end; ++start) 171 : { 172 410 : if(space) 173 : { 174 150 : space = trim_characters.find(*start) != StringT::npos; 175 150 : if(!space) 176 : { 177 68 : result += *start; 178 : } 179 : } 180 : else 181 : { 182 260 : space = trim_characters.find(*start) != StringT::npos; 183 260 : if(space) 184 : { 185 66 : result += ' '; 186 : } 187 : else 188 : { 189 194 : result += *start; 190 : } 191 : } 192 : } 193 : } 194 : 195 24 : return result; 196 24 : } 197 : 198 : } // namespace snapdev 199 : // vim: ts=4 sw=4 et