OGS
StringTools.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "StringTools.h"
5
6#include <spdlog/fmt/fmt.h>
7
8#include <algorithm>
9#include <boost/algorithm/string/replace.hpp>
10#include <charconv>
11#include <chrono>
12#include <cstdarg>
13#include <cstdio>
14#include <expected>
15#include <iterator>
16#include <random>
17
18namespace BaseLib
19{
20std::vector<std::string> splitString(std::string const& str)
21{
22 std::istringstream str_stream(str);
23 std::vector<std::string> items;
24 std::copy(std::istream_iterator<std::string>(str_stream),
25 std::istream_iterator<std::string>(),
26 std::back_inserter(items));
27 return items;
28}
29
30std::list<std::string> splitString(const std::string& str, char delim)
31{
32 std::list<std::string> strList;
33 std::stringstream ss(str);
34 std::string item;
35 while (std::getline(ss, item, delim))
36 {
37 strList.push_back(item);
38 }
39 return strList;
40}
41
42std::string replaceString(const std::string& searchString,
43 const std::string& replaceString,
44 std::string stringToReplace)
45{
46 boost::replace_all(stringToReplace, searchString, replaceString);
47 return stringToReplace;
48}
49
50void trim(std::string& str, char ch)
51{
52 std::string::size_type pos = str.find_last_not_of(ch);
53 if (pos != std::string::npos)
54 {
55 str.erase(pos + 1);
56 pos = str.find_first_not_of(ch);
57 if (pos != std::string::npos)
58 {
59 str.erase(0, pos);
60 }
61 }
62 else
63 {
64 str.erase(str.begin(), str.end());
65 }
66}
67
68void simplify(std::string& str)
69{
70 trim(str);
71 str.erase(std::unique(str.begin(),
72 str.end(),
73 [](char a, char b) { return a == ' ' && b == ' '; }),
74 str.end());
75}
76
77std::string format(const char* format_str, ...)
78{
79 va_list args;
80 va_start(args, format_str);
81 // get the number of chars to write
82 va_list args_tmp;
83 va_copy(args_tmp, args);
84 int char_length = std::vsnprintf(nullptr, 0, format_str, args_tmp);
85 va_end(args_tmp);
86 // allocate buffer and store formatted output there
87 std::vector<char> buffer(char_length + 1); // note +1 for null terminator
88 vsnprintf(buffer.data(), buffer.size(), format_str, args);
89 va_end(args);
90
91 return std::string(buffer.data());
92}
93
94std::string randomString(std::size_t const length)
95{
96 static constexpr char charset[] =
97 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
98
99 static const auto seed = static_cast<std::mt19937::result_type>(
100 std::chrono::system_clock::now().time_since_epoch().count());
101 static std::mt19937 generator{seed};
102 static std::uniform_int_distribution<unsigned short> distribution(
103 0, sizeof(charset) - 2);
104
105 std::string s(length, 0);
106 std::generate_n(begin(s), length,
107 [&]() { return charset[distribution(generator)]; });
108
109 return s;
110}
111
112std::string getUniqueName(std::vector<std::string> const& existing_names,
113 std::string const& input_name)
114{
115 std::string result_name = input_name;
116 std::size_t count = 1;
117 while (std::find(existing_names.cbegin(),
118 existing_names.cend(),
119 result_name) != existing_names.end())
120 {
121 count++;
122 result_name = input_name + "-" + std::to_string(count);
123 }
124 return result_name;
125}
126std::expected<int, std::string> parseInteger(std::string_view str)
127{
128 int result = 0;
129 auto const [ptr, ec] =
130 std::from_chars(str.data(), str.data() + str.size(), result);
131
132 if (ec == std::errc::invalid_argument)
133 {
134 return std::unexpected(
135 fmt::format("Could not parse '{}' to a valid integer.", str));
136 }
137 if (ec == std::errc::result_out_of_range)
138 {
139 return std::unexpected(fmt::format(
140 "Could not parse '{}'. The integer value exceeds the permitted "
141 "range.",
142 str));
143 }
144
145 std::size_t const chars_consumed = std::distance(str.data(), ptr);
146 if (chars_consumed != str.size())
147 {
148 auto const non_ws_it = std::find_if_not(
149 str.begin() + chars_consumed, str.end(),
150 [](unsigned char const c) { return std::isspace(c); });
151 if (non_ws_it != str.end())
152 {
153 return std::unexpected(fmt::format(
154 "Could not parse '{}'. Invalid character: '{}' at position {}.",
155 str, *non_ws_it, std::distance(str.begin(), non_ws_it)));
156 }
157 }
158
159 return result;
160}
161
162} // end namespace BaseLib
void simplify(std::string &str)
std::expected< int, std::string > parseInteger(std::string_view str)
std::string randomString(std::size_t const length)
Returns a random string of the given length containing just a-z,A-Z,0-9.
std::string getUniqueName(std::vector< std::string > const &existing_names, std::string const &input_name)
Append '-' and a number such that the name is unique.
std::string replaceString(const std::string &searchString, const std::string &replaceString, std::string stringToReplace)
void trim(std::string &str, char ch)
std::string format(const char *format_str,...)
std::vector< std::string > splitString(std::string const &str)