CLI11
C++11 Command Line Interface Parser
Loading...
Searching...
No Matches
StringTools.hpp
1// Copyright (c) 2017-2026, 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
24namespace CLI {
25
26// [CLI11:string_tools_hpp:verbatim]
27
30namespace enums {
31
33template <typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
34std::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 // https://isocpp.org/wiki/faq/input-output#print-char-or-ptr-as-number
37 return in << +static_cast<typename std::underlying_type<T>::type>(item);
38}
39
40} // namespace enums
41
43using enums::operator<<;
44
45namespace detail {
48CLI11_MODULE_INLINE constexpr int expected_max_vector_size{1 << 29};
49// Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
51CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim);
52
54template <typename T> std::string join(const T &v, std::string delim = ",") {
55 std::ostringstream s;
56 auto beg = std::begin(v);
57 auto end = std::end(v);
58 if(beg != end)
59 s << *beg++;
60 while(beg != end) {
61 s << delim << *beg++;
62 }
63 auto rval = s.str();
64 if(!rval.empty() && delim.size() == 1 && rval.back() == delim[0]) {
65 // remove trailing delimiter if the last entry was empty
66 rval.pop_back();
67 }
68 return rval;
69}
70
72template <typename T,
73 typename Callable,
74 typename = typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
75std::string join(const T &v, Callable func, std::string delim = ",") {
76 std::ostringstream s;
77 auto beg = std::begin(v);
78 auto end = std::end(v);
79 auto loc = s.tellp();
80 while(beg != end) {
81 auto nloc = s.tellp();
82 if(nloc > loc) {
83 s << delim;
84 loc = nloc;
85 }
86 s << func(*beg++);
87 }
88 return s.str();
89}
90
92template <typename T> std::string rjoin(const T &v, std::string delim = ",") {
93 std::ostringstream s;
94 for(std::size_t start = 0; start < v.size(); start++) {
95 if(start > 0)
96 s << delim;
97 s << v[v.size() - start - 1];
98 }
99 return s.str();
100}
101
102// Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string
103
105CLI11_INLINE std::string &ltrim(std::string &str);
106
108CLI11_INLINE std::string &ltrim(std::string &str, const std::string &filter);
109
111CLI11_INLINE std::string &rtrim(std::string &str);
112
114CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter);
115
117inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
118
120inline std::string &trim(std::string &str, const std::string &filter) { return ltrim(rtrim(str, filter), filter); }
121
123inline std::string trim_copy(const std::string &str) {
124 std::string s = str;
125 return trim(s);
126}
127
129CLI11_INLINE std::string &remove_outer(std::string &str, char key);
130
132CLI11_INLINE std::string &remove_quotes(std::string &str);
133
135CLI11_INLINE void remove_quotes(std::vector<std::string> &args);
136
141CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input);
142
144inline std::string trim_copy(const std::string &str, const std::string &filter) {
145 std::string s = str;
146 return trim(s, filter);
147}
148
150CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid);
151
154template <typename T> bool valid_first_char(T c) {
155 return ((c != '-') && (static_cast<unsigned char>(c) > 33)); // space and '!' not allowed
156}
157
159template <typename T> bool valid_later_char(T c) {
160 // = and : are value separators, { has special meaning for option defaults,
161 // and control codes other than tab would just be annoying to deal with in many places allowing space here has too
162 // much potential for inadvertent entry errors and bugs
163 return ((c != '=') && (c != ':') && (c != '{') && ((static_cast<unsigned char>(c) > 32) || c == '\t'));
164}
165
167CLI11_INLINE bool valid_name_string(const std::string &str);
168
170inline bool valid_alias_name_string(const std::string &str) {
171 return ((str.find_first_of('\n') == std::string::npos) && (str.find_first_of('\0') == std::string::npos));
172}
173
175inline bool is_separator(const std::string &str) {
176 return (str.empty() || (str.size() == 2 && str[0] == '%' && str[1] == '%'));
177}
178
180inline bool isalpha(const std::string &str) {
181 return std::all_of(str.begin(), str.end(), [](char c) { return std::isalpha(c, std::locale()); });
182}
183
185inline std::string to_lower(std::string str) {
186 std::transform(std::begin(str), std::end(str), std::begin(str), [](const std::string::value_type &x) {
187 return std::tolower(x, std::locale());
188 });
189 return str;
190}
191
193inline std::string remove_underscore(std::string str) {
194 str.erase(std::remove(std::begin(str), std::end(str), '_'), std::end(str));
195 return str;
196}
197
200CLI11_INLINE std::string get_group_separators();
201
203CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to);
204
206inline bool has_default_flag_values(const std::string &flags) {
207 return (flags.find_first_of("{!") != std::string::npos);
208}
209
210CLI11_INLINE void remove_default_flag_values(std::string &flags);
211
213CLI11_INLINE std::ptrdiff_t find_member(std::string name,
214 const std::vector<std::string> &names,
215 bool ignore_case = false,
216 bool ignore_underscore = false);
217
220template <typename Callable> inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) {
221 std::size_t start_pos = 0;
222 while((start_pos = str.find(trigger, start_pos)) != std::string::npos) {
223 start_pos = modify(str, start_pos);
224 }
225 return str;
226}
227
230CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char);
231
234CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter = '\0');
235
237CLI11_INLINE std::string get_environment_value(const std::string &env_name);
238
243CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
244
248CLI11_INLINE bool has_escapable_character(const std::string &str);
249
253CLI11_INLINE std::string add_escaped_characters(const std::string &str);
254
256CLI11_INLINE std::string remove_escaped_characters(const std::string &str);
257
259CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape, bool force = false);
260
261CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string);
262
264CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string);
265
267CLI11_INLINE bool process_quoted_string(std::string &str,
268 char string_char = '\"',
269 char literal_char = '\'',
270 bool disable_secondary_array_processing = false);
271
274CLI11_INLINE std::ostream &streamOutAsParagraph(std::ostream &out,
275 const std::string &text,
276 std::size_t paragraphWidth,
277 const std::string &linePrefix = "",
278 bool skipPrefixOnFirstLine = false);
279
280} // namespace detail
281
282// [CLI11:string_tools_hpp:end]
283
284} // namespace CLI
285
286#ifndef CLI11_COMPILE
287#include "impl/StringTools_inl.hpp" // IWYU pragma: export
288#endif
std::ostream & operator<<(std::ostream &in, const T &item)
output streaming for enumerations
Definition StringTools.hpp:34