Форум программистов, компьютерный форум CyberForum.ru

Ввод строки типа {a,b,c,d,f,{a,b,c,f},g,h,j}, исправить код - C++

Восстановить пароль Регистрация
Другие темы раздела
C++ Нужно написать программу со строками http://www.cyberforum.ru/cpp-beginners/thread666360.html
Пожалуйста помогите написать программу, которая будет подсчитывать количество заглавных букв в строке, введенной с клавиатуры. e. выполнить пункты a и b на оценку 4 балла. f. реализовать меню пользователя, состоящее как минимум из 4-х пунктов: a. ввод данных; b. обработка данных; c. вывод результата на экран; d. выход. g. Для корректной работы меню организовать промежуточное хранение...
C++ Сумма ряда до точность E Четвёртый член ряда равен 0.001411 (можете проверить запустив программу) Вопрос: почему не срабатывает строчка (последняя) if(E<b) printf("Sum ryada do tochnosty %f ravna: %f\n", E, w); Когда 0.0001<0.001411? #include <iostream> #include <stdio.h> #include <math.h> using namespace std; int function(); http://www.cyberforum.ru/cpp-beginners/thread666344.html
Обьясните, пожалуйста, строчки C++
CRect rect; GetWindowRect(&rect); rect.OffsetRect(20,20); if (pic_wnd) delete pic_wnd; pic_wnd = new CPicWnd; pic_wnd->some = this; pic_wnd->CreateEx(NULL, "", "", WS_VISIBLE|WS_OVERLAPPEDWINDOW, rect, this, 0);
Реализовать класс Account, представляющий собой банковский счет C++
Б15.12 Реализовать класс Account , представляющий собой банковский счет. В классе должны быть реализованы 4 поля: фамилия владельца, номер счета, процент начисления и сумма в рублях. Необходимо выполнять следующие операции: сменить владельца счета, снять некоторую сумму со счета, положить деньги на счет, начислить проценты, перевести сумму в доллары, перевести сумму в евро, ...
C++ Компилятор и исполняющая среда CUDA http://www.cyberforum.ru/cpp-beginners/thread666324.html
Помогите разобраться... что не так?? Подскажите.. Должно получиться как на первом скрине
C++ Для заданного числа найти не превышающие его дружественные Написать программу, которая для заданного натурального числа N находит, не превышающие это число дружественные. подробнее

Показать сообщение отдельно
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
09.10.2012, 15:23     Ввод строки типа {a,b,c,d,f,{a,b,c,f},g,h,j}, исправить код
Да уже низачем.

Идея в чём. Есть Set parse(const std::string&). Его задача вернуть множество, сконвертированное из строки. Но строка неудобна как инструмент парсинга: у неё нет встроенного указателя на текущий просматриваемый символ, а нам нужен этот указатель. Поэтому мы его создадим и передадим другой функции: Set parse(std::stringstream&). Вот эта parse() и будет вызываться рекурсивно и принимать ссылку на общий stringstream, который хранится в первой функции parse(). Вот так:
C++
1
2
3
4
5
6
Set Set::parse(const std::string &str)
{
  std::stringstream stream(str); // <- вот это надо выполнить до всех
                                 // возможных рекурсивных вызовов
  return parse(stream);
}
А эта вторая parse() уже выполняет собственно парсинг (очень толстая, но неполная подсказка):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Set Set::parse(std::stringstream &str)
{
  enum { OPEN      // ждём пробел или {
         ELEMENT,  // ждём пробел, символ, { или }
         NEXT      // ждём пробел, запятую или }
  } state = OPEN;
  Set theSet; // вот это множество мы вернём, как всё дочитаем
  while (!str.eof()) {
    switch (state) {
    case OPEN:
      switch (str.get()) {
      case ' ':   // при пробеле остаёмся в том же состоянии 
        continue; // и переходим к следующему символу
 
      case '{':          // за { ожидается или следующий элемент-символ,
        state = ELEMENT; // или элемент-множество, или конец множества
        continue;        // ставим нужное состояние и переходим к следующему символу
 
      default:  // синтаксическая ошибка (мы ждём { и только её)
        return Set();
      }
 
    case ELEMENT:
      // peek(), потому что мы не хотим сразу вынимать следующий символ из потока
      switch (str.peek()) {
      case ' ':
        str.ignore();  // пробелы игнорим
        continue;
 
      case ',':
        return Set(); // синтаксическая ошибка (запятая зарезервирована как разделитель)
 
      case '}':
        str.ignore();  // парсинг окончен, забираем этот символ из потока
        return theSet; // и возвращаем собранное множество
 
      case '{':
        theSet.add(parse(str)); // рекурсивно вызываем парсер, добавляем в множество то,
        state = NEXT;  // что он там напарсил, после чего ждём запятой или конца множества
        continue;
 
      default:
        theSet.add(str.get()); // забираем символ из потока, добавляем его и ждём того же
        state = NEXT;
        continue;
      }
 
    case NEXT:
      switch (str.get()) {
      case ' ':
        // пробелы игнорим
      case ',':
        // после запятой мы ждём следующий элемент
      case '}':
        // множество закончилось, возвращаем то, что построили
      default:
        // какая-то непонятная лабуда, выдаём ошибку
      }
    }
  }
  return Set(); // ошибка: неожиданно закончилась строка
}
Да, парсинг это сложно, нудно и вот такие простыни свичей. Это единственный способ, к сожалению. Именно поэтому все пользуются генераторами парсеров, которые напишут эти простынки сами по переданному описанию грамматики языка. Человеку удобнее читать грамматику, а не эту мешанину.

Согласитесь, вот такое:
множество ::= { элементы-множества }
элементы-множества ::= пусто | ещё-элементы-множества
ещё-элементы-множества ::= элемент | элемент , ещё-элементы-множества
элемент ::= атом | множество
атом ::= буква | цифра
гораздо короче и понятнее всей этой простыни. И есть программы-генераторы, которые принимают вот такой файл (ну, почти такой; там ещё указания, что делать с элементами) и сами выдают парсер.

(Боюсь, всё это для вас вообще как китайская грамота.)



Касательно потоков. Вы читали ж что-то из файлов? С помощью fstream? Вот тут тот же принцип, только читается из строки. На параметры не смотрите, они позволяют читать больше, чем один символ за раз. Здесь достаточно читать по одному символу за раз, поэтому без аргументов вообще.

Можете понимать stringstream как безопасный аналог char*. Если у вас есть поле char *cur, то он работает вот так (иллюстративная запись):
C++
1
2
3
4
stringstream(char *str)   ==>   cur = str;
get()                     ==>   return *cur++;
peek()                    ==>   return *cur;
eof()                     ==>   return *cur == '\0';
Можете даже char* и использовать, если так понятнее (метод c_str() вернёт строку в таком виде из std::string). Используется именно он, потому что нас, в общем-то, не волнует какой там длины строка и на каком индексе мы стоим. Важно, что за символ с этим индексом, важно иметь возможность перейти к следующему символу и важно вовремя остановиться.
 
Текущее время: 05:32. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru