Cantera  2.4.0
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 http://www.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& err) {
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  istart = 1;
151  }
152  for (size_t i = istart; i < str.size(); i++) {
153  ch = str[i];
154  if (isdigit(ch)) {
155  } else if (ch == '.') {
156  numDot++;
157  if (numDot > 1) {
158  throw CanteraError("fpValueCheck",
159  "string has more than one .");
160  }
161  if (numExp > 0) {
162  throw CanteraError("fpValueCheck",
163  "string has decimal point in exponent");
164  }
165  } else if (ch == 'e' || ch == 'E' || ch == 'd' || ch == 'D') {
166  numExp++;
167  str[i] = 'E';
168  if (numExp > 1) {
169  throw CanteraError("fpValueCheck",
170  "string has more than one exp char");
171  }
172  ch = str[i+1];
173  if (ch == '+' || ch == '-') {
174  i++;
175  }
176  } else {
177  throw CanteraError("fpValueCheck",
178  "Trouble processing string, " + str);
179  }
180  }
181  return fpValue(str);
182 }
183 
184 std::string parseSpeciesName(const std::string& nameStr, std::string& phaseName)
185 {
186  std::string s = ba::trim_copy(nameStr);
187  phaseName = "";
188  size_t ibegin = s.find_first_not_of(" ;\n\t");
189  if (ibegin != std::string::npos) {
190  s = s.substr(ibegin,s.size());
191  size_t icolon = s.find(':');
192  size_t iend = s.find_first_of(" ;\n\t");
193  if (icolon != std::string::npos) {
194  phaseName = s.substr(0, icolon);
195  s = s.substr(icolon+1, s.size());
196  icolon = s.find(':');
197  if (icolon != std::string::npos) {
198  throw CanteraError("parseSpeciesName()", "two colons in name: " + nameStr);
199  }
200  }
201  if (iend != std::string::npos) {
202  throw CanteraError("parseSpeciesName()",
203  "Species name has \" ;/\n/\t\" in the middle of it: " + nameStr);
204  }
205  }
206  return s;
207 }
208 
209 doublereal strSItoDbl(const std::string& strSI)
210 {
211  std::vector<std::string> v;
212  tokenizeString(strSI, v);
213  doublereal fp = 1.0;
214  size_t n = v.size();
215  if (n > 2 || n < 1) {
216  throw CanteraError("strSItoDbl",
217  "number of tokens is too high");
218  } else if (n == 2) {
219  fp = toSI(v[1]);
220  }
221  doublereal val = fpValueCheck(v[0]);
222  return val * fp;
223 }
224 
225 void tokenizeString(const std::string& in_val, std::vector<std::string>& v)
226 {
227  std::string val = ba::trim_copy(in_val);
228  v.clear();
229  if (val.empty()) {
230  // In this case, prefer v to be empty instead of split's behavior of
231  // returning a vector with one element that is the empty string.
232  return;
233  }
234  ba::split(v, val, ba::is_space(), ba::token_compress_on);
235 }
236 
237 size_t copyString(const std::string& source, char* dest, size_t length)
238 {
239  const char* c_src = source.c_str();
240  size_t N = std::min(length, source.length()+1);
241  size_t ret = (length >= source.length() + 1) ? 0 : source.length() + 1;
242  std::copy(c_src, c_src + N, dest);
243  if (length != 0) {
244  dest[length-1] = '\0';
245  }
246  return ret;
247 }
248 
249 std::string trimCopy(const std::string &input) {
250  return ba::trim_copy(input);
251 }
252 
253 std::string toLowerCopy(const std::string &input) {
254  return ba::to_lower_copy(input);
255 }
256 
257 bool caseInsensitiveEquals(const std::string &input, const std::string &test) {
258  return ba::iequals(input, test);
259 }
260 
261 }
std::map< std::string, doublereal > compositionMap
Map connecting a string name with a double.
Definition: ct_defs.h:149
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
std::string trimCopy(const std::string &input)
Trim.
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data...
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
Various templated functions that carry out common vector operations (see Templated Utility Functions)...
doublereal toSI(const std::string &unit)
Return the conversion factor to convert unit std::string &#39;unit&#39; to SI units.
Definition: global.cpp:135
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:165
This file contains definitions of terms that are used in internal routines and are unlikely to need m...
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...
bool caseInsensitiveEquals(const std::string &input, const std::string &test)
Case insensitive equality predicate.
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:504
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:65
std::string parseSpeciesName(const std::string &nameStr, std::string &phaseName)
Parse a name string, separating out the phase name from the species name.
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.
int intValue(const std::string &val)
Translate a string into one integer value.
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
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:157
Contains declarations for string manipulation functions within Cantera.
Definition: fmt.h:29
std::string toLowerCopy(const std::string &input)
Convert to lower case.
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:8
doublereal strSItoDbl(const std::string &strSI)
Interpret one or two token string as a single double.
std::string stripnonprint(const std::string &s)
Strip non-printing characters wherever they are.
Definition: stringUtils.cpp:49
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...