CLI11  2.5.0
StringTools.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2025, University of Cincinnati, developed by Henry Schreiner
2 // under NSF AWARD 1414736 and by the respective contributors.
3 // All rights reserved.
4 //
5 // SPDX-License-Identifier: BSD-3-Clause
6 
7 #pragma once
8 
9 // IWYU pragma: private, include "CLI/CLI.hpp"
10 
11 // [CLI11:public_includes:set]
12 #include <algorithm>
13 #include <iomanip>
14 #include <locale>
15 #include <sstream>
16 #include <stdexcept>
17 #include <string>
18 #include <type_traits>
19 #include <vector>
20 // [CLI11:public_includes:end]
21 
22 #include "Macros.hpp"
23 
24 namespace CLI {
25 
26 // [CLI11:string_tools_hpp:verbatim]
27 
30 namespace enums {
31 
33 template <typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
34 std::ostream &operator<<(std::ostream &in, const T &item) {
35  // make sure this is out of the detail namespace otherwise it won't be found when needed
36  return in << static_cast<typename std::underlying_type<T>::type>(item);
37 }
38 
39 } // namespace enums
40 
42 using enums::operator<<;
43 
44 namespace detail {
47 constexpr int expected_max_vector_size{1 << 29};
48 // Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
50 CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim);
51 
53 template <typename T> std::string join(const T &v, std::string delim = ",") {
54  std::ostringstream s;
55  auto beg = std::begin(v);
56  auto end = std::end(v);
57  if(beg != end)
58  s << *beg++;
59  while(beg != end) {
60  s << delim << *beg++;
61  }
62  auto rval = s.str();
63  if(!rval.empty() && delim.size() == 1 && rval.back() == delim[0]) {
64  // remove trailing delimiter if the last entry was empty
65  rval.pop_back();
66  }
67  return rval;
68 }
69 
71 template <typename T,
72  typename Callable,
73  typename = typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
74 std::string join(const T &v, Callable func, std::string delim = ",") {
75  std::ostringstream s;
76  auto beg = std::begin(v);
77  auto end = std::end(v);
78  auto loc = s.tellp();
79  while(beg != end) {
80  auto nloc = s.tellp();
81  if(nloc > loc) {
82  s << delim;
83  loc = nloc;
84  }
85  s << func(*beg++);
86  }
87  return s.str();
88 }
89 
91 template <typename T> std::string rjoin(const T &v, std::string delim = ",") {
92  std::ostringstream s;
93  for(std::size_t start = 0; start < v.size(); start++) {
94  if(start > 0)
95  s << delim;
96  s << v[v.size() - start - 1];
97  }
98  return s.str();
99 }
100 
101 // Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string
102 
104 CLI11_INLINE std::string &ltrim(std::string &str);
105 
107 CLI11_INLINE std::string &ltrim(std::string &str, const std::string &filter);
108 
110 CLI11_INLINE std::string &rtrim(std::string &str);
111 
113 CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter);
114 
116 inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
117 
119 inline std::string &trim(std::string &str, const std::string filter) { return ltrim(rtrim(str, filter), filter); }
120 
122 inline std::string trim_copy(const std::string &str) {
123  std::string s = str;
124  return trim(s);
125 }
126 
128 CLI11_INLINE std::string &remove_quotes(std::string &str);
129 
131 CLI11_INLINE void remove_quotes(std::vector<std::string> &args);
132 
137 CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input);
138 
140 inline std::string trim_copy(const std::string &str, const std::string &filter) {
141  std::string s = str;
142  return trim(s, filter);
143 }
144 
146 CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid);
147 
150 template <typename T> bool valid_first_char(T c) {
151  return ((c != '-') && (static_cast<unsigned char>(c) > 33)); // space and '!' not allowed
152 }
153 
155 template <typename T> bool valid_later_char(T c) {
156  // = and : are value separators, { has special meaning for option defaults,
157  // and control codes other than tab would just be annoying to deal with in many places allowing space here has too
158  // much potential for inadvertent entry errors and bugs
159  return ((c != '=') && (c != ':') && (c != '{') && ((static_cast<unsigned char>(c) > 32) || c == '\t'));
160 }
161 
163 CLI11_INLINE bool valid_name_string(const std::string &str);
164 
166 inline bool valid_alias_name_string(const std::string &str) {
167  static const std::string badChars(std::string("\n") + '\0');
168  return (str.find_first_of(badChars) == std::string::npos);
169 }
170 
172 inline bool is_separator(const std::string &str) {
173  static const std::string sep("%%");
174  return (str.empty() || str == sep);
175 }
176 
178 inline bool isalpha(const std::string &str) {
179  return std::all_of(str.begin(), str.end(), [](char c) { return std::isalpha(c, std::locale()); });
180 }
181 
183 inline std::string to_lower(std::string str) {
184  std::transform(std::begin(str), std::end(str), std::begin(str), [](const std::string::value_type &x) {
185  return std::tolower(x, std::locale());
186  });
187  return str;
188 }
189 
191 inline std::string remove_underscore(std::string str) {
192  str.erase(std::remove(std::begin(str), std::end(str), '_'), std::end(str));
193  return str;
194 }
195 
197 CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to);
198 
200 inline bool has_default_flag_values(const std::string &flags) {
201  return (flags.find_first_of("{!") != std::string::npos);
202 }
203 
204 CLI11_INLINE void remove_default_flag_values(std::string &flags);
205 
207 CLI11_INLINE std::ptrdiff_t find_member(std::string name,
208  const std::vector<std::string> names,
209  bool ignore_case = false,
210  bool ignore_underscore = false);
211 
214 template <typename Callable> inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) {
215  std::size_t start_pos = 0;
216  while((start_pos = str.find(trigger, start_pos)) != std::string::npos) {
217  start_pos = modify(str, start_pos);
218  }
219  return str;
220 }
221 
224 CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char);
225 
228 CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter = '\0');
229 
231 CLI11_INLINE std::string get_environment_value(const std::string &env_name);
232 
237 CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
238 
242 CLI11_INLINE bool has_escapable_character(const std::string &str);
243 
247 CLI11_INLINE std::string add_escaped_characters(const std::string &str);
248 
250 CLI11_INLINE std::string remove_escaped_characters(const std::string &str);
251 
253 CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape);
254 
255 CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string);
256 
258 CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string);
259 
261 CLI11_INLINE bool process_quoted_string(std::string &str, char string_char = '\"', char literal_char = '\'');
262 
265 CLI11_INLINE std::ostream &streamOutAsParagraph(std::ostream &out,
266  const std::string &text,
267  std::size_t paragraphWidth,
268  const std::string &linePrefix = "",
269  bool skipPrefixOnFirstLine = false);
270 
271 } // namespace detail
272 
273 // [CLI11:string_tools_hpp:end]
274 
275 } // namespace CLI
276 
277 #ifndef CLI11_COMPILE
278 #include "impl/StringTools_inl.hpp" // IWYU pragma: export
279 #endif
std::string trim_copy(const std::string &str)
Make a copy of the string and then trim it.
Definition: StringTools.hpp:122
Definition: App.hpp:36
CLI11_INLINE std::string & remove_quotes(std::string &str)
remove quotes at the front and back of a string either '"' or '\''
CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape)
generate a string with all non printable characters escaped to hex codes
std::string ignore_case(std::string item)
Helper function to allow ignore_case to be passed to IsMember or Transform.
Definition: Validators.hpp:695
bool valid_later_char(T c)
Verify following characters of an option.
Definition: StringTools.hpp:155
bool is_separator(const std::string &str)
check if a string is a container segment separator (empty or "%%")
Definition: StringTools.hpp:172
std::string rjoin(const T &v, std::string delim=",")
Join a string in reverse order.
Definition: StringTools.hpp:91
CLI11_INLINE std::ostream & format_aliases(std::ostream &out, const std::vector< std::string > &aliases, std::size_t wid)
Print subcommand aliases.
CLI11_INLINE bool valid_name_string(const std::string &str)
Verify an option/subcommand name.
CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input)
#define CLI11_INLINE
Definition: Macros.hpp:150
std::ostream & operator<<(std::ostream &in, const T &item)
output streaming for enumerations
Definition: StringTools.hpp:34
std::string ignore_underscore(std::string item)
Helper function to allow ignore_underscore to be passed to IsMember or Transform. ...
Definition: Validators.hpp:698
std::string find_and_modify(std::string str, std::string trigger, Callable modify)
Definition: StringTools.hpp:214
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition: StringTools.hpp:53
CLI11_INLINE std::ostream & streamOutAsParagraph(std::ostream &out, const std::string &text, std::size_t paragraphWidth, const std::string &linePrefix="", bool skipPrefixOnFirstLine=false)
std::string & trim(std::string &str)
Trim whitespace from string.
Definition: StringTools.hpp:116
CLI11_INLINE std::string & rtrim(std::string &str)
Trim whitespace from right of string.
std::string remove_underscore(std::string str)
remove underscores from a string
Definition: StringTools.hpp:191
CLI11_INLINE std::string & ltrim(std::string &str)
Trim whitespace from left of string.
CLI11_INLINE std::vector< std::string > split_up(std::string str, char delimiter= '\0')
CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string)
CLI11_INLINE std::string remove_escaped_characters(const std::string &str)
replace the escaped characters with their equivalent
std::string to_lower(std::string str)
Return a lower case version of a string.
Definition: StringTools.hpp:183
CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to)
Find and replace a substring with another substring.
CLI11_INLINE bool process_quoted_string(std::string &str, char string_char= '\"', char literal_char = '\'')
process a quoted string, remove the quotes and if appropriate handle escaped characters ...
CLI11_INLINE std::string add_escaped_characters(const std::string &str)
escape all escapable characters
CLI11_INLINE std::ptrdiff_t find_member(std::string name, const std::vector< std::string > names, bool ignore_case=false, bool ignore_underscore=false)
Check if a string is a member of a list of strings and optionally ignore case or ignore underscores...
CLI11_INLINE std::vector< std::string > split(const std::string &s, char delim)
Split a string by a delim.
CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset)
CLI11_INLINE void remove_default_flag_values(std::string &flags)
CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char)
CLI11_INLINE bool has_escapable_character(const std::string &str)
detect if a string has escapable characters
CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string)
extract an escaped binary_string
bool valid_first_char(T c)
Definition: StringTools.hpp:150
bool has_default_flag_values(const std::string &flags)
check if the flag definitions has possible false flags
Definition: StringTools.hpp:200
bool valid_alias_name_string(const std::string &str)
Verify an app name.
Definition: StringTools.hpp:166
CLI11_INLINE std::string get_environment_value(const std::string &env_name)
get the value of an environmental variable or empty string if empty
constexpr int expected_max_vector_size
Definition: StringTools.hpp:47
bool isalpha(const std::string &str)
Verify that str consists of letters only.
Definition: StringTools.hpp:178