Cantera  2.5.1
stringUtils.cpp
Go to the documentation of this file.
1 /**
2  * @file stringUtils.cpp
3  * Contains definitions for string manipulation functions
4  * within Cantera.
5  */
6 
7 // This file is part of Cantera. See License.txt in the top-level directory or
8 // at https://cantera.org/license.txt for license and copyright information.
9 
10 //@{
11 #include "cantera/base/ct_defs.h"
12 
13 #ifdef _MSC_VER
14 #define SNPRINTF _snprintf
15 #else
16 #define SNPRINTF snprintf
17 #endif
18 //@}
19 
22 #include "cantera/base/ctml.h"
23 #include "cantera/base/utilities.h"
24 
25 #include <boost/algorithm/string.hpp>
26 #include <sstream>
27 #include <cstdio>
28 
29 namespace ba = boost::algorithm;
30 
31 namespace Cantera
32 {
33 
34 std::string vec2str(const vector_fp& v, const std::string& fmt,
35  const std::string& sep)
36 {
37  char buf[64];
38  std::stringstream o;
39  for (size_t i = 0; i < v.size(); i++) {
40  SNPRINTF(buf, 63, fmt.c_str(), v[i]);
41  o << buf;
42  if (i != v.size() - 1) {
43  o << sep;
44  }
45  }
46  return o.str();
47 }
48 
49 std::string stripnonprint(const std::string& s)
50 {
51  std::string ss = "";
52  for (size_t i = 0; i < s.size(); i++) {
53  if (isprint(s[i])) {
54  ss += s[i];
55  }
56  }
57  return ss;
58 }
59 
60 compositionMap parseCompString(const std::string& ss,
61  const std::vector<std::string>& names)
62 {
64  for (size_t k = 0; k < names.size(); k++) {
65  x[names[k]] = 0.0;
66  }
67 
68  size_t start = 0;
69  size_t stop = 0;
70  size_t left = 0;
71  while (stop < ss.size()) {
72  size_t colon = ss.find(':', left);
73  if (colon == npos) {
74  break;
75  }
76  size_t valstart = ss.find_first_not_of(" \t\n", colon+1);
77  stop = ss.find_first_of(", ;\n\t", valstart);
78  std::string name = ba::trim_copy(ss.substr(start, colon-start));
79  if (!names.empty() && x.find(name) == x.end()) {
80  throw CanteraError("parseCompString",
81  "unknown species '" + name + "'");
82  }
83 
84  double value;
85  try {
86  value = fpValueCheck(ss.substr(valstart, stop-valstart));
87  } catch (CanteraError&) {
88  // If we have a key containing a colon, we expect this to fail. In
89  // this case, take the current substring as part of the key and look
90  // to the right of the next colon for the corresponding value.
91  // Otherwise, this is an invalid composition string.
92  std::string testname = ss.substr(start, stop-start);
93  if (testname.find_first_of(" \n\t") != npos) {
94  // Space, tab, and newline are never allowed in names
95  throw;
96  } else if (ss.substr(valstart, stop-valstart).find(':') != npos) {
97  left = colon + 1;
98  stop = 0; // Force another iteration of this loop
99  continue;
100  } else {
101  throw;
102  }
103  }
104  if (getValue(x, name, 0.0) != 0.0) {
105  throw CanteraError("parseCompString",
106  "Duplicate key: '" + name + "'.");
107  }
108 
109  x[name] = value;
110  start = ss.find_first_not_of(", ;\n\t", stop+1);
111  left = start;
112  }
113  if (left != start) {
114  throw CanteraError("parseCompString", "Unable to parse key-value pair:"
115  "\n'{}'", ss.substr(start, stop));
116  }
117  if (stop != npos && !ba::trim_copy(ss.substr(stop)).empty()) {
118  throw CanteraError("parseCompString", "Found non-key:value data "
119  "in composition string: '" + ss.substr(stop) + "'");
120  }
121  return x;
122 }
123 
124 int intValue(const std::string& val)
125 {
126  return std::atoi(ba::trim_copy(val).c_str());
127 }
128 
129 doublereal fpValue(const std::string& val)
130 {
131  doublereal rval;
132  std::stringstream ss(val);
133  ss.imbue(std::locale("C"));
134  ss >> rval;
135  return rval;
136 }
137 
138 doublereal fpValueCheck(const std::string& val)
139 {
140  std::string str = ba::trim_copy(val);
141  if (str.empty()) {
142  throw CanteraError("fpValueCheck", "string has zero length");
143  }
144  int numDot = 0;
145  int numExp = 0;
146  char ch;
147  int istart = 0;
148  ch = str[0];
149  if (ch == '+' || ch == '-') {
150  if (str.size() == 1) {
151  throw CanteraError("fpValueCheck", "string ends in '{}'", ch);
152  }
153  istart = 1;
154  }
155  for (size_t i = istart; i < str.size(); i++) {
156  ch = str[i];
157  if (isdigit(ch)) {
158  } else if (ch == '.') {
159  numDot++;
160  if (numDot > 1) {
161  throw CanteraError("fpValueCheck",
162  "string has more than one .");
163  }
164  if (numExp > 0) {
165  throw CanteraError("fpValueCheck",
166  "string has decimal point in exponent");
167  }
168  } else if (ch == 'e' || ch == 'E' || ch == 'd' || ch == 'D') {
169  numExp++;
170  str[i] = 'E';
171  if (numExp > 1) {
172  throw CanteraError("fpValueCheck",
173  "string has more than one exp char");
174  } else if (i == str.size() - 1) {
175  throw CanteraError("fpValueCheck",
176  "string ends in '{}'", ch);
177  }
178  ch = str[i+1];
179  if (ch == '+' || ch == '-') {
180  if (i + 1 == str.size() - 1) {
181  throw CanteraError("fpValueCheck",
182  "string ends in '{}'", ch);
183  }
184  i++;
185  }
186  } else {
187  throw CanteraError("fpValueCheck",
188  "Trouble processing string, " + str);
189  }
190  }
191  return fpValue(str);
192 }
193 
194 std::string parseSpeciesName(const std::string& nameStr, std::string& phaseName)
195 {
196  std::string s = ba::trim_copy(nameStr);
197  phaseName = "";
198  size_t ibegin = s.find_first_not_of(" ;\n\t");
199  if (ibegin != std::string::npos) {
200  s = s.substr(ibegin,s.size());
201  size_t icolon = s.find(':');
202  size_t iend = s.find_first_of(" ;\n\t");
203  if (icolon != std::string::npos) {
204  phaseName = s.substr(0, icolon);
205  s = s.substr(icolon+1, s.size());
206  icolon = s.find(':');
207  if (icolon != std::string::npos) {
208  throw CanteraError("parseSpeciesName",
209  "two colons in name: '{}'", nameStr);
210  }
211  }
212  if (iend != std::string::npos) {
213  throw CanteraError("parseSpeciesName", "Species name has "
214  "\" ;/\n/\t\" in the middle of it: '{}'", nameStr);
215  }
216  }
217  return s;
218 }
219 
220 doublereal strSItoDbl(const std::string& strSI)
221 {
222  std::vector<std::string> v;
223  tokenizeString(strSI, v);
224  doublereal fp = 1.0;
225  size_t n = v.size();
226  if (n > 2 || n < 1) {
227  throw CanteraError("strSItoDbl",
228  "number of tokens is too high");
229  } else if (n == 2) {
230  fp = toSI(v[1]);
231  }
232  doublereal val = fpValueCheck(v[0]);
233  return val * fp;
234 }
235 
236 void tokenizeString(const std::string& in_val, std::vector<std::string>& v)
237 {
238  std::string val = ba::trim_copy(in_val);
239  v.clear();
240  if (val.empty()) {
241  // In this case, prefer v to be empty instead of split's behavior of
242  // returning a vector with one element that is the empty string.
243  return;
244  }
245  ba::split(v, val, ba::is_space(), ba::token_compress_on);
246 }
247 
248 size_t copyString(const std::string& source, char* dest, size_t length)
249 {
250  const char* c_src = source.c_str();
251  size_t N = std::min(length, source.length()+1);
252  size_t ret = (length >= source.length() + 1) ? 0 : source.length() + 1;
253  std::copy(c_src, c_src + N, dest);
254  if (length != 0) {
255  dest[length-1] = '\0';
256  }
257  return ret;
258 }
259 
260 std::string trimCopy(const std::string &input) {
261  return ba::trim_copy(input);
262 }
263 
264 std::string toLowerCopy(const std::string &input) {
265  return ba::to_lower_copy(input);
266 }
267 
268 bool caseInsensitiveEquals(const std::string &input, const std::string &test) {
269  return ba::iequals(input, test);
270 }
271 
272 }
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
This file contains definitions of terms that are used in internal routines and are unlikely to need m...
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
doublereal toSI(const std::string &unit)
Return the conversion factor to convert unit std::string 'unit' to SI units.
Definition: global.cpp:140
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:188
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:180
std::map< std::string, double > compositionMap
Map connecting a string name with a double.
Definition: ct_defs.h:172
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:264
const U & getValue(const std::map< T, U > &m, const T &key, const U &default_val)
Const accessor for a value in a std::map.
Definition: utilities.h:528
int intValue(const std::string &val)
Translate a string into one integer value.
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
bool caseInsensitiveEquals(const std::string &input, const std::string &test)
Case insensitive equality predicate.
std::string vec2str(const vector_fp &v, const std::string &fmt, const std::string &sep)
Convert a vector to a string (separated by commas)
Definition: stringUtils.cpp:34
std::string trimCopy(const std::string &input)
Trim.
size_t copyString(const std::string &source, char *dest, size_t length)
Copy the contents of a std::string into a char array of a given length.
std::string toLowerCopy(const std::string &input)
Convert to lower case.
std::string parseSpeciesName(const std::string &nameStr, std::string &phaseName)
Parse a name string, separating out the phase name from the species name.
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
doublereal strSItoDbl(const std::string &strSI)
Interpret one or two token string as a single double.
void tokenizeString(const std::string &in_val, std::vector< std::string > &v)
This function separates a string up into tokens according to the location of white space.
std::string stripnonprint(const std::string &s)
Strip non-printing characters wherever they are.
Definition: stringUtils.cpp:49
compositionMap parseCompString(const std::string &ss, const std::vector< std::string > &names)
Parse a composition string into a map consisting of individual key:composition pairs.
Definition: stringUtils.cpp:60
Versions 6.2.0 and 6.2.1 of fmtlib do not include this define before they include windows....
Definition: fmt.h:35
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector operations (see Templated Utility Functions)...