Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
StringUtils.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
21// Some static methods for string processing
22/****************************************************************************/
23#include <config.h>
24
25#include <string>
26#include <iostream>
27#include <cstdio>
28#include <cstring>
29#include <regex>
30#ifdef WIN32
31#define NOMINMAX
32#include <windows.h>
33#undef NOMINMAX
34#else
35#include <unistd.h>
36#endif
37#include <xercesc/util/TransService.hpp>
38#include <xercesc/util/TranscodingException.hpp>
42#include "StringUtils.h"
43
44#define KM_PER_MILE 1.609344
45
46
47// ===========================================================================
48// static member definitions
49// ===========================================================================
50std::string StringUtils::emptyString;
51XERCES_CPP_NAMESPACE::XMLLCPTranscoder* StringUtils::myLCPTranscoder = nullptr;
52
53
54// ===========================================================================
55// method definitions
56// ===========================================================================
57std::string
58StringUtils::prune(const std::string& str) {
59 const std::string::size_type endpos = str.find_last_not_of(" \t\n\r");
60 if (std::string::npos != endpos) {
61 const int startpos = (int)str.find_first_not_of(" \t\n\r");
62 return str.substr(startpos, endpos - startpos + 1);
63 }
64 return "";
65}
66
67
68std::string
69StringUtils::pruneZeros(const std::string& str, int max) {
70 const std::string::size_type endpos = str.find_last_not_of("0");
71 if (endpos != std::string::npos && str.back() == '0') {
72 std::string res = str.substr(0, MAX2((int)str.size() - max, (int)endpos + 1));
73 return res;
74 }
75 return str;
76}
77
78std::string
79StringUtils::to_lower_case(const std::string& str) {
80 std::string s = str;
81 std::transform(s.begin(), s.end(), s.begin(), [](char c) {
82 return (char)::tolower(c);
83 });
84 return s;
85}
86
87
88std::string
89StringUtils::to_upper_case(const std::string& str) {
90 std::string s = str;
91 std::transform(s.begin(), s.end(), s.begin(), [](char c) {
92 return (char)::toupper(c);
93 });
94 return s;
95}
96
97
98std::string
100 // inspired by http://stackoverflow.com/questions/4059775/convert-iso-8859-1-strings-to-utf-8-in-c-c
101 std::string result;
102 for (const auto& c : str) {
103 const unsigned char uc = (unsigned char)c;
104 if (uc < 128) {
105 result += uc;
106 } else {
107 result += (char)(0xc2 + (uc > 0xbf));
108 result += (char)((uc & 0x3f) + 0x80);
109 }
110 }
111 return result;
112}
113
114
115std::string
117 str = replace(str, "\xE4", "ae");
118 str = replace(str, "\xC4", "Ae");
119 str = replace(str, "\xF6", "oe");
120 str = replace(str, "\xD6", "Oe");
121 str = replace(str, "\xFC", "ue");
122 str = replace(str, "\xDC", "Ue");
123 str = replace(str, "\xDF", "ss");
124 str = replace(str, "\xC9", "E");
125 str = replace(str, "\xE9", "e");
126 str = replace(str, "\xC8", "E");
127 str = replace(str, "\xE8", "e");
128 return str;
129}
130
131
132std::string
133StringUtils::replace(std::string str, const std::string& what, const std::string& by) {
134 std::string::size_type idx = str.find(what);
135 const int what_len = (int)what.length();
136 if (what_len > 0) {
137 const int by_len = (int)by.length();
138 while (idx != std::string::npos) {
139 str = str.replace(idx, what_len, by);
140 idx = str.find(what, idx + by_len);
141 }
142 }
143 return str;
144}
145
146
147std::string
148StringUtils::substituteEnvironment(const std::string& str, const std::chrono::time_point<std::chrono::system_clock>* const timeRef) {
149 std::string s = str;
150 if (timeRef != nullptr) {
151 const std::string::size_type localTimeIndex = str.find("${LOCALTIME}");
152 const std::string::size_type utcIndex = str.find("${UTC}");
153 const bool isUTC = utcIndex != std::string::npos;
154 if (localTimeIndex != std::string::npos || isUTC) {
155 const time_t rawtime = std::chrono::system_clock::to_time_t(*timeRef);
156 char buffer [80];
157 struct tm* timeinfo = isUTC ? gmtime(&rawtime) : localtime(&rawtime);
158 strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S.", timeinfo);
159 auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(*timeRef);
160 auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(*timeRef - seconds);
161 const std::string micro = buffer + toString(microseconds.count());
162 if (isUTC) {
163 s.replace(utcIndex, 6, micro);
164 } else {
165 s.replace(localTimeIndex, 12, micro);
166 }
167 }
168 }
169 const std::string::size_type pidIndex = str.find("${PID}");
170 if (pidIndex != std::string::npos) {
171#ifdef WIN32
172 s.replace(pidIndex, 6, toString(::GetCurrentProcessId()));
173#else
174 s.replace(pidIndex, 6, toString(::getpid()));
175#endif
176 }
177 if (std::getenv("SUMO_LOGO") == nullptr) {
178 s = replace(s, "${SUMO_LOGO}", "${SUMO_HOME}/data/logo/sumo-128x138.png");
179 }
180 const std::string::size_type tildeIndex = str.find("~");
181 if (tildeIndex == 0) {
182 s.replace(0, 1, "${HOME}");
183 }
184 s = replace(s, ",~", ",${HOME}");
185#ifdef WIN32
186 if (std::getenv("HOME") == nullptr) {
187 s = replace(s, "${HOME}", "${USERPROFILE}");
188 }
189#endif
190
191 // Expression for an environment variables, e.g. ${NAME}
192 // Note: - R"(...)" is a raw string literal syntax to simplify a regex declaration
193 // - .+? looks for the shortest match (non-greedy)
194 // - (.+?) defines a "subgroup" which is already stripped of the $ and {, }
195 std::regex envVarExpr(R"(\$\{(.+?)\})");
196
197 // Are there any variables in this string?
198 std::smatch match;
199 std::string strIter = s;
200
201 // Loop over the entire value string and look for variable names
202 while (std::regex_search(strIter, match, envVarExpr)) {
203 std::string varName = match[1];
204
205 // Find the variable in the environment and its value
206 std::string varValue;
207 if (std::getenv(varName.c_str()) != nullptr) {
208 varValue = std::getenv(varName.c_str());
209 }
210
211 // Replace the variable placeholder with its value in the original string
212 s = std::regex_replace(s, std::regex("\\$\\{" + varName + "\\}"), varValue);
213
214 // Continue the loop with the remainder of the string
215 strIter = match.suffix();
216 }
217 return s;
218}
219
220
221std::string
222StringUtils::isoTimeString(const std::chrono::time_point<std::chrono::system_clock>* const timeRef) {
223 const std::chrono::system_clock::time_point now = timeRef == nullptr ? std::chrono::system_clock::now() : *timeRef;
224 const auto now_seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
225 const std::time_t now_c = std::chrono::system_clock::to_time_t(now);
226 const auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(now - now_seconds).count();
227 std::tm local_tm = *std::localtime(&now_c);
228
229 // Get the time zone offset
230 std::time_t utc_time = std::time(nullptr);
231 std::tm utc_tm = *std::gmtime(&utc_time);
232 const double offset = std::difftime(std::mktime(&local_tm), std::mktime(&utc_tm)) / 3600.0;
233 const int hours_offset = static_cast<int>(offset);
234 const int minutes_offset = static_cast<int>((offset - hours_offset) * 60);
235
236 // Format the time
237 std::ostringstream oss;
238 char buf[32];
239 std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &local_tm);
240 oss << buf << "."
241 << std::setw(6) << std::setfill('0') << std::abs(microseconds)
242 << (hours_offset >= 0 ? "+" : "-")
243 << std::setw(2) << std::setfill('0') << std::abs(hours_offset) << ":"
244 << std::setw(2) << std::setfill('0') << std::abs(minutes_offset);
245 return oss.str();
246}
247
248
249bool
250StringUtils::startsWith(const std::string& str, const std::string prefix) {
251 return str.compare(0, prefix.length(), prefix) == 0;
252}
253
254
255bool
256StringUtils::endsWith(const std::string& str, const std::string suffix) {
257 if (str.length() >= suffix.length()) {
258 return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
259 } else {
260 return false;
261 }
262}
263
264
265std::string
266StringUtils::padFront(const std::string& str, int length, char padding) {
267 return std::string(MAX2(0, length - (int)str.size()), padding) + str;
268}
269
270
271std::string
272StringUtils::escapeXML(const std::string& orig, const bool maskDoubleHyphen) {
273 std::string result = replace(orig, "&", "&amp;");
274 result = replace(result, ">", "&gt;");
275 result = replace(result, "<", "&lt;");
276 result = replace(result, "\"", "&quot;");
277 if (maskDoubleHyphen) {
278 result = replace(result, "--", "&#45;&#45;");
279 }
280 for (char invalid = '\1'; invalid < ' '; invalid++) {
281 result = replace(result, std::string(1, invalid).c_str(), "");
282 }
283 return replace(result, "'", "&apos;");
284}
285
286
287std::string
288StringUtils::escapeShell(const std::string& orig) {
289 std::string result = replace(orig, "\"", "\\\"");
290 return result;
291}
292
293
294std::string
295StringUtils::urlEncode(const std::string& toEncode, const std::string encodeWhich) {
296 std::ostringstream out;
297
298 for (int i = 0; i < (int)toEncode.length(); ++i) {
299 const char t = toEncode.at(i);
300
301 if ((encodeWhich != "" && encodeWhich.find(t) == std::string::npos) ||
302 (encodeWhich == "" &&
303 ((t >= 45 && t <= 57) || // hyphen, period, slash, 0-9
304 (t >= 65 && t <= 90) || // A-Z
305 t == 95 || // underscore
306 (t >= 97 && t <= 122) || // a-z
307 t == 126)) // tilde
308 ) {
309 out << toEncode.at(i);
310 } else {
311 out << charToHex(toEncode.at(i));
312 }
313 }
314
315 return out.str();
316}
317
318
319std::string
320StringUtils::urlDecode(const std::string& toDecode) {
321 std::ostringstream out;
322
323 for (int i = 0; i < (int)toDecode.length(); ++i) {
324 if (toDecode.at(i) == '%') {
325 std::string str(toDecode.substr(i + 1, 2));
326 out << hexToChar(str);
327 i += 2;
328 } else {
329 out << toDecode.at(i);
330 }
331 }
332
333 return out.str();
334}
335
336std::string
337StringUtils::charToHex(unsigned char c) {
338 short i = c;
339
340 std::stringstream s;
341
342 s << "%" << std::setw(2) << std::setfill('0') << std::hex << i;
343
344 return s.str();
345}
346
347
348unsigned char
349StringUtils::hexToChar(const std::string& str) {
350 short c = 0;
351 if (!str.empty()) {
352 std::istringstream in(str);
353 in >> std::hex >> c;
354 if (in.fail()) {
355 throw NumberFormatException(str + " could not be interpreted as hex");
356 }
357 }
358 return static_cast<unsigned char>(c);
359}
360
361
362int
363StringUtils::toInt(const std::string& sData) {
364 long long int result = toLong(sData);
365 if (result > std::numeric_limits<int>::max() || result < std::numeric_limits<int>::min()) {
366 throw NumberFormatException(toString(result) + " int overflow");
367 }
368 return (int)result;
369}
370
371
372bool
373StringUtils::isInt(const std::string& sData) {
374 // first check if can be converted to long int
375 if (isLong(sData)) {
376 const long long int result = toLong(sData);
377 // now check if the result is in the range of an int
378 return ((result <= std::numeric_limits<int>::max()) && (result >= std::numeric_limits<int>::min()));
379 }
380 return false;
381}
382
383
384int
385StringUtils::toIntSecure(const std::string& sData, int def) {
386 if (sData.length() == 0) {
387 return def;
388 }
389 return toInt(sData);
390}
391
392
393long long int
394StringUtils::toLong(const std::string& sData) {
395 const char* const data = sData.c_str();
396 if (data == 0 || data[0] == 0) {
397 throw EmptyData();
398 }
399 char* end;
400 errno = 0;
401#ifdef _MSC_VER
402 long long int ret = _strtoi64(data, &end, 10);
403#else
404 long long int ret = strtoll(data, &end, 10);
405#endif
406 if (errno == ERANGE) {
407 errno = 0;
408 throw NumberFormatException("(long long integer range) " + sData);
409 }
410 if ((int)(end - data) != (int)strlen(data)) {
411 throw NumberFormatException("(long long integer format) " + sData);
412 }
413 return ret;
414}
415
416
417bool
418StringUtils::isLong(const std::string& sData) {
419 const char* const data = sData.c_str();
420 if (data == 0 || data[0] == 0) {
421 return false;
422 }
423 char* end;
424 // reset errno before parsing, to keep errors
425 errno = 0;
426 // continue depending of current plattform
427#ifdef _MSC_VER
428 _strtoi64(data, &end, 10);
429#else
430 strtoll(data, &end, 10);
431#endif
432 // check out of range
433 if (errno == ERANGE) {
434 return false;
435 }
436 // check length of converted data
437 if ((int)(end - data) != (int)strlen(data)) {
438 return false;
439 }
440 return true;
441}
442
443
444int
445StringUtils::hexToInt(const std::string& sData) {
446 if (sData.length() == 0) {
447 throw EmptyData();
448 }
449 size_t idx = 0;
450 int result;
451 try {
452 if (sData[0] == '#') { // for html color codes
453 result = std::stoi(sData.substr(1), &idx, 16);
454 idx++;
455 } else {
456 result = std::stoi(sData, &idx, 16);
457 }
458 } catch (...) {
459 throw NumberFormatException("(hex integer format) " + sData);
460 }
461 if (idx != sData.length()) {
462 throw NumberFormatException("(hex integer format) " + sData);
463 }
464 return result;
465}
466
467
468bool
469StringUtils::isHex(std::string sData) {
470 if (sData.length() == 0) {
471 return false;
472 }
473 // remove the first character (for HTML color codes)
474 if (sData[0] == '#') {
475 sData = sData.substr(1);
476 }
477 const char* sDataPtr = sData.c_str();
478 char* returnPtr;
479 // reset errno
480 errno = 0;
481 // call string to long (size 16) from standard library
482 strtol(sDataPtr, &returnPtr, 16);
483 // check out of range
484 if (errno == ERANGE) {
485 return false;
486 }
487 // check if there was an error converting sDataPtr to double,
488 if (sDataPtr == returnPtr) {
489 return false;
490 }
491 // compare size of start and end points
492 if (static_cast<size_t>(returnPtr - sDataPtr) != sData.size()) {
493 return false;
494 }
495 return true;
496}
497
498
499double
500StringUtils::toDouble(const std::string& sData) {
501 if (sData.size() == 0) {
502 throw EmptyData();
503 }
504 try {
505 size_t idx = 0;
506 const double result = std::stod(sData, &idx);
507 if (idx != sData.size()) {
508 throw NumberFormatException("(double format) " + sData);
509 } else {
510 return result;
511 }
512 } catch (...) {
513 // invalid_argument or out_of_range
514 throw NumberFormatException("(double) " + sData);
515 }
516}
517
518
519bool
520StringUtils::isDouble(const std::string& sData) {
521 if (sData.size() == 0) {
522 return false;
523 }
524 const char* sDataPtr = sData.c_str();
525 char* returnPtr;
526 // reset errno
527 errno = 0;
528 // call string to double from standard library
529 strtod(sDataPtr, &returnPtr);
530 // check out of range
531 if (errno == ERANGE) {
532 return false;
533 }
534 // check if there was an error converting sDataPtr to double,
535 if (sDataPtr == returnPtr) {
536 return false;
537 }
538 // compare size of start and end points
539 if (static_cast<size_t>(returnPtr - sDataPtr) != sData.size()) {
540 return false;
541 }
542 return true;
543}
544
545
546double
547StringUtils::toDoubleSecure(const std::string& sData, const double def) {
548 if (sData.length() == 0) {
549 return def;
550 }
551 return toDouble(sData);
552}
553
554
555bool
556StringUtils::toBool(const std::string& sData) {
557 if (sData.length() == 0) {
558 throw EmptyData();
559 }
560 const std::string s = to_lower_case(sData);
561 if (s == "1" || s == "yes" || s == "true" || s == "on" || s == "x" || s == "t") {
562 return true;
563 }
564 if (s == "0" || s == "no" || s == "false" || s == "off" || s == "-" || s == "f") {
565 return false;
566 }
567 throw BoolFormatException(s);
568}
569
570
571bool
572StringUtils::isBool(const std::string& sData) {
573 if (sData.length() == 0) {
574 return false;
575 }
576 const std::string s = to_lower_case(sData);
577 // check true values
578 if (s == "1" || s == "yes" || s == "true" || s == "on" || s == "x" || s == "t") {
579 return true;
580 }
581 // check false values
582 if (s == "0" || s == "no" || s == "false" || s == "off" || s == "-" || s == "f") {
583 return true;
584 }
585 // no valid true or false values
586 return false;
587}
588
589
591StringUtils::toVersion(const std::string& sData) {
592 std::vector<std::string> parts = StringTokenizer(sData, ".").getVector();
593 return MMVersion(toInt(parts.front()), toDouble(parts.back()));
594}
595
596
597double
598StringUtils::parseDist(const std::string& sData) {
599 if (sData.size() == 0) {
600 throw EmptyData();
601 }
602 try {
603 size_t idx = 0;
604 const double result = std::stod(sData, &idx);
605 if (idx != sData.size()) {
606 const std::string unit = prune(sData.substr(idx));
607 if (unit == "m" || unit == "metre" || unit == "meter" || unit == "metres" || unit == "meters") {
608 return result;
609 }
610 if (unit == "km" || unit == "kilometre" || unit == "kilometer" || unit == "kilometres" || unit == "kilometers") {
611 return result * 1000.;
612 }
613 if (unit == "mi" || unit == "mile" || unit == "miles") {
614 return result * 1000. * KM_PER_MILE;
615 }
616 if (unit == "nmi") {
617 return result * 1852.;
618 }
619 if (unit == "ft" || unit == "foot" || unit == "feet") {
620 return result * 12. * 0.0254;
621 }
622 if (unit == "\"" || unit == "in" || unit == "inch" || unit == "inches") {
623 return result * 0.0254;
624 }
625 if (unit[0] == '\'') {
626 double inches = 12 * result;
627 if (unit.length() > 1) {
628 inches += std::stod(unit.substr(1), &idx);
629 if (unit.substr(idx) == "\"") {
630 return inches * 0.0254;
631 }
632 }
633 }
634 throw NumberFormatException("(distance format) " + sData);
635 } else {
636 return result;
637 }
638 } catch (...) {
639 // invalid_argument or out_of_range
640 throw NumberFormatException("(double) " + sData);
641 }
642}
643
644
645double
646StringUtils::parseSpeed(const std::string& sData, const bool defaultKmph) {
647 if (sData.size() == 0) {
648 throw EmptyData();
649 }
650 try {
651 size_t idx = 0;
652 const double result = std::stod(sData, &idx);
653 if (idx != sData.size()) {
654 const std::string unit = prune(sData.substr(idx));
655 if (unit == "km/h" || unit == "kph" || unit == "kmh" || unit == "kmph") {
656 return result / 3.6;
657 }
658 if (unit == "m/s") {
659 return result;
660 }
661 if (unit == "mph") {
662 return result * KM_PER_MILE / 3.6;
663 }
664 if (unit == "knots") {
665 return result * 1.852 / 3.6;
666 }
667 throw NumberFormatException("(speed format) " + sData);
668 } else {
669 return defaultKmph ? result / 3.6 : result;
670 }
671 } catch (...) {
672 // invalid_argument or out_of_range
673 throw NumberFormatException("(double) " + sData);
674 }
675}
676
677
678std::string
679StringUtils::transcode(const XMLCh* const data, int length) {
680 if (data == 0) {
681 throw EmptyData();
682 }
683 if (length == 0) {
684 return "";
685 }
686#if _XERCES_VERSION < 30100
687 char* t = XERCES_CPP_NAMESPACE::XMLString::transcode(data);
688 std::string result(t);
689 XERCES_CPP_NAMESPACE::XMLString::release(&t);
690 return result;
691#else
692 try {
693 XERCES_CPP_NAMESPACE::TranscodeToStr utf8(data, "UTF-8");
694 return reinterpret_cast<const char*>(utf8.str());
695 } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {
696 return "?";
697 }
698#endif
699}
700
701
702std::string
703StringUtils::transcodeFromLocal(const std::string& localString) {
704#if _XERCES_VERSION > 30100
705 try {
706 if (myLCPTranscoder == nullptr) {
707 myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
708 }
709 if (myLCPTranscoder != nullptr) {
710 return transcode(myLCPTranscoder->transcode(localString.c_str()));
711 }
712 } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {}
713#endif
714 return localString;
715}
716
717
718std::string
719StringUtils::transcodeToLocal(const std::string& utf8String) {
720#if _XERCES_VERSION > 30100
721 try {
722 if (myLCPTranscoder == nullptr) {
723 myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
724 }
725 if (myLCPTranscoder != nullptr) {
726 XERCES_CPP_NAMESPACE::TranscodeFromStr utf8(reinterpret_cast<const XMLByte*>(utf8String.c_str()), utf8String.size(), "UTF-8");
727 return myLCPTranscoder->transcode(utf8.str());
728 }
729 } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {}
730#endif
731 return utf8String;
732}
733
734
735std::string
736StringUtils::trim_left(const std::string s, const std::string& t) {
737 std::string result = s;
738 result.erase(0, s.find_first_not_of(t));
739 return result;
740}
741
742std::string
743StringUtils::trim_right(const std::string s, const std::string& t) {
744 std::string result = s;
745 result.erase(s.find_last_not_of(t) + 1);
746 return result;
747}
748
749std::string
750StringUtils::trim(const std::string s, const std::string& t) {
751 return trim_right(trim_left(s, t), t);
752}
753
754
755std::string
756StringUtils::wrapText(const std::string s, int width) {
757 std::vector<std::string> parts = StringTokenizer(s).getVector();
758 std::string result;
759 std::string line;
760 bool firstLine = true;
761 bool firstWord = true;
762 for (std::string p : parts) {
763 if ((int)(line.size() + p.size()) < width || firstWord) {
764 if (firstWord) {
765 firstWord = false;
766 } else {
767 line += " ";
768 }
769 line += p;
770 } else {
771 if (firstLine) {
772 firstLine = false;
773 } else {
774 result += "\n";
775 }
776 result += line;
777 line.clear();
778 line += p;
779 }
780 }
781 if (line.size() > 0) {
782 if (firstLine) {
783 firstLine = false;
784 } else {
785 result += "\n";
786 }
787 result += line;
788 }
789 return result;
790}
791
792
793void
797
798
799std::string
800StringUtils::adjustDecimalValue(double value, int precision) {
801 // obtain value in string format with 20 decimals precision
802 auto valueStr = toString(value, precision);
803 // now clear all zeros
804 while (valueStr.size() > 1) {
805 if (valueStr.back() == '0') {
806 valueStr.pop_back();
807 } else if (valueStr.back() == '.') {
808 valueStr.pop_back();
809 return valueStr;
810 } else {
811 return valueStr;
812 }
813 }
814 return valueStr;
815}
816
817/****************************************************************************/
std::pair< int, double > MMVersion
(M)ajor/(M)inor version for written networks and default version for loading
Definition StdDefs.h:71
T MAX2(T a, T b)
Definition StdDefs.h:86
#define KM_PER_MILE
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
std::vector< std::string > getVector()
return vector of strings
static std::string pruneZeros(const std::string &str, int max)
Removes trailing zeros (at most 'max')
static std::string urlEncode(const std::string &url, const std::string encodeWhich="")
encode url (stem from http://bogomip.net/blog/cpp-url-encoding-and-decoding/)
static bool isDouble(const std::string &sData)
check if the given sData can be conveted to double
static MMVersion toVersion(const std::string &sData)
parse a (network) version string
static bool isBool(const std::string &sData)
check if the given value can be converted to bool
static std::string to_upper_case(const std::string &str)
Transfers the content to upper case.
static std::string charToHex(unsigned char c)
char to hexadecimal
static std::string urlDecode(const std::string &encoded)
decode url (stem from http://bogomip.net/blog/cpp-url-encoding-and-decoding/)
static long long int toLong(const std::string &sData)
converts a string into the long value described by it by calling the char-type converter,...
static double toDoubleSecure(const std::string &sData, const double def)
converts a string into the integer value described by it
static std::string trim(const std::string s, const std::string &t=" \t\n")
remove leading and trailing whitespace
static std::string to_lower_case(const std::string &str)
Transfers the content to lower case.
static void resetTranscoder()
must be called when shutting down the xml subsystem
static XERCES_CPP_NAMESPACE::XMLLCPTranscoder * myLCPTranscoder
static std::string trim_right(const std::string s, const std::string &t=" \t\n")
remove trailing whitespace from string
static std::string trim_left(const std::string s, const std::string &t=" \t\n")
remove leading whitespace from string
static std::string escapeShell(const std::string &orig)
Escape special characters with backslash.
static std::string replace(std::string str, const std::string &what, const std::string &by)
Replaces all occurrences of the second string by the third string within the first string.
static int hexToInt(const std::string &sData)
converts a string with a hex value into the integer value described by it by calling the char-type co...
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
static bool isHex(std::string sData)
check if the given string can be converted to hex
static std::string latin1_to_utf8(std::string str)
Transfers from Latin 1 (ISO-8859-1) to UTF-8.
static std::string prune(const std::string &str)
Removes trailing and leading whitechars.
static std::string padFront(const std::string &str, int length, char padding)
static std::string convertUmlaute(std::string str)
Converts german "Umlaute" to their latin-version.
static double parseDist(const std::string &sData)
parse a distance, length or width value with a unit
static std::string adjustDecimalValue(double value, int precision)
write with maximum precision if needed but remove trailing zeros
static unsigned char hexToChar(const std::string &str)
hexadecimal to char
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static std::string wrapText(const std::string s, int width)
remove leading and trailing whitespace
static double parseSpeed(const std::string &sData, const bool defaultKmph=true)
parse a speed value with a unit
static std::string emptyString
An empty string.
Definition StringUtils.h:97
static bool endsWith(const std::string &str, const std::string suffix)
Checks whether a given string ends with the suffix.
static std::string substituteEnvironment(const std::string &str, const std::chrono::time_point< std::chrono::system_clock > *const timeRef=nullptr)
Replaces an environment variable with its value (similar to bash); syntax for a variable is ${NAME}.
static bool isLong(const std::string &sData)
Check if the given sData can be converted to long.
static std::string transcode(const XMLCh *const data)
converts a 0-terminated XMLCh* array (usually UTF-16, stemming from Xerces) into std::string in UTF-8
static std::string transcodeToLocal(const std::string &utf8String)
convert a string from UTF-8 to the local codepage
static int toIntSecure(const std::string &sData, int def)
converts a string into the integer value described by it
static std::string isoTimeString(const std::chrono::time_point< std::chrono::system_clock > *const timeRef=nullptr)
Returns an ISO8601 formatted time string with microsecond precision.
static std::string transcodeFromLocal(const std::string &localString)
convert a string from the local codepage to UTF-8
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static bool isInt(const std::string &sData)
check if the given sData can be converted to int
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter