Есть ли способ использовать стирание-удаление идиома в сочетании с другими условиями зацикливания? - PullRequest
0 голосов
/ 29 декабря 2018

У меня есть функция, которая, учитывая блок текста, должна удалять все знаки пунктуации и делать все буквы строчными, а в конечном итоге - сдвигать их в соответствии с моно-буквенным шифром.Приведенный ниже код работает:

class Cipher { 
  public:

  string keyword; 

  string decipheredText;

  deque<string> encipheredAlphabet;

    static bool is_punctuation (char c) {
      return c ==  '.' || c == ',' || c == '!' || c == '\''|| c == '?' || c 
      == ' ';
    }

  string encipher(string text) { 
    Alphabet a;
    encipheredAlphabet = a.cipherLetters(keyword);


    text.erase( remove_if(text.begin(), text.end(), is_punctuation), 
    text.end() );

    string::iterator it;
    for (it = text.begin(); it != text.end(); it++) { 
      *it = tolower(*it); 
      // encipher text according to shift
    }

    return text;
  }

};

Проблема в том, что в настоящее время он делает два прохода над строкой, один для удаления пунктуации и один для выполнения всех остальных действий.Это кажется неэффективным, поскольку кажется, что все преобразования могут быть выполнены как-то за один проход через строку.Есть ли чистый способ включить идирацию удаления-удаления с другими условиями цикла?

Ответы [ 4 ]

0 голосов
/ 29 декабря 2018

С range-v3 вы можете создать (ленивое) представление:

return text | ranges::view::filter([](char c){ return !is_punctuation(c); })
            | ranges::view::transform([](char c) -> char { return to_lower(c); });
0 голосов
/ 29 декабря 2018

Если вы не хотите делать два цикла, потому что вы измерили и обнаружили, что он медленнее , напишите собственный алгоритм:

template <typename Iter, typename OutIter>
OutIter lowercased_without_punctuation(Iter begin, Iter end, OutIter out) {
    while (begin != end) {
        // Ignoring things like std::move_iterator for brevity.
        if (!is_punctuation(*begin)) {
            *out = tolower(*begin);
            ++out;
        }

        // Use `++iter` rather than `iter++` when possible
        ++begin;
    }

    return out;
}

// ...

string encipher(string text) {
    Alphabet a;
    encipheredAlphabet = a.cipherLetters(keyword);

    text.erase(
        lowercased_without_punctuation(text.begin(), text.end(), text.begin()),
        text.end());

    return text;
}

Если вы подумаете об этом,более того, lowercased_without_punctuation на самом деле является частным случаем более общего алгоритма, который можно назвать transform_if ( соответствующие вопросы и ответы ):

template <typename Iter, typename OutIter, typename Pred, typename Transf>
OutIter transform_if(Iter begin, Iter end, OutIter out, Pred p, Transf t) {
    while (begin != end) {
        if (p(*begin)) {
            *out = t(*begin);
            ++out;
        }

        ++begin;
    }

    return out;
}

// ...

string encipher(string text) {
    Alphabet a;
    encipheredAlphabet = a.cipherLetters(keyword);

    text.erase(
        transform_if(text.begin(), text.end(), text.begin(),
            [](char c) { return !is_punctuation(c); },
            [](char c) { return tolower(c); }),
        text.end());

    return text;
}
0 голосов
/ 29 декабря 2018

Скопируйте и / или измените символы, затем обрежьте строку:

string encipher(string text)
{
    auto it = text.begin(),
         jt = it;
    for (; it != text.end(); it++)
    {
        if (!is_punctuation(*it))
        {
            *jt = tolower(*it);
            ++jt;
        }
    }
    text.erase(jt, it);
    return text;
}
0 голосов
/ 29 декабря 2018

Вы можете сделать это, используя std :: аккумулировать и итератор в качестве значения инициализации, которое вставляется в вывод std::string

auto filter = [](auto pred) {
    return [=](auto map) {
        auto accumulator = [=](auto it, auto c) {
            if (pred(c)) {
                *it = map(c);
            }
            return ++it;
        };
        return accumulator;
    };
};

auto accumulator = filter(std::not_fn(is_punctuation))
([](auto c) {
    return std::tolower(c);
});

std::string in = "insIsjs.|s!js";
std::string out;
std::accumulate(std::begin(in), std::end(in), std::back_inserter(out), accumulator);

См. demo

...