代码之家  ›  专栏  ›  技术社区  ›  adam tropp

有没有一种方法可以与其他循环条件一起使用“删除”习语?

  •  3
  • adam tropp  · 技术社区  · 6 年前

    我有一个函数,在给定一块文本的情况下,应该删除所有标点字符,并将所有字母变为小写,最后,应该根据一个单字母密码移动它们。以下代码有效:

    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 回复  |  直到 6 年前
        1
  •  0
  •   Justin    6 年前

    如果你不想做两个循环,因为 你已经测量过了,发现速度慢了 ,编写自定义算法:

    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 ( relevant Q&A ):

    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;
    }
    
        2
  •  2
  •   Jarod42    6 年前

    range-v3 ,您可以创建(惰性)视图:

    return text | ranges::view::filter([](char c){ return !is_punctuation(c); })
                | ranges::view::transform([](char c) -> char { return to_lower(c); });
    
        3
  •  1
  •   Jans    6 年前

    你可以用 std::accumulate 以及一个迭代器作为init值插入到输出中 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

        4
  •  1
  •   Sid S    6 年前

    复制和/或修改字符,然后截断字符串:

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