https://mooseframework.inl.gov
MooseStringUtils.h
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #pragma once
11 
12 #include <algorithm>
13 #include <sstream>
14 #include <string>
15 #include <vector>
16 
17 // The capabilities library (capabilities target in moose.mk) uses this
18 // utility for parsing. We don't want to include libmesh libraries in
19 // this library as the test harness uses it. However, in the convert
20 // method (heavily used by the parser), we really want to take advantage
21 // of libMesh::demangle() for useful error messages. So this lets us
22 // still use pretty demangling when used by MOOSE but not by the
23 // capabilities library (which is probably ok...)
24 #ifndef MOOSESTRINGUTILS_NO_LIBMESH
25 #include "libmesh/libmesh_common.h"
26 #endif
27 
28 /*
29  * This must stay a header-only utility! It is used in the capabilities python module and
30  * we do not want to link against any MOOSE libs.
31  */
32 namespace MooseUtils
33 {
37 inline std::string
38 trim(const std::string & str, const std::string & white_space = " \t\n\v\f\r")
39 {
40  const auto begin = str.find_first_not_of(white_space);
41  if (begin == std::string::npos)
42  return ""; // no content
43  const auto end = str.find_last_not_of(white_space);
44  return str.substr(begin, end - begin + 1);
45 }
46 
53 template <typename T>
54 void
55 tokenize(const std::string & str,
56  std::vector<T> & elements,
57  unsigned int min_len = 1,
58  const std::string & delims = "/")
59 {
60  elements.clear();
61 
62  std::string::size_type last_pos = str.find_first_not_of(delims, 0);
63  std::string::size_type pos = str.find_first_of(delims, std::min(last_pos + min_len, str.size()));
64 
65  while (last_pos != std::string::npos)
66  {
67  elements.push_back(str.substr(last_pos, pos - last_pos));
68  // skip delims between tokens
69  last_pos = str.find_first_not_of(delims, pos);
70  if (last_pos == std::string::npos)
71  break;
72  pos = str.find_first_of(delims, std::min(last_pos + min_len, str.size()));
73  }
74 }
75 
94 template <class T>
95 bool
96 convert(const std::string & str, T & value, const bool throw_on_failure)
97 {
98  // Special case for numeric values, also handling range checking
99  if constexpr (std::is_same_v<short int, T> || std::is_same_v<unsigned short int, T> ||
100  std::is_same_v<int, T> || std::is_same_v<unsigned int, T> ||
101  std::is_same_v<long int, T> || std::is_same_v<unsigned long int, T> ||
102  std::is_same_v<long long int, T> || std::is_same_v<unsigned long long int, T>)
103  {
104  // Try read a double and try to cast it to an int
105  long double double_val;
106  std::stringstream double_ss(str);
107  double_ss >> double_val;
108 
109  if (!double_ss.fail() && double_ss.eof())
110  {
111  // on arm64 the long double does not have sufficient precision
112  std::stringstream int_ss(str);
113  const bool use_int = !(int_ss >> value).fail() && int_ss.eof();
114 
115  // Check to see if it's an integer and thus within range of an integer
116  if (double_val == static_cast<long double>(static_cast<T>(double_val)))
117  {
118  if (!use_int)
119  value = static_cast<T>(double_val);
120  return true;
121  }
122  }
123  }
124  // Non numeric values
125  else
126  {
127  // string or derived string: direct copy
128  if constexpr (std::is_base_of_v<std::string, T>)
129  {
130  value = str;
131  return true;
132  }
133  // non-string or numeric, use stringstream >>
134  else
135  {
136  std::stringstream ss(trim(str));
137  if (!(ss >> value).fail() && ss.eof())
138  return true;
139  }
140  }
141 
142  if (throw_on_failure)
143  {
144  std::string error = "Unable to convert '" + str + "' to type ";
145 #ifdef MOOSESTRINGUTILS_NO_LIBMESH
146  error += typeid(T).name();
147 #else
148  error += libMesh::demangle(typeid(T).name());
149 #endif
150  throw std::invalid_argument(error);
151  }
152 
153  return false;
154 }
155 
160 template <typename T>
161 bool
162 tokenizeAndConvert(const std::string & str,
163  std::vector<T> & tokenized_vector,
164  const std::string & delimiter = " \t\n\v\f\r")
165 {
166  std::vector<std::string> tokens;
167  MooseUtils::tokenize(str, tokens, 1, delimiter);
168  tokenized_vector.resize(tokens.size());
169  for (std::size_t i = 0; i < tokens.size(); ++i)
170  if (!convert<T>(tokens[i], tokenized_vector[i], false))
171  return false;
172  return true;
173 }
174 
179 inline std::string
180 toUpper(std::string name)
181 {
182  std::transform(name.begin(), name.end(), name.begin(), ::toupper);
183  return name;
184 }
185 
190 inline std::string
191 toLower(std::string name)
192 {
193  std::transform(name.begin(), name.end(), name.begin(), ::tolower);
194  return name;
195 }
196 }
std::string name(const ElemQuality q)
void tokenize(const std::string &str, std::vector< T > &elements, unsigned int min_len=1, const std::string &delims="/")
This function will split the passed in string on a set of delimiters appending the substrings to the ...
bool tokenizeAndConvert(const std::string &str, std::vector< T > &tokenized_vector, const std::string &delimiter=" \\\)
tokenizeAndConvert splits a string using delimiter and then converts to type T.
bool convert(const std::string &str, T &value, const bool throw_on_failure)
Takes the string representation of a value and converts it to the value.
std::string toUpper(std::string name)
Convert supplied string to upper case.
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
std::string trim(const std::string &str, const std::string &white_space=" \\\)
Standard scripting language trim function.
std::string toLower(std::string name)
Convert supplied string to lower case.
std::string demangle(const char *name)
charT const * delimiter
Definition: InfixIterator.h:34
auto min(const L &left, const R &right)