CLI11
C++11 Command Line Interface Parser
Loading...
Searching...
No Matches
StringTools.hpp
1// Copyright (c) 2017-2024, 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 return in << static_cast<typename std::underlying_type<T>::type>(item);
37}
38
39} // namespace enums
40
42using enums::operator<<;
43
44namespace detail {
47constexpr int expected_max_vector_size{1 << 29};
48// Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
50CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim);
51
53template <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
71template <typename T,
72 typename Callable,
73 typename = typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
74std::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
91template <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
104CLI11_INLINE std::string &ltrim(std::string &str);
105
107CLI11_INLINE std::string &ltrim(std::string &str, const std::string &filter);
108
110CLI11_INLINE std::string &rtrim(std::string &str);
111
113CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter);
114
116inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
117
119inline std::string &trim(std::string &str, const std::string filter) { return ltrim(rtrim(str, filter), filter); }
120
122inline std::string trim_copy(const std::string &str) {
123 std::string s = str;
124 return trim(s);
125}
126
128CLI11_INLINE std::string &remove_quotes(std::string &str);
129
131CLI11_INLINE void remove_quotes(std::vector<std::string> &args);
132
137CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input);
138
140inline std::string trim_copy(const std::string &str, const std::string &filter) {
141 std::string s = str;
142 return trim(s, filter);
143}
144
146CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid);
147
150template <typename T> bool valid_first_char(T c) {
151 return ((c != '-') && (static_cast<unsigned char>(c) > 33)); // space and '!' not allowed
152}
153
155template <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
163CLI11_INLINE bool valid_name_string(const std::string &str);
164
166inline 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
172inline bool is_separator(const std::string &str) {
173 static const std::string sep("%%");
174 return (str.empty() || str == sep);
175}
176
178inline 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
183inline 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
191inline 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
197CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to);
198
200inline bool has_default_flag_values(const std::string &flags) {
201 return (flags.find_first_of("{!") != std::string::npos);
202}
203
204CLI11_INLINE void remove_default_flag_values(std::string &flags);
205
207CLI11_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
214template <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
224CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char);
225
228CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter = '\0');
229
231CLI11_INLINE std::string get_environment_value(const std::string &env_name);
232
237CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
238
242CLI11_INLINE bool has_escapable_character(const std::string &str);
243
247CLI11_INLINE std::string add_escaped_characters(const std::string &str);
248
250CLI11_INLINE std::string remove_escaped_characters(const std::string &str);
251
253CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape);
254
255CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string);
256
258CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string);
259
261CLI11_INLINE bool process_quoted_string(std::string &str, char string_char = '\"', char literal_char = '\'');
262
265CLI11_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