User Guide
string_utils.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #pragma once
9 
10 /**
11  * \file
12  * \brief Implement string manipulation functions
13  *
14  * String trimming and manipulation functions based on
15  * stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
16  */
17 
18 #include <algorithm>
19 #include <cctype>
20 #include <cmath>
21 #include <functional>
22 #include <sstream>
23 #include <vector>
24 
25 namespace nmodl {
26 /// string utility functions
27 namespace stringutils {
28 
29 /**
30  * \addtogroup utils
31  * \{
32  */
33 
34 /// text alignment when printing in the tabular form
35 enum class text_alignment { left, right, center };
36 
37 /**
38  * \param text the string to manipulate
39  * \return a copy of the given string with leading ASCII space characters removed
40  */
41 [[nodiscard]] static inline std::string ltrim(std::string text) {
42  text.erase(text.begin(),
43  std::find_if(text.begin(), text.end(), [](int c) { return !std::isspace(c); }));
44  return text;
45 }
46 
47 /**
48  * \param text the string to manipulate
49  * \return a copy of the given string with trailing characters removed.
50  */
51 [[nodiscard]] static inline std::string rtrim(std::string text) {
52  text.erase(
53  std::find_if(text.rbegin(), text.rend(), [](int c) { return !std::isspace(c); }).base(),
54  text.end());
55  return text;
56 }
57 
58 /**
59  *
60  * \param text the string to manipulate
61  * \return a copy of the given string with both leading and trailing ASCII space characters removed
62  */
63 [[nodiscard]] static inline std::string trim(std::string text) {
64  return ltrim(rtrim(std::move(text)));
65 }
66 
67 /**
68  * Remove all occurrences of a given character in a text
69  * \param text the string to manipulate
70  * \param c the character to remove
71  * @return a copy the modified text
72  */
73 [[nodiscard]] static inline std::string remove_character(std::string text, const char c) {
74  text.erase(std::remove(text.begin(), text.end(), c), text.end());
75  return text;
76 }
77 
78 /**
79  *
80  * \param text the string to manipulate
81  * \return a copy of the given string with all occurrences of the ASCII newline character removed
82  */
83 [[nodiscard]] static inline std::string trim_newline(std::string text) {
84  return remove_character(std::move(text), '\n');
85 }
86 
87 /**
88  * Escape double-quote in a text, useful for JSON pretty printer.
89  * \param text the string to manipulate
90  * \return a copy of the given string with every " and \ characters prefixed with an extra \
91  */
92 [[nodiscard]] static inline std::string escape_quotes(const std::string& text) {
93  std::string result;
94 
95  for (auto c: text) {
96  switch (c) {
97  case '"':
98  case '\\':
99  result += '\\';
100  /// don't break here as we want to append actual character
101 
102  default:
103  result += c;
104  }
105  }
106 
107  return result;
108 }
109 
110 /**
111  * Split a text in a list of words, using a given delimiter character
112  * \param text the string to manipulate
113  * \param delimiter the delimiter character
114  * \return a container holding copies of the substrings
115  */
116 [[nodiscard]] static inline std::vector<std::string> split_string(const std::string& text,
117  char delimiter) {
118  std::vector<std::string> elements;
119  std::stringstream ss(text);
120  std::string item;
121 
122  while (std::getline(ss, item, delimiter)) {
123  elements.push_back(item);
124  }
125 
126  return elements;
127 }
128 
129 
130 /**
131  * Check if `haystack` ends with `needle`.
132  *
133  * The empty string is a suffix of every string.
134  */
135 static inline bool ends_with(const std::string& haystack, const std::string& needle) {
136  if (needle.empty()) {
137  return true;
138  }
139 
140  auto n_chars = needle.size();
141  if (haystack.size() < n_chars) {
142  return false;
143  }
144 
145  auto haystack_begin = haystack.begin() + haystack.size() - n_chars;
146  return std::equal(haystack_begin, haystack.end(), needle.begin(), needle.end());
147 };
148 
149 /**
150  * Check if `haystack` starts with `needle`.
151  *
152  * The empty string is a prefix of every string.
153  */
154 static inline bool starts_with(const std::string& haystack, const std::string& needle) {
155  return haystack.rfind(needle, 0) == 0;
156 }
157 
158 
159 ///
160 /**
161  * Aligns a text within a field of width \a width
162  * \param text the string to manipulate
163  * \param width the width of the field
164  * \param type the kind of alignment Left, Right, or Center
165  * \return a copy of the string aligned
166  */
167 [[nodiscard]] static inline std::string align_text(const std::string& text,
168  int width,
169  text_alignment type) {
170  /// left and right spacing
171  std::string left, right;
172 
173  /// count excess room to pad
174  const int padding = width - static_cast<int>(text.size());
175 
176  if (padding > 0) {
177  if (type == text_alignment::left) {
178  right = std::string(padding, ' ');
179  } else if (type == text_alignment::right) {
180  left = std::string(padding, ' ');
181  } else {
182  left = std::string(padding / 2, ' ');
183  right = std::string(padding / 2, ' ');
184  /// if odd #, add one more space
185  if (padding % 2 != 0) {
186  right += " ";
187  }
188  }
189  }
190  return left + text + right;
191 }
192 
193 /// To lower case
194 /**
195  * \param text the string to manipulate
196  * \return a copy of string converted to lowercase
197  */
198 [[nodiscard]] static inline std::string tolower(std::string text) {
199  std::transform(text.begin(), text.end(), text.begin(), ::tolower);
200  return text;
201 }
202 
203 /**
204  * Convert double value to string without trailing zeros
205  *
206  * When we use std::to_string with double value 1 then it gets
207  * printed as `1.000000`. This is not convenient for testing
208  * and testing/validation. To avoid this issue, we use to_string
209  * for integer values and stringstream for the rest.
210  */
211 std::string to_string(double value, const std::string& format_spec = "{:.16g}");
212 
213 /** Joint two (list of) arguments.
214  *
215  * The tricks is to not add a ',' when either side is empty.
216  */
217 std::string join_arguments(const std::string& lhs, const std::string& rhs);
218 
219 /** \} */ // end of utils
220 
221 } // namespace stringutils
222 } // namespace nmodl
nmodl::stringutils::escape_quotes
static std::string escape_quotes(const std::string &text)
Escape double-quote in a text, useful for JSON pretty printer.
Definition: string_utils.hpp:92
nmodl::stringutils::starts_with
static bool starts_with(const std::string &haystack, const std::string &needle)
Check if haystack starts with needle.
Definition: string_utils.hpp:154
nmodl::stringutils::join_arguments
std::string join_arguments(const std::string &lhs, const std::string &rhs)
Joint two (list of) arguments.
Definition: string_utils.cpp:30
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::stringutils::align_text
static std::string align_text(const std::string &text, int width, text_alignment type)
Aligns a text within a field of width width.
Definition: string_utils.hpp:167
nmodl::stringutils::text_alignment::center
@ center
nmodl::stringutils::trim_newline
static std::string trim_newline(std::string text)
Definition: string_utils.hpp:83
nmodl::stringutils::text_alignment::left
@ left
nmodl::stringutils::trim
static std::string trim(std::string text)
Definition: string_utils.hpp:63
nmodl::stringutils::text_alignment
text_alignment
text alignment when printing in the tabular form
Definition: string_utils.hpp:35
nmodl::stringutils::split_string
static std::vector< std::string > split_string(const std::string &text, char delimiter)
Split a text in a list of words, using a given delimiter character.
Definition: string_utils.hpp:116
nmodl::stringutils::ltrim
static std::string ltrim(std::string text)
Definition: string_utils.hpp:41
nmodl::stringutils::tolower
static std::string tolower(std::string text)
To lower case.
Definition: string_utils.hpp:198
nmodl::stringutils::remove_character
static std::string remove_character(std::string text, const char c)
Remove all occurrences of a given character in a text.
Definition: string_utils.hpp:73
nmodl::stringutils::text_alignment::right
@ right
nmodl::stringutils::ends_with
static bool ends_with(const std::string &haystack, const std::string &needle)
Check if haystack ends with needle.
Definition: string_utils.hpp:135
nmodl::stringutils::to_string
std::string to_string(double value, const std::string &format_spec)
Convert double value to string without trailing zeros.
Definition: string_utils.cpp:18
nmodl::stringutils::rtrim
static std::string rtrim(std::string text)
Definition: string_utils.hpp:51