Разделение строки в C ++ (с использованием cin)

0

Я делаю ЭТУ проблему UVa, которая принимает следующий вход:

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 - два раза и т.д.).

Моя проблема такова: при чтении в 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;
}

lengthFrequency - это map<int,int>.

  • 0
    Я не вижу слов длины один в примере ввода ..
Теги:
string
split
cin

3 ответа

4

Вы можете переопределить то, что поток считает символом пробела, используя std::locale с настраиваемой гранью std::ctype<char>. Вот соответствующий код, который не совсем выполняет задание, но демонстрирует, как использовать грань:

#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";
    }
}
  • 0
    Что ты? Волшебник?! Это потрясающе!
  • 0
    Как насчет дефисов и # ?
Показать ещё 6 комментариев
0

Как насчет этого (используя 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 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 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 строка и все ванильные С++ 98.

Грубая схема того, что я сделал:

  1. Поскольку дефисы встречаются по двум строкам, найдите все дефисы и удалите все новые строки, которые следуют за ними.
  2. Есть символы, которые не добавляют к длине слова, например, законные загибшие слова и апостроф. Найдите их и сотрите их, поскольку они упрощают токенизацию.
  3. Все остальные оставшиеся разделители теперь можно найти и заменить пробелами. Зачем? Поскольку мы можем использовать пробелы в наших интересах, используя потоки (действие по умолчанию - пропустить пробелы).
  4. Создайте поток и отметьте текст через пробелы в соответствии с предыдущим.
  5. Сохраните длину токенов и их появление.
  6. Сортируйте длины токенов, а затем выведите длину токена и соответствующие вхождения.

РЕКОМЕНДАЦИИ:

qaru.site/questions/520277/...

qaru.site/questions/923131/...

0

Прежде чем считать частоты, вы можете проанализировать входную строку и заменить все символы {".",",","!","?"} Пробелами (или любым другим символом разделения, который вы хотите использовать). Тогда ваш существующий код должен работать.

Вы можете обрабатывать некоторые символы по-разному. Например, в случае before.Crazy вы замените '.' с пространством, но для чего-то вроде 'ny! ' 'ny! ' вы бы удалили '!' в целом, потому что за ним уже следует пробел.

  • 0
    Это, вероятно, будет работать на самом деле. Просто сложность разграничения между тем, чтобы поставить пробел и нет, но не так уж плохо. Благодарю.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню