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++ lib
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 : * \todo
58 : * Add support for UTF-8 (in which case we need to move this to our
59 : * libutf8 library?).
60 : *
61 : * \tparam StringT The type of container used to output the tokens.
62 : * \param[in] str The string to trim.
63 : * \param[in] trim_start Trim the start of the input string.
64 : * \param[in] trim_end Trim the end of the input string.
65 : * \param[in] trim_inside Trim the inside of the input string.
66 : * \param[in] trim_characters Trim those characters from the start/inside/end.
67 : *
68 : * \return The trimmed string.
69 : */
70 : template<class StringT>
71 48 : StringT trim_string(
72 : StringT const & str
73 : , bool const trim_start = true
74 : , bool const trim_end = true
75 : , bool const trim_inside = false
76 : , StringT const & trim_characters = StringT())
77 : {
78 48 : typename StringT::value_type const * start(str.data());
79 48 : typename StringT::value_type const * end(str.data() + str.length());
80 :
81 48 : if(trim_start)
82 : {
83 24 : start = std::find_if_not(
84 : start
85 : , end
86 64 : , [&trim_characters](auto const c)
87 96 : {
88 64 : if(trim_characters.empty())
89 : {
90 32 : return std::iswspace(c) != 0;
91 : }
92 32 : return trim_characters.find(c) != StringT::npos;
93 : });
94 : }
95 :
96 48 : if(start < end
97 48 : && trim_end)
98 : {
99 24 : reverse_cstring<typename StringT::value_type const> const rstr(start, end);
100 24 : auto const p(std::find_if_not(
101 : rstr.begin()
102 : , rstr.end()
103 56 : , [&trim_characters](auto const c)
104 80 : {
105 56 : if(trim_characters.empty())
106 : {
107 32 : return std::iswspace(c) != 0;
108 : }
109 24 : return trim_characters.find(c) != StringT::npos;
110 : }));
111 24 : end = p.get();
112 : }
113 :
114 48 : if(!trim_inside)
115 : {
116 24 : return StringT(start, end);
117 : }
118 :
119 : // in this case, we want to copy the characters one by one
120 : //
121 24 : bool space(false);
122 48 : StringT result;
123 24 : result.reserve(end - start);
124 :
125 24 : if(!trim_start)
126 : {
127 164 : for(; start < end && !space; ++start)
128 : {
129 76 : result += *start;
130 76 : if(trim_characters.empty())
131 : {
132 38 : space = std::iswspace(*start);
133 : }
134 : else
135 : {
136 38 : space = trim_characters.find(*start) != StringT::npos;
137 : }
138 : }
139 : }
140 :
141 24 : if(trim_characters.empty())
142 : {
143 824 : for(; start < end; ++start)
144 : {
145 406 : if(space)
146 : {
147 180 : space = std::iswspace(*start);
148 180 : if(!space)
149 : {
150 40 : result += *start;
151 : }
152 : }
153 : else
154 : {
155 226 : space = std::iswspace(*start);
156 226 : if(space)
157 : {
158 40 : result += ' ';
159 : }
160 : else
161 : {
162 186 : result += *start;
163 : }
164 : }
165 : }
166 : }
167 : else
168 : {
169 832 : for(; start < end; ++start)
170 : {
171 410 : if(space)
172 : {
173 150 : space = trim_characters.find(*start) != StringT::npos;
174 150 : if(!space)
175 : {
176 68 : result += *start;
177 : }
178 : }
179 : else
180 : {
181 260 : space = trim_characters.find(*start) != StringT::npos;
182 260 : if(space)
183 : {
184 66 : result += ' ';
185 : }
186 : else
187 : {
188 194 : result += *start;
189 : }
190 : }
191 : }
192 : }
193 :
194 24 : return result;
195 : }
196 :
197 : } // namespace snapdev
198 : // vim: ts=4 sw=4 et
|