struct NOTEBOOK{
char model[21]; //наименование
struct size{ // габаритные размеры
float x;
float y;
float z;
};
float w; //вес
int price; //цена
}
#include <locale>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstring>
#include <iterator>
#include <valarray>
#include <stdexcept>
#include <regex>
#include <cerrno>
#include <list>
// Входной файл
const char* const IN_FILE_NAME="../Data/note.txt";
// Выходной файл
const char* const OUT_FILE_NAME="note.bin";
// Величина табуляции по умолчанию
const size_t TAB_WIDTH=8;
// Типы используемых данных
// Введены для улучшения совместимости и меньшего количества ручной работы
// для написания сходных заданий 178618, 178619, 178620
// Тип символов с которыми будем работать
typedef char CharType;
// Пробел
const CharType SPACE=' ';
// Строковый тип
typedef std::basic_string<CharType> String;
// Файловые типы
typedef std::basic_ifstream<CharType> InFile;
typedef std::basic_ofstream<CharType> OutFile;
// Базовый контейнер
typedef std::list<class Notebook> BaseContainer;
// Габариты
class BoxSize
{
public:
explicit BoxSize(float x=0,float y=0,float z=0);
float x()const;
float y()const;
float z()const;
private:
float _x,_y,_z;
};
// Оператор вывода для BoxSize
template<class Elem,class Traits>
std::basic_ostream<Elem,Traits>& operator<<(std::basic_ostream<Elem,Traits>& stream,const BoxSize& size)
{
const std::ctype<Elem>& fac=std::use_facet<std::ctype<Elem> >(stream.getloc());
Elem x=fac.widen('x');
return stream<<size.x()<<x<<size.y()<<x<<size.z();
}
// Класс - ноутбук
class Notebook
{
public:
// Длина наименования модели
static const size_t MODEL_LEN=20;
Notebook(const char* const model,BoxSize size,float weight,int price);
// Модель
const char* const model()const;
// Габариты
BoxSize size()const;
// Вес
float weight()const;
// Цена
int price()const;
// Метод записывающий данные в конец бинарного файла. true в случае успеха
bool write(OutFile& file)const;
private:
char _model[MODEL_LEN+1];
BoxSize _size;
float _weight;
int _price;
};
// Оператор вывода для Notebook
template<class Elem,class Traits>
std::basic_ostream<Elem,Traits>& operator<<(std::basic_ostream<Elem,Traits>& stream,const Notebook& notebook)
{
return stream<<std::left<<std::setw(Notebook::MODEL_LEN)<<notebook.model()<<'\t'
<<std::setw(6)<<notebook.price()<<'\t'
<<std::setw(5)<<notebook.weight()<<'\t'<<notebook.size();
}
// Класс - контейнер создан для меньшего количества исправлений необходимых для решения 3х задач
// Базовый класс - список
class Container:protected BaseContainer
{
public:
// Заносит запись в контейнер
void put(const Notebook& note);
// Извлекает запись из контейнера
Notebook get();
// Сортирует данные в контейнере используя функцию-предикат
void sort(bool (*pred)(const Notebook&,const Notebook&));
// Откроем для публичного доступа некоторые члены базового класса
BaseContainer::begin;
BaseContainer::end;
BaseContainer::size;
typedef BaseContainer::iterator iterator;
typedef BaseContainer::const_iterator const_iterator;
};
// Функция-предикат для сортировки
bool sortPredicate(const Notebook& n1,const Notebook& n2);
// Ф-я возвращает контейнер с записями о ноутбуках у которых объем HDD<1Gb
Container readHDDLess1Gb(InFile& file);
int main()
{
std::locale::global(std::locale(""));
setlocale(LC_NUMERIC,"C");
try
{
// Откроем файл
InFile inFile(IN_FILE_NAME);
if(!inFile)
{
throw InFile::failure(std::string("Не возможно открыть файл:")+IN_FILE_NAME);
}
// Читаем данные
Container notes=readHDDLess1Gb(inFile);
// Закроем файл
inFile.close();
// Откроем файл для вывода как двоичный
OutFile outFile(OUT_FILE_NAME,OutFile::binary|OutFile::trunc|OutFile::out);
if(!outFile)
{
throw OutFile::failure(std::string("Не возможно открыть файл:")+OUT_FILE_NAME);
}
outFile.exceptions(outFile.failbit);
#ifdef _DEBUG
std::cout<<"Выводим данные о ноутбуках с объемом HDD менее 1Gb"<<std::endl;
#endif
try
{
// Выводим 2 байта информации о количестве записей
unsigned short size=notes.size();
outFile.write(reinterpret_cast<const CharType*>(&size),sizeof(size));
// Выводим в файл и на экран для контроля
for(Container::const_iterator it=notes.begin();it!=notes.end();++it)
{
it->write(outFile);
#ifdef _DEBUG
std::cout<<*it<<std::endl;
#endif
}
outFile.close();
}
catch (OutFile::failure& ex)
{
std::cerr<<"Ошибка записи в файл:"<<OUT_FILE_NAME<<std::endl<<ex.what()<<std::endl;
return 1;
}
}
catch (std::exception& ex)
{
std::cerr<<"Исключение: "<<ex.what()<<std::endl;
}
catch(...)
{
std::cerr<<"Неизвестное исключение"<<std::endl;
}
_getwch();
return 0;
}
bool sortPredicate(const Notebook& n1,const Notebook& n2)
{
return strcoll(n1.model(),n2.model())<0;
}
// Ф-я удаляет символы табуляции из файла
// Поскольку нет точной спецификации на формат входных данных приходится гадать
String expandTabs(const String& str,const size_t tabWidth=TAB_WIDTH)
{
String result;
// Идем по строке
for(String::const_iterator it=str.begin(),end=str.end();it!=end;++it)
{
// Если встретился знак табуляции
if(*it=='\t')
{
// Вычисляем количество необходимых пробелов
String::size_type spaceCount=static_cast<String::size_type>(std::ceil(static_cast<double>(result.length())/tabWidth)*tabWidth)-result.length();
if(!spaceCount)
{
spaceCount=tabWidth;
}
// Заменяем табуляцию пробелами
result+=String().assign(spaceCount,SPACE);
}
else
{
result+=*it;
}
}
return result;
}
// Размер полей данных в файле
const size_t FIELDS_LENGTH[]={24,8,8,16,8,8,8,8,16,8,8};
// Их количество
const size_t FIELDS_COUNT=sizeof(FIELDS_LENGTH)/sizeof(FIELDS_LENGTH[0]);
// Для удобства именуем эти поля
enum FIELD_NAMES
{
MODEL_INDEX=0,
PRICE_INDEX,
WEIGHT_INDEX,
SIZE_INDEX,
HDD_SIZE_INDEX=10
};
// Удаляет начальные/конечные пробелы из строки
String trim(const String& str)
{
String::size_type beg=0,end=str.length();
// Ишем первый не пробел
while(beg<end)
{
if(!isspace(str[beg]))
{
break;
}
++beg;
}
// Ищем последний не пробел
while(beg<end)
{
if(!isspace(str[end-1]))
{
break;
}
--end;
}
return str.substr(beg,end-beg);
}
typedef std::valarray<String> Fields;
// Разбивает строку на набор полей данных. Если удачно то возвращает true
bool parseNoteString(const String& str,Fields& result)
{
result.resize(FIELDS_COUNT);
// Перебираем поля
for(size_t i=0,offset=0;i<FIELDS_COUNT;offset+=FIELDS_LENGTH[i++])
{
// Если смещение в строке меньше ее длины
if(offset<str.length())
{
result[i]=trim(str.substr(offset,FIELDS_LENGTH[i]));
}
else
{
return false;
}
}
return true;
}
// Конвертирует строку в действительное float
float convertToFloat(const String& str)
{
float result=static_cast<float>(atof(str.c_str()));
if(errno==EINVAL)
{
throw std::invalid_argument("float convertToFloat(const stringT& str):Невозможно преобразовать строку в число");
}
return result;
}
// Конвертирует строку в целое int
int convertToInt(const String& str)
{
int result=atoi(str.c_str());
if(errno==EINVAL)
{
throw std::invalid_argument("int convertToInt(const stringT& str):Невозможно преобразовать строку в число");
}
return result;
}
// Конвертирует строку в BoxSize
BoxSize convertToSize(const String& str)
{
// Регулярное выражение для проверки формата данных
static const std::tr1::basic_regex<CharType> rx("(.+)[xX](.+)[xX](.+)");
std::tr1::match_results<String::const_iterator> mr;
if(!std::tr1::regex_search(str,mr,rx))
{
throw std::invalid_argument("noteT::noteSizeT convertToSize(const stringT&): Входные данные имеют не верный формат");
}
return BoxSize(convertToFloat(mr[1].str()),convertToFloat(mr[2].str()),convertToFloat(mr[3].str()));
}
Container readHDDLess1Gb(InFile& file)
{
Container result;
String str;
size_t countStr=0;
std::getline(file,str);
while(file)
{
++countStr;
str=expandTabs(str);
Fields fields;
if(parseNoteString(str,fields))
{
try
{
if(convertToFloat(fields[HDD_SIZE_INDEX])<1)
{
result.put(Notebook(
fields[MODEL_INDEX].c_str(),
convertToSize(fields[SIZE_INDEX]),
convertToFloat(fields[WEIGHT_INDEX]),
convertToInt(fields[PRICE_INDEX])));
}
}
catch(std::invalid_argument&)
{
std::cerr<<"Ошибка во входных данных"<<std::endl;
throw;
}
}
std::getline(file,str);
}
return result;
}
#pragma region BoxSize
BoxSize::BoxSize(float x/*=0*/,float y/*=0*/,float z/*=0*/)
:_x(x)
,_y(y)
,_z(z)
{}
float BoxSize::x() const
{
return _x;
}
float BoxSize::y() const
{
return _y;
}
float BoxSize::z() const
{
return _z;
}
#pragma endregion BoxSize
#pragma region Notebook
Notebook::Notebook(const char* const model,BoxSize size,float weight,int price)
:_size(size)
,_weight(weight)
,_price(price)
{
if(model)
{
strcpy_s(_model,model);
}
else
{
memset(_model,0,MODEL_LEN+1);
}
}
const char* const Notebook::model() const
{
return _model;
}
BoxSize Notebook::size() const
{
return _size;
}
float Notebook::weight() const
{
return _weight;
}
int Notebook::price() const
{
return _price;
}
bool Notebook::write(OutFile& file) const
{
if(file)
{
// Запись в файл
file.write(reinterpret_cast<const CharType*>(this),sizeof(*this));
return !file.fail();
}
else
{
return false;
}
}
#pragma endregion Notebook
#pragma region Container
void Container::put(const Notebook& note)
{
push_back(note);
}
Notebook Container::get()
{
Notebook note=this->front();
pop_front();
return note;
}
void Container::sort(bool (*pred)(const Notebook&,const Notebook&))
{
// STL - списки не поддерживают сортировку. Поэтому реализуем сами подобие пузырьковой
for(iterator it1=begin();it1!=end();++it1)
{
iterator it2=it1;
for(++it2;it2!=end();++it2)
{
if(!pred(*it1,*it2))
{
std::swap(*it1,*it2);
}
}
}
}
#pragma endregion Container
Выводим данные о ноутбуках с объемом HDD менее 1Gb
AST Ascentia P50 4499 7.5 2.3x11.3x9
Acer Note Light 2699 5.6 2x11.8x8.3
BSI NP8657D 2605 8 2.3x11.8x9.3
Dell Xpi P100SD 3459 6 2.3x11x8.8
Gateway Solo S5 4499 5.6 2x11.9x8.8
IBM ThinkPad 560 3749 4.1 1.3x11.8x8.8
NEC Versa 4080H 4780 6 2.3x11.8x9.5
Samsung SENS 810 3667 8.7 2.3x11.5x9.5
Twinhead Slimnote 2965 7.4 2x11.5x8
Если Вы уже зарегистрированы на Портале - войдите в систему, если Вы еще не регистрировались - пройдите простую процедуру регистрации.