Fcitx
stringutils.h
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2015-2017 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX_UTILS_STRINGUTILS_H_
8 #define _FCITX_UTILS_STRINGUTILS_H_
9 
10 /// \addtogroup FcitxUtils
11 /// \{
12 /// \file
13 /// \brief String handle utilities.
14 
15 #include <cstddef>
16 #include <initializer_list>
17 #include <iterator>
18 #include <optional>
19 #include <string>
20 #include <string_view>
21 #include <utility>
22 #include <vector>
23 #include <fcitx-utils/fcitxutils_export.h>
24 #include <fcitx-utils/stringutils_details.h> // IWYU pragma: export
25 
26 namespace fcitx::stringutils {
27 
28 /// \brief Check if a string starts with a prefix.
29 FCITXUTILS_DEPRECATED_EXPORT bool startsWith(std::string_view str,
30  std::string_view prefix);
31 
32 /// \brief Check if a string starts with a prefix char.
33 inline bool startsWith(std::string_view str, char prefix) {
34  return !str.empty() && str.front() == prefix;
35 }
36 
37 /// \brief Check if a string ends with a suffix.
38 FCITXUTILS_DEPRECATED_EXPORT bool endsWith(std::string_view str,
39  std::string_view suffix);
40 
41 /// \brief Check if a string ends with a suffix char.
42 inline bool endsWith(std::string_view str, char suffix) {
43  return !str.empty() && str.back() == suffix;
44 }
45 
46 /// \brief Check if a string is a concatenation of two other strings
47 inline bool isConcatOf(std::string_view str, std::string_view sub1,
48  std::string_view sub2) {
49  return str.size() == sub1.size() + sub2.size() && str.starts_with(sub1) &&
50  str.ends_with(sub2);
51 }
52 
53 /// \brief Trim the whitespace by returning start end end of first and list non
54 /// whitespace character position.
55 ///
56 /// Will return a pair of equal value all characters are whitespace.
57 FCITXUTILS_EXPORT std::pair<std::string::size_type, std::string::size_type>
58 trimInplace(std::string_view str);
59 
60 /// \brief Trim the white space in string view
61 /// \see trimInplace
62 /// \since 5.0.16
63 FCITXUTILS_EXPORT std::string_view trimView(std::string_view);
64 
65 /// \brief Trim the white space in str.
66 /// \see trimInplace
67 FCITXUTILS_EXPORT std::string trim(std::string_view str);
68 
69 /// \brief Split the string by delim.
70 FCITXUTILS_EXPORT std::vector<std::string> split(std::string_view str,
71  std::string_view delim);
72 
73 enum class SplitBehavior { KeepEmpty, SkipEmpty };
74 
75 /// \brief Split the string by delim.
76 FCITXUTILS_EXPORT std::vector<std::string>
77 split(std::string_view str, std::string_view delim, SplitBehavior behavior);
78 
79 /// \brief Replace all substring appearance of before with after.
80 FCITXUTILS_EXPORT std::string replaceAll(std::string str,
81  const std::string &before,
82  const std::string &after);
83 
84 /// \brief Search string needle of size ol in string haystack.
85 /// \param from the number of bytes from end.
86 /// \return point to data or null.
87 FCITXUTILS_EXPORT const char *backwardSearch(const char *haystack, size_t l,
88  const char *needle, size_t ol,
89  size_t from);
90 
91 /// \brief The non-const version of backwardSearch
92 /// \see backwardSearch()
93 FCITXUTILS_EXPORT char *backwardSearch(char *haystack, size_t l,
94  const char *needle, size_t ol,
95  size_t from);
96 
97 /// \brief Fast backward substring search.
98 /// \return back from end.
99 ///
100 /// Example:
101 /// stringutils::backwardSearch("abcabc", "bc", 1) == 1
102 /// stringutils::backwardSearch("abcabc", "bc", 1) == 1
103 /// stringutils::backwardSearch("abcabc", "bc", 4) == 4
104 FCITXUTILS_EXPORT size_t backwardSearch(const std::string &haystack,
105  const std::string &needle, size_t from);
106 
107 /// \brief Join a range of string with delim.
108 template <typename Iter, typename T>
109 inline std::string join(Iter start, Iter end, T &&delim) {
110  std::string result;
111  if (start != end) {
112  result += (*start);
113  start++;
114  }
115  for (; start != end; start++) {
116  result += (delim);
117  result += (*start);
118  }
119  return result;
120 }
121 
122 /// \brief Join a set of string with delim.
123 template <typename C, typename T>
124 inline std::string join(C &&container, T &&delim) {
125  using std::begin;
126  using std::end;
127  return join(begin(container), end(container), delim);
128 }
129 
130 /// \brief Join the strings with delim.
131 template <typename C, typename T>
132 inline std::string join(std::initializer_list<C> &&container, T &&delim) {
133  using std::begin;
134  using std::end;
135  return join(begin(container), end(container), delim);
136 }
137 
138 template <typename... Args>
139 std::string concat(const Args &...args) {
140  using namespace ::fcitx::stringutils::details;
141  return concatPieces({static_cast<const UniversalPiece &>(
143  .toPair()...});
144 }
145 
146 template <typename FirstArg, typename... Args>
147 std::string joinPath(const FirstArg &firstArg, const Args &...args) {
148  using namespace ::fcitx::stringutils::details;
149  return concatPathPieces(
150  {static_cast<const UniversalPiece &>(
151  UniversalPieceHelper<FirstArg>::forward(firstArg))
152  .toPathPair(false),
153  static_cast<const UniversalPiece &>(
154  UniversalPieceHelper<Args>::forward(args))
155  .toPathPair()...});
156 }
157 
158 constexpr bool literalEqual(char const *a, char const *b) {
159  return *a == *b && (*a == '\0' || literalEqual(a + 1, b + 1));
160 }
161 
162 /**
163  * \brief Inplace unescape a string contains slash, new line, optionally quote.
164  *
165  * \param str the string to unescape, will be modified.
166  * \param unescapeQuote whether to unescape quote.
167  */
168 FCITXUTILS_EXPORT bool unescape(std::string &str, bool unescapeQuote);
169 
170 /**
171  * \brief unescape a string if it is quoted, otherwise return the original
172  * string.
173  *
174  * Will return nullopt if the escape is invalid.
175  *
176  * \param str input string.
177  * \return unescaped string
178  * \see escapeForValue
179  * \since 5.0.16
180  */
181 FCITXUTILS_EXPORT std::optional<std::string>
182 unescapeForValue(std::string_view str);
183 
184 /**
185  * \brief escape a string if str contains certain characters.
186  *
187  * The characters include all FCITX_WHITESPACE, backslash, quote, space.
188  *
189  * \param str input string.
190  * \return quoted escaped string, or the original string if no escape is needed.
191  * \see unescapeForValue
192  * \since 5.0.16
193  */
194 FCITXUTILS_EXPORT std::string escapeForValue(std::string_view str);
195 
196 /**
197  * Return a substring of input str if str starts with given prefix.
198  *
199  * \param str input string
200  * \param prefix to check
201  * \since 5.1.12
202  */
203 FCITXUTILS_EXPORT bool consumePrefix(std::string_view &str,
204  std::string_view prefix);
205 
206 /**
207  * Consume a value that is potentially quoted and escaped. Useful for tokenize a
208  * line with multiple values.
209  *
210  * Logic is like:
211  * 1. skip leading character defined in skip.
212  * 2. if the first non-skip character is quote, consume until next unescaped
213  * quote. if the end is reached before finding the closing quote treat it as
214  * unquoted.
215  * 3. if the first non-skip character is not quote, consume until next skip
216  * character.
217  *
218  * \param input the string to consume from, will be updated to the remaining
219  * string after consuming.
220  * \param skip the characters to skip before and after the value.
221  * \param output the unescaped value, if not null.
222  * \return the consumed value range.
223  * \since 5.1.20
224  */
225 FCITXUTILS_EXPORT std::string_view
226 consumeMaybeEscapedValue(std::string_view &input, std::string_view skip,
227  std::string *output);
228 
229 } // namespace fcitx::stringutils
230 
231 #endif // _FCITX_UTILS_STRINGUTILS_H_
std::optional< std::string > unescapeForValue(std::string_view str)
unescape a string if it is quoted, otherwise return the original string.
bool unescape(std::string &str, bool unescapeQuote)
Inplace unescape a string contains slash, new line, optionally quote.
bool consumePrefix(std::string_view &str, std::string_view prefix)
Return a substring of input str if str starts with given prefix.
std::pair< std::string::size_type, std::string::size_type > trimInplace(std::string_view str)
Trim the whitespace by returning start end end of first and list non whitespace character position...
bool endsWith(std::string_view str, char suffix)
Check if a string ends with a suffix char.
Definition: stringutils.h:42
std::string_view consumeMaybeEscapedValue(std::string_view &input, std::string_view skip, std::string *output)
Consume a value that is potentially quoted and escaped.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
std::string_view trimView(std::string_view str)
Trim the white space in string view.
std::string join(std::initializer_list< C > &&container, T &&delim)
Join the strings with delim.
Definition: stringutils.h:132
const char * backwardSearch(const char *haystack, size_t l, const char *needle, size_t ol, size_t from)
Search string needle of size ol in string haystack.
std::string replaceAll(std::string str, const std::string &before, const std::string &after)
Replace all substring appearance of before with after.
std::string escapeForValue(std::string_view str)
escape a string if str contains certain characters.
std::string trim(std::string_view str)
Trim the white space in str.
bool isConcatOf(std::string_view str, std::string_view sub1, std::string_view sub2)
Check if a string is a concatenation of two other strings.
Definition: stringutils.h:47
bool startsWith(std::string_view str, char prefix)
Check if a string starts with a prefix char.
Definition: stringutils.h:33