Line data Source code
1 : // Copyright (c) 2011-2022 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 2 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 along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : //
20 : #pragma once
21 :
22 : /** \file
23 : * \brief Template used to trim a string.
24 : *
25 : * This function will trim the start, end, and inside of a string.
26 : *
27 : * The function works with any standard string. The characters to trim
28 : * are themselves to be defined in a string.
29 : *
30 : * The function also takes three flags to determine where the trimming
31 : * is to happen.
32 : */
33 :
34 : // self
35 : //
36 : #include <snapdev/reverse_cstring.h>
37 :
38 :
39 : // C++
40 : //
41 : #include <algorithm>
42 : #include <cwctype>
43 : #include <string>
44 :
45 :
46 :
47 : namespace snapdev
48 : {
49 :
50 :
51 : /** \brief Trim a string.
52 : *
53 : * This function goes through the input string and remove
54 : * \p trim_characters from the \p trim_start, the \p trim_end, and the
55 : * \p trim_inside.
56 : *
57 : * If no \p trim_characters are specified (empty string) then the default
58 : * applies. The default uses the `iswspace()` on each character.
59 : *
60 : * \todo
61 : * Add support for UTF-8 (in which case we need to move this to our
62 : * libutf8 library?).
63 : *
64 : * \tparam StringT The type of container used to output the tokens.
65 : * \param[in] str The string to trim.
66 : * \param[in] trim_start Trim the start of the input string.
67 : * \param[in] trim_end Trim the end of the input string.
68 : * \param[in] trim_inside Trim the inside of the input string.
69 : * \param[in] trim_characters Trim those characters from the start/inside/end.
70 : *
71 : * \return The trimmed string.
72 : */
73 : template<class StringT>
74 48 : StringT trim_string(
75 : StringT const & str
76 : , bool const trim_start = true
77 : , bool const trim_end = true
78 : , bool const trim_inside = false
79 : , StringT const & trim_characters = StringT())
80 : {
81 48 : typename StringT::value_type const * start(str.data());
82 48 : typename StringT::value_type const * end(str.data() + str.length());
83 :
84 48 : if(trim_start)
85 : {
86 24 : start = std::find_if_not(
87 : start
88 : , end
89 64 : , [&trim_characters](auto const c)
90 96 : {
91 64 : if(trim_characters.empty())
92 : {
93 32 : return std::iswspace(c) != 0;
94 : }
95 32 : return trim_characters.find(c) != StringT::npos;
96 : });
97 : }
98 :
99 48 : if(start < end
100 48 : && trim_end)
101 : {
102 24 : reverse_cstring<typename StringT::value_type const> const rstr(start, end);
103 24 : auto const p(std::find_if_not(
104 : rstr.begin()
105 : , rstr.end()
106 56 : , [&trim_characters](auto const c)
107 80 : {
108 56 : if(trim_characters.empty())
109 : {
110 32 : return std::iswspace(c) != 0;
111 : }
112 24 : return trim_characters.find(c) != StringT::npos;
113 : }));
114 24 : end = p.get();
115 : }
116 :
117 48 : if(!trim_inside)
118 : {
119 24 : return StringT(start, end);
120 : }
121 :
122 : // in this case, we want to copy the characters one by one
123 : //
124 24 : bool space(false);
125 48 : StringT result;
126 24 : result.reserve(end - start);
127 :
128 24 : if(!trim_start)
129 : {
130 164 : for(; start < end && !space; ++start)
131 : {
132 76 : result += *start;
133 76 : if(trim_characters.empty())
134 : {
135 38 : space = std::iswspace(*start);
136 : }
137 : else
138 : {
139 38 : space = trim_characters.find(*start) != StringT::npos;
140 : }
141 : }
142 : }
143 :
144 24 : if(trim_characters.empty())
145 : {
146 824 : for(; start < end; ++start)
147 : {
148 406 : if(space)
149 : {
150 180 : space = std::iswspace(*start);
151 180 : if(!space)
152 : {
153 40 : result += *start;
154 : }
155 : }
156 : else
157 : {
158 226 : space = std::iswspace(*start);
159 226 : if(space)
160 : {
161 40 : result += ' ';
162 : }
163 : else
164 : {
165 186 : result += *start;
166 : }
167 : }
168 : }
169 : }
170 : else
171 : {
172 832 : for(; start < end; ++start)
173 : {
174 410 : if(space)
175 : {
176 150 : space = trim_characters.find(*start) != StringT::npos;
177 150 : if(!space)
178 : {
179 68 : result += *start;
180 : }
181 : }
182 : else
183 : {
184 260 : space = trim_characters.find(*start) != StringT::npos;
185 260 : if(space)
186 : {
187 66 : result += ' ';
188 : }
189 : else
190 : {
191 194 : result += *start;
192 : }
193 : }
194 : }
195 : }
196 :
197 24 : return result;
198 : }
199 :
200 : } // namespace snapdev
201 : // vim: ts=4 sw=4 et
|