【问题标题】:Splitting a String in C++ (using cin)在 C++ 中拆分字符串(使用 cin)
【发布时间】:2013-11-03 22:54:57
【问题描述】:

我在做THISUVa 问题,它接受以下输入:

This is fun-
ny!  Mr.P and I've never seen
this ice-cream flavour
before.Crazy eh?
#
This is fun-
ny!  Mr.P and I've never seen
this ice-cream flavour
before.Crazy eh?
#

并产生这个输出:

1 1
2 3
3 2
4 3
5 3
6 1
7 1
8 1

1 1
2 3
3 2
4 3
5 3
6 1
7 1
8 1

在输入中,# 划分案例。我应该获取每个单词的长度并计算每个不同长度的频率(如您在输出中看到的,长度为 1 的单词出现一次,长度为 2 的单词出现 3 次,3 出现两次,依此类推)。

我的问题是:在 cin 中阅读时,before.Crazy 被计为一个单词,因为它们之间没有空格。那么它应该就像在某些标点符号上拆分字符串一样简单(例如{".",",","!","?"})......但是C++似乎没有简单的方法来拆分字符串。

那么,我的问题是:如何拆分字符串并将每个返回的字符串发送到处理其余问题的函数?

这是我的代码:

int main()
{
    string input="";
    while(cin.peek()!=-1)
    {   
        while(cin >> input && input!="#")
        {
            lengthFrequency(input);
            cout << input << " " << input.length() << endl;
        }

        if(cin.peek()!=-1) cout << endl;
        lengthFrequencies.clear();
    }
    return 0;
}

lengthFrequencymap&lt;int,int&gt;

【问题讨论】:

  • 我在示例输入中没有看到任何长度为 1 的单词..

标签: c++ string split cin


【解决方案1】:

您可以使用带有自定义std::ctype&lt;char&gt; 构面的std::locale 重新定义流认为是空白字符的内容。这是相应的代码,它并没有完全完成分配,但演示了如何使用方面:

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

struct ctype
    : std::ctype<char>
{
    typedef std::ctype<char> base;
    static base::mask const* make_table(char const* spaces,
                                        base::mask* table)
    {
        base::mask const* classic(base::classic_table());
        std::copy(classic, classic + base::table_size, table);
        for (; *spaces; ++spaces) {
            table[int(*spaces)] |= base::space;
        }
        return table;
    }
    ctype(char const* spaces)
        : base(make_table(spaces, table))
    {
    }
    base::mask table[base::table_size];
};

int main()
{
    std::cin.imbue(std::locale(std::locale(), new ctype(".,!?")));
    for (std::string s; std::cin >> s; ) {
        std::cout << "s='" << s << "'\n";
    }
}

【讨论】:

  • 你是什么人?一个巫师?!太棒了!
  • 连字符和#怎么样?
  • @jrd1:在某些时候,我已经为我的实验性标准 C++ 库实现CXXRT 实现了语言环境和 IOStreams。结果,我知道有哪些类以及如何使用它们来自定义 IOStreams。
  • @DietmarKühl:好东西。感谢您的解释和链接到您的图书馆! :)
  • @jrd1:请注意,该库大约十年以来一直没有维护。我希望最终能够发布更新,但到目前为止我还没有找到时间......
【解决方案2】:

在计算频率之前,您可以解析输入字符串并将所有{".",",","!","?"} 字符替换为空格(或您想要使用的任何分隔字符)。那么你现有的代码应该可以工作了。

您可能希望以不同的方式处理某些字符。例如,对于before.Crazy,您可以将'.' 替换为一个空格,但对于'ny! ',您将完全删除'!',因为它后面已经有一个空格。

【讨论】:

  • 这实际上可能会起作用。只是区分放置空间和不放置空间的复杂性,但还不错。谢谢。
【解决方案3】:

这个怎么样(使用 STL、比较器和仿函数)?

注意:所有假设和解释都在源代码本身中。

#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <utility>
#include <string.h>

bool compare (const std::pair<int, int>& l, const std::pair<int, int>& r) {
    return l.first < r.first;
}

//functor/unary predicate:
struct CompareFirst {
    CompareFirst(int val) : val_(val) {}
    bool operator()(const std::pair<int, int>& p) const {
        return (val_ == p.first);
    }
private:
    int val_;
};

int main() {
    char delims[] = ".,!?";
    char noise[] ="-'";

    //I'm assuming you've read the text from some file, and that information has been stored in a string. Or, the information is a string (like below):
    std::string input = "This is fun-\nny,  Mr.P and I've never seen\nthis ice-cream flavour\nbefore.Crazy eh?\n#\nThis is fun-\nny!  Mr.P and I've never seen\nthis ice-cream flavour\nbefore.Crazy eh?\n#\n";

    std::istringstream iss(input);
    std::string temp;

    //first split the string by #
    while(std::getline(iss, temp, '#')) {

        //find all the occurences of the hypens as it crosses lines, and remove the newline:
        std::string::size_type begin = 0;

        while(std::string::npos != (begin = temp.find('-', begin))) {
            //look at the character in front of the current hypen and erase it if it's a newline, if it is - remove it
            if (temp[begin+1] == '\n') {
                temp.erase(begin+1, 1);
            }
            ++begin;
        }

        //now, erase all the `noise` characters ("'-") as these count as these punctuation count as zero
        for (int i = 0; i < strlen(noise); ++i) {
            //this replaces all the hyphens and apostrophes with nothing
            temp.erase(std::remove(temp.begin(), temp.end(), noise[i]), temp.end());//since hyphens occur across two lines, you need to erase newlines
        }//at this point, everything is dandy for complete substitution

        //now try to remove any other delim chracters by replacing them with spaces
        for (int i = 0; i < strlen(delims); ++i) {
            std::replace(temp.begin(), temp.end(), delims[i], ' ');
        }

        std::vector<std::pair<int, int> > occurences;

        //initialize another input stringstream to make use of the whitespace
        std::istringstream ss(temp);

        //now use the whitespace to tokenize
        while (ss >> temp) {

            //try to find the token's size in the occurences
            std::vector<std::pair<int, int> >::iterator it = std::find_if(occurences.begin(), occurences.end(), CompareFirst(temp.size()));

            //if found, increment count by 1
            if (it != occurences.end()) {
                it->second += 1;//increment the count
            }
            //this is the first time it has been created. Store value, and a count of 1
            else {
                occurences.push_back(std::make_pair<int, int>(temp.size(), 1));
            }
        }

        //now sort and output:
        std::stable_sort(occurences.begin(), occurences.end(), compare);

        for (int i = 0; i < occurences.size(); ++i) {
            std::cout << occurences[i].first << " " << occurences[i].second << "\n";
        }
        std::cout << "\n";
    }

    return 0;
}

91 行,所有原版 C++98。

我所做的大致轮廓是:

  1. 由于连字符跨越两行找到所有连字符并删除它们后面的所有换行符。
  2. 有些字符不会增加单词的长度,例如合法的连字符和撇号。 找到并删除它们,因为它使标记化更容易。
  3. 现在可以找到所有其他剩余的分隔符并将其替换为空格。为什么?因为我们可以通过使用流(其默认操作是跳过空格)来利用空格。
  4. 如前所述,创建一个流并通过空格标记文本
  5. 存储标记的长度及其出现次数
  6. 对token的长度进行排序,然后输出token的长度和对应的出现次数。

参考:

https://stackoverflow.com/a/5815875/866930

https://stackoverflow.com/a/12008126/866930

【讨论】:

    猜你喜欢
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-04
    • 2015-06-29
    相关资源
    最近更新 更多