使用操纵器忽略标点符号

发布于 2024-09-27 08:16:39 字数 302 浏览 1 评论 0原文

是否可以在 cin 上使用 std 操纵器忽略标点符号?例如,假设您有一个输入流(在实际情况下是一个文件),例如:“一,二三”。我希望能够做到:

f >> ignore_punct >> a;
f >> ignore_punct >> b;
f >> ignore_punct >> c;

最后 a=="one", b=="two", c==" Three"代码>.

Is it possibile to ignore punctuacion using std manipulator on cin? For example suppose you have an input stream (in the actual case a file) like: "one, two three". I want to be able to do:

f >> ignore_punct >> a;
f >> ignore_punct >> b;
f >> ignore_punct >> c;

at the end a=="one", b=="two", c=="three".

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浅浅淡淡 2024-10-04 08:16:39

试试这个:

它使用本地来过滤标点符号。
这允许其余代码保持不变。

#include <locale>
#include <string>
#include <iostream>
#include <fstream>
#include <cctype>

class PunctRemove: public std::codecvt<char,char,std::char_traits<char>::state_type>
{
    bool do_always_noconv() const throw()  { return false;}
    int do_encoding()       const throw()  { return true; }

    typedef std::codecvt<char,char,std::char_traits<char>::state_type> MyType;
    typedef MyType::state_type          state_type;
    typedef MyType::result              result;


    virtual result  do_in(state_type& s,
            const char* from,const char* from_end,const char*& from_next,
                  char* to,        char* to_limit,      char*& to_next  ) const
    {
        /*
         * This function is used to filter the input
         */
        for(from_next = from, to_next = to;from_next != from_end;++from_next)
        {
            if (!std::ispunct(*from_next))
            {
                *to_next = *from_from;
                ++to_next;
            }
        }
        return ok;
    }

    /*
     * This function is used to filter the output
     */
    virtual result do_out(state_type& state,
            const char* from, const char* from_end, const char*& from_next,
                  char* to,         char* to_limit,       char*& to_next  ) const
    { /* I think you can guess this */ }
};


int main()
{
    // stream must be imbued before they are opened.
    // Otherwise the imbing is ignored.
    //
    std::ifstream   data;
    data.imbue(std::locale(std::locale(), new PunctRemove));
    data.open("plop");
    if (!data)
    {
        std::cout << "Failed to open plop\n";
        return 1;
    }

    std::string         line;
    std::getline(data, line);
    std::cout << "L(" << line << ")\n";
}

Try this:

It uses the local to filter out punctuation.
This allows the rest of the code to remain unchanged.

#include <locale>
#include <string>
#include <iostream>
#include <fstream>
#include <cctype>

class PunctRemove: public std::codecvt<char,char,std::char_traits<char>::state_type>
{
    bool do_always_noconv() const throw()  { return false;}
    int do_encoding()       const throw()  { return true; }

    typedef std::codecvt<char,char,std::char_traits<char>::state_type> MyType;
    typedef MyType::state_type          state_type;
    typedef MyType::result              result;


    virtual result  do_in(state_type& s,
            const char* from,const char* from_end,const char*& from_next,
                  char* to,        char* to_limit,      char*& to_next  ) const
    {
        /*
         * This function is used to filter the input
         */
        for(from_next = from, to_next = to;from_next != from_end;++from_next)
        {
            if (!std::ispunct(*from_next))
            {
                *to_next = *from_from;
                ++to_next;
            }
        }
        return ok;
    }

    /*
     * This function is used to filter the output
     */
    virtual result do_out(state_type& state,
            const char* from, const char* from_end, const char*& from_next,
                  char* to,         char* to_limit,       char*& to_next  ) const
    { /* I think you can guess this */ }
};


int main()
{
    // stream must be imbued before they are opened.
    // Otherwise the imbing is ignored.
    //
    std::ifstream   data;
    data.imbue(std::locale(std::locale(), new PunctRemove));
    data.open("plop");
    if (!data)
    {
        std::cout << "Failed to open plop\n";
        return 1;
    }

    std::string         line;
    std::getline(data, line);
    std::cout << "L(" << line << ")\n";
}
夜雨飘雪 2024-10-04 08:16:39

没有标准库的方法可以做到这一点,但如果我理解正确的话,这很容易做到。 一样,那么您可以使用接受谓词而不是单个分隔符的 getline 版本:

template<class F>
std::istream& getline(std::istream& stream, std::string& string, F delim) {

    string.clear();

    // Get characters while the stream is valid and the next character is not the terminating delimiter.
    while (stream && !delim(stream.peek()))
        string += stream.get();

    // Discard delimiter.
    stream.ignore(1);

    return stream;

};

如果您想读取一个字符串直到一些标点符号,就好像它是换行符 示例:

#include <iostream>
#include <cctype>

int main(int argc, char** argv) {

    std::string s;
    getline(std::cin, s, ::ispunct);

    std::cout << s << '\n';
    return 0;

}

如果您还想在换行符上中断,那么您可以编写一个函子:

struct punct_or_newline {
    bool operator()(char c) const { return ::ispunct(c) || c == '\n'; }
};

并调用 getline(std::cin, my_string, punct_or_newline()) 来代替。希望这有帮助!

There's no standard-library way to do it, but it's pretty easy to do, if I understand you correctly. If you want to read a string until some punctuation as though it were a newline, then you could use a version of getline that accepts a predicate instead of a single delimiter:

template<class F>
std::istream& getline(std::istream& stream, std::string& string, F delim) {

    string.clear();

    // Get characters while the stream is valid and the next character is not the terminating delimiter.
    while (stream && !delim(stream.peek()))
        string += stream.get();

    // Discard delimiter.
    stream.ignore(1);

    return stream;

};

Usage example:

#include <iostream>
#include <cctype>

int main(int argc, char** argv) {

    std::string s;
    getline(std::cin, s, ::ispunct);

    std::cout << s << '\n';
    return 0;

}

If you also want to break on newlines, then you can write a functor:

struct punct_or_newline {
    bool operator()(char c) const { return ::ispunct(c) || c == '\n'; }
};

And invoke as getline(std::cin, my_string, punct_or_newline()) instead. Hope this helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文