Форум кафедры Техники и Электрофизики Высоких Напряжений

Онлайн-сообщество ТВНщиков
Гостям форума:

Добро пожаловать на форум по технике высоких напряжений!
Для получения доступа ко всем разделам необходимо зарегистрироваться


Текущее время: 19 фев 2018, 03:07

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 11 ] 
Автор Сообщение
СообщениеДобавлено: 21 ноя 2017, 22:43 
Не в сети
Site Admin

Зарегистрирован: 03 сен 2008, 16:09
Сообщения: 4210
Откуда: Д-3
Сегодня на занятии мы рассмотрели два способа подсчета числа вхождений символа в текстовом файле. Оба они были недостаточно эффективны, хоть и полезны с точки зрения изучения возможностей языка. Первый способ и вовсе некорректно работал, если символ в слове встречается более одоного раза. Договорились мы о том, что в этой теме будем выкладывать другие способы - чем эффективнее, тем лучше. Способов множество, так что дерзайте.

Привожу код с занятия.

1-й способ:

fstream file("P:\\C++\\deleteme.txt", ios_base::in);
int cntr = 0;
while (!outfile.eof())
{
     string str;
     outfile >> str;
     transform(begin(str), end(str), begin(str), [](unsigned char c) { return toupper(c); });
     auto it = find(str.begin(), str.end(), 'C');
     if (it != str.end())
     cntr++;
}
cout << " cout << "Number of \'c\' entries: " << cntr << endl;


2-й способ:

fstream file("P:\\C++\\deleteme.txt", ios_base::in);
int cntr = 0;
string str;
while (!getline(file, str, '\n').eof())
{
     istringstream iss(str);
     while (iss)
     {
          if (toupper(iss.get()) == 'C')
               cntr++;
     }
}
cout << " cout << "Number of \'c\' entries: " << cntr << endl;


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 22 ноя 2017, 15:16 
Не в сети
Site Admin

Зарегистрирован: 03 сен 2008, 16:09
Сообщения: 4210
Откуда: Д-3
Для выкладывания кода пользуйтесь тегом "Code", он не расцвечивает, к сожалению, но хотя бы шрифт получается адекватный.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 23 ноя 2017, 21:03 
Не в сети

Зарегистрирован: 12 окт 2016, 20:08
Сообщения: 14
Получилась некая смесь первых двух вариантов:

Код:
fstream file("d:\\deleteme.txt", ios_base::in);

int cntr = 0;
string str;

while (!file.eof())
{
   file >> str;
   for (auto i : str)
      if (i == 'e' || i == 'E') cntr++;
}
cout << "Number of \'e\' entries: " << cntr << endl;


Вопрос в следующем. Как оценить эффективность?


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 23 ноя 2017, 22:03 
Не в сети

Зарегистрирован: 10 сен 2010, 22:09
Сообщения: 254
Откуда: из Д3 я
Начало положено, дерзну и я кое-что предложить. Собственно, ничего особого — нашел пару алгоритмов стандартной библиотеки, которые можно, немного покумекав, использовать для решения нашей задачи, и применил по одному из них для случаев считывания файла по формату и неформатированного считывания.

Для начала коррекция 1-го варианта с семинара, избавляющая его от уже упомянутого в этой теме недостатка.

// искомый символ
char cSearched = 'a';

fstream file("i:\\deleteme.txt", ios_base::in);

if (!file)
     cerr << "Can't do it.\n";
else {
     unsigned cntr = 0;
     string str;
     while (!file.eof()) {
          file >> str;
          cntr += str.end() - remove_if(begin(str), end(str), [&cSearched](unsigned char c) {return (toupper(c) == toupper(cSearched)); });
     }
cout << "\nNumber of \'" << cSearched << "\' entries: " << cntr << endl;
}



Теперь вариант со считыванием с помощью getline.

// искомый символ
char cSearched = 'a';

fstream file("i:\\deleteme.txt", ios_base::in);

if (!file)
     cerr << "Can't do it.\n";
else {
     unsigned cntr = 0;
     string str;
     while (!file.eof()) {
          getline(file, str, '\n');
          for_each(begin(str), end(str), [&cSearched, &cntr](unsigned char c) { if (toupper(c) == toupper(cSearched)) cntr++; });
     }
     cout << "\nNumber of \'" << cSearched << "\' entries: " << cntr << endl;
}



P.S. А можно сделать так, чтоб я тоже мог использовать кодировку html? :roll:

P.P.S. Ох как велик был соблазн во втором случае написать
Код:
while (!getline(file, str, 'искомый_символ').eof())
      cntr++;

