I'm trying to write a function whose first parameter is a string and the second parameter is vector of real numbers. The function should return as a result a new string in which each occurrence replaces the sequences "%d" or "%f" with one number each from the vector, in the order in which they appear. In doing so, if the sequence is "%d", any decimals in the number are truncated, while in the sequence "%f" they are retained.
For example, if the string reads “abc%dxx%fyy %d” and if the vector contains the numbers 12.25, 34.13, 25 and 47, the new string should read “abc12xx34.13yy 25” (data 47 which is “redundant” is simply ignored).
#include <iostream>
#include <string>
#include <vector>
std::string Replace(std::string s, std::vector < double > vek) {
std::string str;
int j = 0;
for (int i = 0; i < s.length(); i ) {
while (s[i] != '%' && i < s.length()) {
if (s[i] != 'f' && s[i] != 'd')
str = s[i];
i ;
}
if (s[i] == '%' && (s[i 1] == 'd' || s[i 1] == 'f')) {
if (s[i 1] == 'd')
str = (std::to_string(int(vek[j])));
if (s[i 1] == 'f') {
std::string temp = std::to_string(vek[j]);
int l = 0;
while (temp[l] != '0') {
str = temp[l];
l ;
}
}
j ;
if (j > vek.size())
throw std::range_error("Not enough elements");
if (i == s.length()) break;
}
}
return str;
}
int main() {
try {
std::cout<<Replace("abc%dxx%fyy %d",{12.25, 34.13, 25});
std::cout << "\n" << "abc12xx34.13yy 25";
} catch (std::range_error e) {
std::cout << e.what();
}
return 0;
}
OUTPUT:
abc12xx34.13yy 25
abc12xx34.13yy 25
Output is correct. How could I modify this to work with less lines of code? Is there any way to make this more elegant and efficient?
CodePudding user response:
You could use:
- regular expressions to search for the pattern
(%d|%f)
, i.e.,%d
or%f
, and - a string stream to create the string to return.
Going into some more detail:
- The code is basically a
while (std::regex_search)
. std::regex_search
will return whatever was in the input string before the matched pattern (what you want in the output string), the matched pattern (what you will need to check in order to decide if you want to write out an int or a double), and whatever is left to parse.- By using
std::ostringstream
, you can simply write out ints or doubles without converting them to strings yourself. vek.at()
will throw anstd::out_of_range
exception if you run out of data in the vector.- Notice as well that, whereas for this implementation it's good to pass the string
s
by value (since we are modifying it within the function), you should passvek
as a const reference to avoid a copy of the whole vector.
#include <iostream>
#include <regex>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
std::string Replace(std::string s, const std::vector<double>& vek) {
std::regex pattern{"(%d|%f)"};
std::smatch match{};
std::ostringstream oss{};
for (auto i{0}; std::regex_search(s, match, pattern); i) {
oss << match.prefix();
auto d{vek.at(i)};
oss << ((match[0] == "%d") ? static_cast<int>(d) : d);
s = match.suffix();
}
return oss.str();
}
int main() {
try {
std::cout << Replace("abc%dxx%fyy %d", {12.25, 34.13, 25});
std::cout << "\n"
<< "abc12xx34.13yy 25";
} catch (std::out_of_range& e) {
std::cout << e.what();
}
}
// Outputs:
//
// abc12xx34.13yy 25
// abc12xx34.13yy 25
CodePudding user response:
#include <iostream>
#include <vector>
#include <string>
std::string replace(std::string str, std::vector<double> vec) {
std::string result = "";
int i = 0;
// loop through the string
while (i < str.size()) {
// if the current character is a %
if (str[i] == '%') {
// if the next character is a d
if (str[i 1] == 'd') {
// if the vector is not empty
if (vec.size() > 0) {
// add the first element of the vector to the result
result = std::to_string(vec[0]);
// remove the first element of the vector
vec.erase(vec.begin());
}
// move the index to the next character
i = 2;
}
// if the next character is a f
else if (str[i 1] == 'f') {
// if the vector is not empty
if (vec.size() > 0) {
// add the first element of the vector to the result
result = std::to_string(vec[0]);
// remove the first element of the vector
vec.erase(vec.begin());
}
// move the index to the next character
i = 2;
}
// if the next character is not a d or f
else {
// add the current character to the result
result = str[i];
// move the index to the next character
i = 1;
}
}
// if the current character is not a %
else {
// add the current character to the result
result = str[i];
// move the index to the next character
i = 1;
}
}
// return the result
return result;
}
int main() {
std::vector<double> vec = {12.25, 34.13, 25, 47};
std::string str = "abc%dxx%fyy %d";
std::cout << replace(str, vec);
return 0;
}