用字符串中的双精度替换每个匹配项

Replace every occurrence with double in string

我正在尝试编写一个函数,其第一个参数是字符串,第二个参数是实数向量。该函数应该 return 作为一个新字符串的结果,其中每次出现都将序列“%d”或“%f”替换为向量中的一个数字,按照它们出现的顺序。这样做时,如果序列是“%d”,数字中的任何小数都将被截断,而在序列“%f”中,它们将被保留。

例如,如果字符串为“abc%dxx%fyy %d”并且向量包含数字 12.25、34.13、25 和 47,则新字符串应为“abc12xx34.13yy 25”(数据 47这是“多余的”被简单地忽略了)。

#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

输出正确。我如何修改它以使用更少的代码行?有没有办法让它更优雅、更高效?

#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;
}

您可以使用:

  1. 用于搜索模式 (%d|%f) 的正则表达式,即 %d%f,以及
  2. 创建字符串的字符串流 return。

进入更多细节:

  • 代码基本上就是一个while (std::regex_search).
  • std::regex_search 将 return 匹配模式之前的输入字符串中的任何内容(输出字符串中您想要的内容),匹配的模式(您需要检查以决定的内容如果你想写出一个 int 或 double),以及剩下的任何解析。
  • 通过使用 std::ostringstream,您可以简单地写出整数或双精度数,而无需自己将它们转换为字符串。
  • vek.at() 如果您 运行 向量中的数据不足,将抛出 std::out_of_range 异常。
  • 还请注意,对于此实现,最好按值传递字符串 s(因为我们在函数内修改它),您应该将 vek 作为常量引用传递避免复制整个向量。

[Demo]

#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

[编辑] 没有 std::regex_search 的一种可能方法是手动搜索 (%d|%f) 模式,在循环中使用 std::string::find 直到字符串末尾是达到。

下面的代码考虑到了:

  • 输入字符串不能有那个模式,那个
  • 它可以有一个 % 字符,后面既没有 d 也没有 f

[Demo]

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>

std::string Replace(std::string s, const std::vector<double>& vek) {
    std::ostringstream oss{};
    size_t previous_pos{0};
    size_t pos{0};
    auto i{0};
    while (previous_pos != s.size()) {
        if ((pos = s.find('%', previous_pos)) == std::string::npos) {
            oss << s.substr(previous_pos);
            break;
        }
        oss << s.substr(previous_pos, pos - previous_pos);
        bool pattern_found{false};
        if (s.size() > pos + 1) {
            auto c{s[pos + 1]};
            if (c == 'd') {
                oss << static_cast<int>(vek.at(i));
                pattern_found = true;
            } else if (c == 'f') {
                oss << vek.at(i);
                pattern_found = true;
            }
        }
        if (pattern_found) {
            ++i;
            previous_pos = pos + 2;
        } else {
            oss << s[pos];
            previous_pos = pos + 1;
        }
    }
    return oss.str();
}

int main() {
    try {
        std::cout << Replace("abc%%dx%x%fyy %d", {12.25, 34.13, 25}) << "\n";
        std::cout << "abc%12x%x34.13yy 25\n";
        std::cout << Replace("abcdxxfyy d", {12.25, 34.13, 25}) << "\n";
        std::cout << "abcdxxfyy d\n";
    } catch (std::out_of_range& e) {
        std::cout << e.what();
    }
}

// Outputs:
//
//   abc%12x%x34.13yy 25
//   abc%12x%x34.13yy 25
//   abcdxxfyy d
//   abcdxxfyy d