да регистр мешает :-( Может кому-нибудь придет в голову, как красиво обойти это препятствие?


Последний раз редактировалось ToX@ 27 ноя 2017, 09:41, всего редактировалось 2 раз(а).

Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 24 ноя 2017, 00:53 
Не в сети

Зарегистрирован: 31 окт 2010, 13:50
Сообщения: 20
ToX@ писал(а):
P.P.S. Ох как велик был соблазн во втором случае написать
Код:
while (!getline(file, str, 'искомый_символ').eof())
      cntr++;

да регистр мешает :-( Может кому-нибудь придет в голову, как красиво обойти это препятствие?

Хороший вопрос. Предлагаю следующее решение, которое красивым вряд ли назовёшь (на Visual Studio 2013 должно работать):
Код:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <algorithm>

using namespace std;

struct custom_traits : char_traits<char>
{
   static int_type to_int_type(char_type c)
   {
      return int(toupper(c));
   }
};

void main()
{

   basic_fstream<char, custom_traits> file("J:\\input_file.txt", ios_base::in);
   basic_string<char, custom_traits> str;

   int cntr{ 0 };

   while (!getline(file, str, 'c').eof())
      ++cntr;

   cout << "Number of \'c\' entries: " << cntr << endl;

}


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 24 ноя 2017, 10:37 
Не в сети

Зарегистрирован: 10 сен 2010, 22:09
Сообщения: 254
Откуда: из Д3 я
КириллС. писал(а):
Хороший вопрос. Предлагаю следующее решение, которое красивым вряд ли назовёшь (на Visual Studio 2013 должно работать)


Ну не знаю, а мне понравилось, спс!

Правда, использовать операторы потокового ввода/вывода в/из объекта cin/cout для объекта класса basic_string, параметризованного таким вот "пользовательским" классом Traits, не выходит. Как я понял, причина в том, что в перегруженных для basic_string операторах << и >> класс потокового ввода/вывода и сам basic_string параметризованы одним и тем же Traits, что в нашем случае уже не соблюдается.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 27 ноя 2017, 01:07 
Не в сети
Site Admin

Зарегистрирован: 03 сен 2008, 16:09
Сообщения: 4210
Откуда: Д-3
КириллС. писал(а):
struct custom_traits : char_traits<char>

Да, это очень правильное решение и полезный пример :idea:


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 27 ноя 2017, 01:11 
Не в сети
Site Admin

Зарегистрирован: 03 сен 2008, 16:09
Сообщения: 4210
Откуда: Д-3
Моя альтернативная версия 1-го способа (форматированный ввод):

int cntr = count_if(istream_iterator<unsigned char>(file), istream_iterator<unsigned char>(), [](unsigned char x) {return toupper(x)=='C'; });

Чтобы работало, нужно дополнительно сделать #include <iterator>.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 27 ноя 2017, 02:23 
Не в сети
Site Admin

Зарегистрирован: 03 сен 2008, 16:09
Сообщения: 4210
Откуда: Д-3
ToX@ писал(а):
P.S. А можно сделать так, чтоб я тоже мог использовать кодировку html? :roll:

А попробуй =)


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 27 ноя 2017, 09:44 
Не в сети

Зарегистрирован: 10 сен 2010, 22:09
Сообщения: 254
Откуда: из Д3 я
dmatveev писал(а):
ToX@ писал(а):
P.S. А можно сделать так, чтоб я тоже мог использовать кодировку html? :roll:

А попробуй =)

Работает, спс! Отредактировал сообщение со своими вариантами.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
СообщениеДобавлено: 28 ноя 2017, 12:55 
Не в сети

Зарегистрирован: 10 сен 2010, 22:09
Сообщения: 254
Откуда: из Д3 я
Можно еще при неформатированном считывании использовать не getline, а get. Получается довольно просто, я бы даже сказал "простовато":

// искомый символ
char cSearched = 'a';

fstream file("i:\\deleteme.txt", ios_base::in);
unsigned cntr = 0;

if (!file)
     cerr << "Can't do it.\n";
else {
     while (!file.eof())
          cntr += unsigned(toupper(file.get()) == toupper(cSearched));

     cout << "\nNumber of \'" << cSearched << "\' entries: " << cntr << endl;
}



Ну или с использованием уже изученного нами функтора:

template <typename T>
struct countSymbEntry
{
     countSymbEntry(const unsigned char& s) : s{ unsigned char(toupper(s)) } {}
     unsigned operator() (T& fs) {
          unsigned cntr = 0;
          while (!fs.eof())
               cntr += unsigned(toupper(fs.get()) == s);
          return cntr;
     }
private:
     unsigned char s;
};

void main()
{
     // искомый символ
     char cSearched = 'a';

     fstream file("i:\\deleteme.txt", ios_base::in);

     if (!file)
          cerr << "Can't do it.\n";
     else {
          countSymbEntry<fstream> cse(cSearched);
          cout << "\nNumber of \'" << cSearched << "\' entries: " << cse(file) << endl;
     }
}


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 11 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB