Cantera  3.0.0
Loading...
Searching...
No Matches
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//@{
12
13#ifdef _MSC_VER
14#define SNPRINTF _snprintf
15#else
16#define SNPRINTF snprintf
17#endif
18//@}
19
23#include "cantera/base/global.h"
24
25#include <boost/algorithm/string.hpp>
26#include <sstream>
27
28namespace ba = boost::algorithm;
29
30namespace Cantera
31{
32
33string vec2str(const vector<double>& v, const string& fmt, const string& sep)
34{
35 char buf[64];
36 std::stringstream o;
37 for (size_t i = 0; i < v.size(); i++) {
38 SNPRINTF(buf, 63, fmt.c_str(), v[i]);
39 o << buf;
40 if (i != v.size() - 1) {
41 o << sep;
42 }
43 }
44 return o.str();
45}
46
47string stripnonprint(const string& s)
48{
49 string ss = "";
50 for (size_t i = 0; i < s.size(); i++) {
51 if (isprint(s[i])) {
52 ss += s[i];
53 }
54 }
55 return ss;
56}
57
58Composition parseCompString(const string& ss, const vector<string>& names)
59{
61 for (size_t k = 0; k < names.size(); k++) {
62 x[names[k]] = 0.0;
63 }
64
65 size_t start = 0;
66 size_t stop = 0;
67 size_t left = 0;
68 while (stop < ss.size()) {
69 size_t colon = ss.find(':', left);
70 if (colon == npos) {
71 break;
72 }
73 size_t valstart = ss.find_first_not_of(" \t\n", colon+1);
74 stop = ss.find_first_of(", ;\n\t", valstart);
75 string name = ba::trim_copy(ss.substr(start, colon-start));
76 if (!names.empty() && x.find(name) == x.end()) {
77 throw CanteraError("parseCompString",
78 "unknown species '" + name + "'");
79 }
80
81 double value;
82 try {
83 value = fpValueCheck(ss.substr(valstart, stop-valstart));
84 } catch (CanteraError&) {
85 // If we have a key containing a colon, we expect this to fail. In
86 // this case, take the current substring as part of the key and look
87 // to the right of the next colon for the corresponding value.
88 // Otherwise, this is an invalid composition string.
89 string testname = ss.substr(start, stop-start);
90 if (testname.find_first_of(" \n\t") != npos) {
91 // Space, tab, and newline are never allowed in names
92 throw;
93 } else if (ss.substr(valstart, stop-valstart).find(':') != npos) {
94 left = colon + 1;
95 stop = 0; // Force another iteration of this loop
96 continue;
97 } else {
98 throw;
99 }
100 }
101 if (getValue(x, name, 0.0) != 0.0) {
102 throw CanteraError("parseCompString",
103 "Duplicate key: '" + name + "'.");
104 }
105
106 x[name] = value;
107 start = ss.find_first_not_of(", ;\n\t", stop+1);
108 left = start;
109 }
110 if (left != start) {
111 throw CanteraError("parseCompString", "Unable to parse key-value pair:"
112 "\n'{}'", ss.substr(start, stop));
113 }
114 if (stop != npos && !ba::trim_copy(ss.substr(stop)).empty()) {
115 throw CanteraError("parseCompString", "Found non-key:value data "
116 "in composition string: '" + ss.substr(stop) + "'");
117 }
118 return x;
119}
120
121double fpValue(const string& val)
122{
123 double rval;
124 std::stringstream ss(val);
125 ss.imbue(std::locale("C"));
126 ss >> rval;
127 return rval;
128}
129
130double fpValueCheck(const string& val)
131{
132 string str = ba::trim_copy(val);
133 if (str.empty()) {
134 throw CanteraError("fpValueCheck", "string has zero length");
135 }
136 int numDot = 0;
137 int numExp = 0;
138 char ch;
139 int istart = 0;
140 ch = str[0];
141 if (ch == '+' || ch == '-') {
142 if (str.size() == 1) {
143 throw CanteraError("fpValueCheck", "string '{}' ends in '{}'", val, ch);
144 }
145 istart = 1;
146 }
147 for (size_t i = istart; i < str.size(); i++) {
148 ch = str[i];
149 if (isdigit(ch)) {
150 } else if (ch == '.') {
151 numDot++;
152 if (numDot > 1) {
153 throw CanteraError("fpValueCheck",
154 "string '{}' has more than one decimal point.", val);
155 }
156 if (numExp > 0) {
157 throw CanteraError("fpValueCheck",
158 "string '{}' has decimal point in exponent", val);
159 }
160 } else if (ch == 'e' || ch == 'E' || ch == 'd' || ch == 'D') {
161 numExp++;
162 str[i] = 'E';
163 if (numExp > 1) {
164 throw CanteraError("fpValueCheck",
165 "string '{}' has more than one exp char", val);
166 } else if (i == str.size() - 1) {
167 throw CanteraError("fpValueCheck", "string '{}' ends in '{}'", val, ch);
168 }
169 ch = str[i+1];
170 if (ch == '+' || ch == '-') {
171 if (i + 1 == str.size() - 1) {
172 throw CanteraError("fpValueCheck",
173 "string '{}' ends in '{}'", val, ch);
174 }
175 i++;
176 }
177 } else {
178 throw CanteraError("fpValueCheck", "Trouble processing string '{}'", str);
179 }
180 }
181 return fpValue(str);
182}
183
184void tokenizeString(const string& in_val, vector<string>& v)
185{
186 string val = ba::trim_copy(in_val);
187 v.clear();
188 if (val.empty()) {
189 // In this case, prefer v to be empty instead of split's behavior of
190 // returning a vector with one element that is the empty string.
191 return;
192 }
193 ba::split(v, val, ba::is_space(), ba::token_compress_on);
194}
195
196void tokenizePath(const string& in_val, vector<string>& v)
197{
198 string val = ba::trim_copy(in_val);
199 v.clear();
200 ba::split(v, val, ba::is_any_of("/\\"), ba::token_compress_on);
201}
202
203size_t copyString(const string& source, char* dest, size_t length)
204{
205 const char* c_src = source.c_str();
206 size_t N = std::min(length, source.length()+1);
207 size_t ret = (length >= source.length() + 1) ? 0 : source.length() + 1;
208 std::copy(c_src, c_src + N, dest);
209 if (length != 0) {
210 dest[length-1] = '\0';
211 }
212 return ret;
213}
214
215string trimCopy(const string &input) {
216 return ba::trim_copy(input);
217}
218
219string toLowerCopy(const string &input) {
220 return ba::to_lower_copy(input);
221}
222
223bool caseInsensitiveEquals(const string &input, const string &test) {
224 return ba::iequals(input, test);
225}
226
227}
Base class for exceptions thrown by Cantera classes.
This file contains definitions of constants, types and terms that are used in internal routines and a...
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
This file contains definitions for utility functions and text for modules, inputfiles and logging,...
size_t copyString(const string &source, char *dest, size_t length)
Copy the contents of a string into a char array of a given length.
bool caseInsensitiveEquals(const string &input, const string &test)
Case insensitive equality predicate.
string stripnonprint(const string &s)
Strip non-printing characters wherever they are.
string vec2str(const vector< double > &v, const string &fmt, const string &sep)
Convert a vector to a string (separated by commas)
double fpValue(const string &val)
Translate a string into one double value.
string trimCopy(const string &input)
Trim.
void tokenizePath(const string &in_val, vector< string > &v)
This function separates a string up into tokens according to the location of path separators.
double fpValueCheck(const string &val)
Translate a string into one double value, with error checking.
string toLowerCopy(const string &input)
Convert to lower case.
Composition parseCompString(const string &ss, const vector< string > &names)
Parse a composition string into a map consisting of individual key:composition pairs.
void tokenizeString(const string &in_val, vector< string > &v)
This function separates a string up into tokens according to the location of white space.
Namespace for the Cantera kernel.
Definition AnyMap.cpp:564
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:195
const U & getValue(const map< T, U > &m, const T &key, const U &default_val)
Const accessor for a value in a map.
Definition utilities.h:190
map< string, double > Composition
Map from string names to doubles.
Definition ct_defs.h:184
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...