Cantera  4.0.0a1
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 static const auto locale = std::locale("C");
125 std::stringstream ss(val);
126 ss.imbue(locale);
127 ss >> rval;
128 return rval;
129}
130
131double fpValueCheck(const string& val)
132{
133 string str = ba::trim_copy(val);
134 if (str.empty()) {
135 throw CanteraError("fpValueCheck", "string has zero length");
136 }
137 int numDot = 0;
138 int numExp = 0;
139 char ch;
140 int istart = 0;
141 ch = str[0];
142 if (ch == '+' || ch == '-') {
143 if (str.size() == 1) {
144 throw CanteraError("fpValueCheck", "string '{}' ends in '{}'", val, ch);
145 }
146 istart = 1;
147 }
148 for (size_t i = istart; i < str.size(); i++) {
149 ch = str[i];
150 if (isdigit(ch)) {
151 } else if (ch == '.') {
152 numDot++;
153 if (numDot > 1) {
154 throw CanteraError("fpValueCheck",
155 "string '{}' has more than one decimal point.", val);
156 }
157 if (numExp > 0) {
158 throw CanteraError("fpValueCheck",
159 "string '{}' has decimal point in exponent", val);
160 }
161 } else if (ch == 'e' || ch == 'E' || ch == 'd' || ch == 'D') {
162 numExp++;
163 str[i] = 'E';
164 if (numExp > 1) {
165 throw CanteraError("fpValueCheck",
166 "string '{}' has more than one exp char", val);
167 } else if (i == str.size() - 1) {
168 throw CanteraError("fpValueCheck", "string '{}' ends in '{}'", val, ch);
169 }
170 ch = str[i+1];
171 if (ch == '+' || ch == '-') {
172 if (i + 1 == str.size() - 1) {
173 throw CanteraError("fpValueCheck",
174 "string '{}' ends in '{}'", val, ch);
175 }
176 i++;
177 }
178 } else {
179 throw CanteraError("fpValueCheck", "Trouble processing string '{}'", str);
180 }
181 }
182 return fpValue(str);
183}
184
185vector<string> tokenizeString(const string& in_val)
186{
187 string val = ba::trim_copy(in_val);
188 vector<string> v;
189 if (val.empty()) {
190 // In this case, prefer v to be empty instead of split's behavior of
191 // returning a vector with one element that is the empty string.
192 return v;
193 }
194 ba::split(v, val, ba::is_space(), ba::token_compress_on);
195 return v;
196}
197
198vector<string> tokenizePath(const string& in_val)
199{
200 string val = ba::trim_copy(in_val);
201 vector<string> v;
202 ba::split(v, val, ba::is_any_of("/\\"), ba::token_compress_on);
203 return v;
204}
205
206size_t copyString(const string& source, char* dest, size_t length)
207{
208 const char* c_src = source.c_str();
209 size_t N = std::min(length, source.length()+1);
210 size_t ret = (length >= source.length() + 1) ? 0 : source.length() + 1;
211 std::copy(c_src, c_src + N, dest);
212 if (length != 0) {
213 dest[length-1] = '\0';
214 }
215 return ret;
216}
217
218string trimCopy(const string &input) {
219 return ba::trim_copy(input);
220}
221
222string toLowerCopy(const string &input) {
223 return ba::to_lower_copy(input);
224}
225
226bool caseInsensitiveEquals(const string &input, const string &test) {
227 return ba::iequals(input, test);
228}
229
230}
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,...
vector< string > tokenizeString(const string &in_val)
This function separates a string up into tokens according to the location of white space.
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.
vector< string > tokenizePath(const string &in_val)
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.
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:183
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:223
map< string, double > Composition
Map from string names to doubles.
Definition ct_defs.h:180
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...