Как эффективно заменить символы в std :: string итеративными значениями из другого std :: string? - PullRequest
3 голосов
/ 08 мая 2020

У меня есть следующие строки:

std::string str1 = "1234567890";
std::string str2 = "B-XXXX_XXX_V-XX_X";

Я хочу от l oop до str2 и заменить каждое вхождение X последующим значением из str1, в результате получится: B-1234_567_V-89_0 .

У меня есть подобие решения ниже, но оно не очень эффективно (в какой-то момент сработало). Вкратце, я попытался l oop через символы в str2, и если символ равен 'X', замените этот символ на увеличивающийся индекс из str1:

  int ind = 0;
  std::string pattern_char;
  for (int i = 0; i < str2.size(); i++) {
    pattern_char = str2[i];
    if (pattern_char == "X") {
      str2[i] = str1[x_ind];
      x_ind++;
    }
  }

Что такое наиболее эффективный способ выполнить эту операцию?

Ответы [ 4 ]

3 голосов
/ 08 мая 2020

Ваша текущая реализация обрабатывает каждую отдельную единицу строки как std::string, а не как отдельную char, что приводит к некоторым ненужным накладным расходам. Вот перезапись, которая использует char s:

  int x_ind = 0;
  for (int i = 0; i < str2.size(); i++) {
    if (str2[i] == 'X') {    // Don't assign str2[i] to a char; use character literals
      str2[i] = str1[x_ind];
      x_ind++;
    }
  }

. Вы можете улучшить читаемость, используя диапазон для l oop, например:

  int x_ind = 0;
  for (char& ch: str2) {
    if (ch == 'X') {
      ch = str1[x_ind];
      x_ind++;
    }
  }
1 голос
/ 08 мая 2020

Если с помощью «не очень эффективно» вы хотите улучшить свой текущий код, возможно, единственное, что нужно сделать, это переписать ваш l oop:

int idx = 0;
for (char& c : str2) {
    if (c == 'X')
      c = str1[idx++];
}

Но если вы хотите написать это, используя только стандартную библиотеку, вы можете сделать то же самое, используя std::transform():

#include <algorithm>
#include <iostream>
#include <string>

int main()
{
    std::string str1 = "1234567890";
    std::string str2 = "B-XXXX_XXX_V-XX_X";
    int i = 0;
    std::transform(str2.begin(), str2.end(), str2.begin(),
                   [&str1, &i](const char& c) -> char {
                       return c == 'X' ? str1[i++] : c;
                   });

    std::cout << str2 << std::endl;
}
0 голосов
/ 08 мая 2020

Вот еще одно решение:

auto i = str1.begin();
for (char& ch: str2) {
  if (ch == 'X') 
    ch = *i++;
0 голосов
/ 08 мая 2020

Единственная проблема, которую я вижу с вашим кодом, заключается в том, что вы используете ненужное std::string pattern_char;:

#include <string>
#include <iostream>
#include <stdexcept>

auto replace_with_pattern(std::string& str, char ch_to_replace, const std::string& pattern)
{
    auto pattern_it = pattern.begin();

    for (char& ch : str)
    {
        if (ch == ch_to_replace)
        {
            if (pattern_it == pattern.end())
                throw std::invalid_argument{"ran out of pattern"};

            ch = *pattern_it;
            ++pattern_it;
        }
    }
}

int main()
{
    std::string str1 = "1234567890";
    std::string str2 = "B-XXXX_XXX_V-XX_X";


    replace_with_pattern(str2, 'X', str1);

    std::cout << str2 << std::endl;
}
...