1

Тема: С++ Vector::insert

Панове, є така проблема:
У мене некоректно працює код для ось цього завдання:
переставити фрагмент тексту (декілька абзаців)
( запитує номер першого абзацу і номер останнього абзацу фрагменту, що переставляється
( запитує номер абзацу, після якого цей фрагмент вставити
( тоді вилучає фрагмент зі старого місця та вставляє у нове

Якщо я вводжу такі от цифри
номер першого абзацу : 2
номер останнього абзацу : 4
після якого абзацу вставити : 5

то результат вийде такий:
1. 1
2. 5
3. пусто
4. пусто
5. пусто
6. 6
7. 7
Ось код методу :

    void replaceParagraphs()
    {
        int indexFirst;
        int indexLast;
        int indexPut;
        if (myText.size() >= 2)
        {
            do
            {
                cout << "Enter the number of the first paragraph of a range : ";
                cin >> indexFirst;
                indexFirst--;
                //cout << myText[indexFirst] << endl;
                cout << "Enter the number of the last paragraph of a range : ";
                cin >> indexLast;
                indexLast--;
                //cout << myText[indexLast] << endl;
                cout << "Enter the number of paragraph after wich the range should be put :";
                cin >> indexPut;
                indexPut--;
                //cout << myText[indexPut] << endl;
                //system("pause");
                if (indexPut >= indexFirst && indexPut <= indexLast)
                {
                    throw "The range cannot be inserted inside itself!";
                }
            } while (indexFirst < 0 && indexFirst > myText.size() && indexLast < 0 && indexLast > myText.size() - 1);
            if (indexFirst > indexLast)
            {
                swap(indexFirst, indexLast);
            }
            vector<string>::const_iterator iter = myText.begin() + (indexPut + 1);
            if (iter < myText.begin() || iter > myText.end())
            {
                throw "Invalid PUT index. Put index is out of range";
            }
            myText.insert(iter, myText.begin() + indexFirst, myText.begin() + (indexLast + 1));
            //this->showText(0);
            //system("pause");
            if (indexPut >= indexLast)
            {
                myText.erase((myText.begin() + indexFirst), (myText.begin() + (indexLast + 1)));
            }
            else if (indexPut < indexFirst)
            {
                myText.erase(myText.begin() + (indexFirst + (indexLast - indexFirst + 1)), myText.begin() + (indexLast + (indexLast - indexFirst + 2)));
            }
        }
        else
        {
            throw "Too few elements in the vector to manipulate them!";
        }
    }

Ось код всієї програми + прикріпив файлик, щоб зчитати:

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <fstream>
#include <windows.h>
#include <string>
#include <algorithm>
#include <vector>
#include <iomanip>
#include <locale>

using namespace std;

class Editor
{
private:
    vector<string> myText;
    fstream myTextEditor;
    string file_name;
public:
    Editor()
    {
        myText = {};
        file_name = "NewFile.txt";
    };


    void createFile()
    {

        string fileName;
        cout << "Type in file name : ";
        cin.ignore();
        getline(cin, fileName);

        /*cout << "Type in directory where to create the file : ";
        string dir;
        getline(cin, dir);
        string path = dir + fileName;*/
        ofstream someFile;
        someFile.open(fileName, ios_base::out);
        someFile.close();
    }

    /*+ відкрити існуючий файл
    ( запитує ім'я файлу)*/

    void openFile()
    {
        string fileName;
        cout << "Type in name of the file to oopen :";
        cin.ignore();
        getline(cin, fileName);
        ifstream readFile;
        readFile.open(fileName, ios_base::in);
        if (!readFile.is_open())
        {
            throw 1;
        }
        else
        {
            string readText;
            while (!readFile.eof())
            {
                getline(readFile, readText);
                myText.push_back(readText);
            }
        }
        readFile.close();
    }

    /*зберегти текст у файл
    ( запитує ім'я файлу і зберігає текст у цей файл*/
    void saveText()
    {
        string fileName;
        cout << "Enter file name to save text :";
        cin.ignore();
        getline(cin, fileName);
        ofstream writeFile;
        writeFile.open(fileName, ios_base::out);
        if (!writeFile.is_open())
        {
            throw 2;
        }
        else
        {
            vector<string>::iterator iter = myText.begin();
            for (; iter != myText.end() - 1; ++iter)
            {
                writeFile << *iter << endl;
            }
            writeFile << *iter;
            writeFile.close();
        }
    }

    void addParagraph()
    {
        string paragraph;
        cout << "Enter new paragraph : " << endl
            << "**********" << endl;
        cin.ignore();
        getline(cin, paragraph);
        myText.push_back(paragraph);
        cout << endl << "New paragraph added!" << endl << endl;
    }

    /*+ редагувати абзац
    ( запитує номер абзацу і замінює його вміст введеним з клавіатури текстом*/
    void editParagraph()
    {
        int index;
        string newParag;
        do
        {
            cout << "Enter number of paragraph to edit : ";
            cin >> index;
        } while (index - 1 < 0 && index - 1 > myText.size());
        cout << "Type in new text of the paragraph :" << endl;
        cin.ignore();
        getline(cin, newParag);
        myText.insert(myText.begin() + (index - 1), newParag);
        myText.erase(myText.begin() + index);
    }

    void clearVector()
    {
        char choice;
        do
        {
            cout << "Are you sure you want to clear the vector? y/n : ";
            cin >> choice;
        } while (choice != 'y' && choice != 'n');

        if (choice == 'y')
        {
            myText.clear();
            cout << "Vector is empty!" << endl;
        }
        else
        {
            cout << "Canceled" << endl;
        }
        system("pause");
    }

    /*+ показати текст
    ( поекранно виводить понумерований список абзаців
    (    ( абзац -- це текст, що завершується символом нового рядка '\n'
    (     ( поекранно -- означає, що після виводу на екран 24 рядків (не абзаців) запитує ( Continue (y/n) ? )*/
    void showText(int index)
    {
        char choice;
        cout << "Vector capasity = " << myText.capacity() << endl;
        cout << "Vector size = " << myText.size() << endl;
        for (int i = index; i < myText.size(); ++i)
        {
            if (i == (index + 7))
            {
                do
                {
                    cout << setw(20) << right << "Continue (y/n) ? : ";
                    cin >> choice;
                } while (choice != 'y' && choice != 'n');
                switch (choice)
                {
                case 'y':
                {
                    showText(i);
                    return;
                }
                case 'n': return;
                default:
                    break;
                }
            }
            cout << i + 1 << ", " << myText[i] << endl;
        }
        system("pause");
    }

    /*+ переставити фрагмент тексту (декілька абзаців)
    ( запитує номер першого абзацу і номер останнього абзацу фрагменту, що переставляється
    ( запитує номер абзацу, після якого цей фрагмент вставити
    ( тоді вилучає фрагмент зі старого місця та вставляє у нове*/

    void replaceParagraphs()
    {
        int indexFirst;
        int indexLast;
        int indexPut;
        if (myText.size() >= 2)
        {
            do
            {
                cout << "Enter the number of the first paragraph of a range : ";
                cin >> indexFirst;
                indexFirst--;
                //cout << myText[indexFirst] << endl;
                cout << "Enter the number of the last paragraph of a range : ";
                cin >> indexLast;
                indexLast--;
                //cout << myText[indexLast] << endl;
                cout << "Enter the number of paragraph after wich the range should be put :";
                cin >> indexPut;
                indexPut--;
                //cout << myText[indexPut] << endl;
                //system("pause");
                if (indexPut >= indexFirst && indexPut <= indexLast)
                {
                    throw "The range cannot be inserted inside itself!";
                }
            } while (indexFirst < 0 && indexFirst > myText.size() && indexLast < 0 && indexLast > myText.size() - 1);
            if (indexFirst > indexLast)
            {
                swap(indexFirst, indexLast);
            }
            vector<string>::const_iterator iter = myText.begin() + (indexPut + 1);
            if (iter < myText.begin() || iter > myText.end())
            {
                throw "Invalid PUT index. Put index is out of range";
            }
            myText.insert(iter, myText.begin() + indexFirst, myText.begin() + (indexLast + 1));
            //this->showText(0);
            //system("pause");
            if (indexPut >= indexLast)
            {
                myText.erase((myText.begin() + indexFirst), (myText.begin() + (indexLast + 1)));
            }
            else if (indexPut < indexFirst)
            {
                myText.erase(myText.begin() + (indexFirst + (indexLast - indexFirst + 1)), myText.begin() + (indexLast + (indexLast - indexFirst + 2)));
            }
        }
        else
        {
            throw "Too few elements in the vector to manipulate them!";
        }
    }

    /*+ знайти і замінити
    ( запитує зразок для пошуку
    ( запитує текст для заміни
    ( замінює усі входження зразка в усіх абзацах тексту*/

    void replaceText()
    {
        string search;
        string replace;
        cin.ignore();
        cout << "Type in text to find : ";
        getline(cin, search);
        cout << "Type in text to replace with : ";
        getline(cin, replace);
        for (int i = 0; i < myText.size(); ++i)
        {
            int k = myText[i].find(search);
            if (k >= 0)
            {
                myText[i].replace(k, search.length(), replace);
            }
        }
        cout << search << " was successfully replaced by " << replace << endl << endl;
        system("pause");
    }

    ~Editor();
};

void main()
{
    Editor *firstEditor = new Editor;
    int choice = 0;
    enum Menu
    {
        exit, create_file, open_file, save_file, clear_file, show_text, edit_paragraph, add_paragraph, replace_paragraphs, replace_text
    };
    do
    {
        do
        {
            system("cls");
            cout << "******************************" << endl
                << setw(17) << "MENU" << endl
                << "******************************" << endl
                << Menu::create_file << ". Create new file" << endl
                << "*****" << endl
                << Menu::open_file << ". Open file and read its content to vector" << endl
                << "*****" << endl
                << Menu::save_file << ". Save text to file" << endl
                << "*****" << endl
                << Menu::clear_file << ". Delete all text" << endl //зробив
                << "*****" << endl
                << Menu::show_text << ". Show the entire text" << endl //зробив
                << "*****" << endl
                << Menu::edit_paragraph << ". Edit single chosen paragraph" << endl
                << "*****" << endl
                << Menu::add_paragraph << ". Add new paragraph" << endl //зробив
                << "*****" << endl
                << Menu::replace_paragraphs << ". Replace range og Paragraphs" << endl
                << "*****" << endl
                << Menu::replace_text << ". Replace word/s in the text" << endl
                << "*****" << endl
                << "*****" << endl
                << Menu::exit << ". Exit" << endl << endl
                << "Make a choice : ";
            cin >> choice;
        } while (choice < Menu::exit && choice > Menu::replace_text);
        switch (choice)
        {
        case Menu::create_file:
        {
            firstEditor->createFile();
            break;
        }
        case Menu::open_file:
        {
            try
            {
                firstEditor->openFile();
            }
            catch (int i)
            {
                cerr << "Error " << i << " : Cannot open file for reading. Exiting...." << endl;
                system("pause");
            }
            break;
        }
        case Menu::save_file:
        {
            try
            {
                firstEditor->saveText();
            }
            catch (int m)
            {
                cerr << "Error " << m << " : Can't open file for writing. Exiting..." << endl;
                system("pause");
            }
            break;
        }
        case Menu::clear_file:
        {
            firstEditor->clearVector();
            break;
        }
        case Menu::show_text:
        {
            firstEditor->showText(0);
            break;
        }
        case Menu::edit_paragraph:
        {
            firstEditor->editParagraph();
            break;
        }
        case Menu::add_paragraph:
        {
            firstEditor->addParagraph();
            break;
        }
        case Menu::replace_paragraphs:
        {
            try
            {
                firstEditor->replaceParagraphs();
            }
            catch (string s)
            {
                cerr << "Replacing paragraphs error : " << s;
                system("pause");
            }
            break;
        }
        case Menu::replace_text:
        {
            firstEditor->replaceText();
            break;
        }
        case Menu::exit:
        {
            cout << "See you!!!" << endl;
            break;
        }
        default:
            break;
        }
    } while (choice != Menu::exit);
    system("pause");
}
Post's attachments

bla.txt 40 b, 247 downloads since 2017-01-30 

2

Re: С++ Vector::insert

Для вашій задачі некоректно використовувати вектор. Це якраз приклад того, як робити взагалі не треба ніколи.
Використовуйте std::list якщо хочется як найпростіше, або std::map для звернення за номером. Для реалізації параграфа треба створити клас. Навіть якщо ви зупинитесь на std:vector.
Це перше. По друге - ламати очі в лапші коду насправді нікому не впало. Тим більше що за такий код треба вбивати у дитинстві.
Відкрийте для себе дебагер  та користуйтеся їм.
Трете - якщо метод реалізовано більше ніж 10 строчок коду - це майже завжди груба помилка. Також треба дотримуватися принцип  - один метод, одна дія. Не припустимо у одному методі одночасно читати індекси, шукати параграфи, заміняти їх - це також помилка.

3

Re: С++ Vector::insert

Чудова допомога: обісрав, покритикував, сказав, що влом читати код і нічим не допоміг. Навіщо взагалі відписували? Я так теж можу.

4

Re: С++ Vector::insert

Не обісрав, а дав корисні поради. Якщо ви "теж так можете", то виправіть те, що він сказав.
Стосовно ж вашої проблеми - то ітератори погано реагують на зміну контексту ітерації, такого краще не робити. Переносьте рядки в інший вектор, а потім назад... чи дійсно використовуйте list, він тут доцільніший.
Конкретно тут рядки зсуваються до фактичного копіювання, а потім копіюється пусте місце.

Подякували: boshik19831

5

Re: С++ Vector::insert

ітератори погано реагують на зміну контексту ітерації, такого краще не робити.

Що мене і цікавило.
Ми зараз вчимо вектори і нам поставили ось таку задачу. Як задачу поставили так я її і виконую. Стикнувся з проблемою і написав на форум, бо сподівався зрозуміти в чому причина проблеми (бо код працює якось вибірково - то він все переставляє без проблем, то забуває перенести значення).
Можна ще 2 питання:
1.

ітератори погано реагують на зміну контексту ітерації

. Це стосується переставляння вмісту вектора в самому собі чи при вставлянні з іншого вектора теж може виникнути подібна ситуація?
2. Можна якось створити файл не відкриваючи потік? Не використовуючи такий метод:

ofstream someFile;
        someFile.open(fileName, ios_base::out);
        someFile.close();

а якось просто створити файл? Я гуглив, прошу туди не відправляти.

6

Re: С++ Vector::insert

1. Очевидно, що в самому собі. Зі вставленням із деінде все добре, проблема виникає, коли контекст ітератора (той об'єкт, по якому іде ітератор) змінюється іншими засобами (зокрема, іншими ітераторами).
2. А нащо? Можете ще fopen-ом, але там те саме буде. Можна ще проголошувати і створювати в одному рядку.

7

Re: С++ Vector::insert

А нащо?

Просто я подумав, що я роблю зайві маніпуляції: відкриваю потік, створюю файл, закриваю потік. І завася питанням чи не можна викинути операції з потоком з цього ланцюга. Одне діло якщо ми відкриваємо файл для вводу/виводу. А коли нам треба просто створити пустий файл (як би це безглуздо не було).

Можна ще проголошувати і створювати в одному рядку.

не зрозумів... а так:
ofstream someFile.open(fileName, ios_base::out);?

8 Востаннє редагувалося koala (31.01.2017 13:59:31)

Re: С++ Vector::insert

boshik1983 написав:

А нащо?

Просто я подумав, що я роблю зайві маніпуляції: відкриваю потік, створюю файл, закриваю потік. І завася питанням чи не можна викинути операції з потоком з цього ланцюга. Одне діло якщо ми відкриваємо файл для вводу/виводу. А коли нам треба просто створити пустий файл (як би це безглуздо не було).

Стандарт такого не передбачає. Можливо, у вашій ОС таке і можливо - пошукайте по її API.

boshik1983 написав:

Можна ще проголошувати і створювати в одному рядку.

не зрозумів... а так:
ofstream someFile.open(fileName, ios_base::out);?

Ні, це не спрацює. Можна навіть так:

ofstream(fileName);

Другий параметр можна опустити, бо це ofstream. Об'єкт буде створено, при цьому параметр передасться в open (дивіться параметри конструктора), після чого знищено (і закрито). Але тоді відкоментуйте, бо це неочевидно.

Подякували: boshik19831

9

Re: С++ Vector::insert

Тема закрита. Коалі дякую!