1 Востаннє редагувалося Logans (02.01.2014 22:55:50)

Тема: Зчитування з файлу

Вітаю всіх з Новим Роком :)

Власне назва теми це узагальнена тема питання. Питання стоїть трохи інше:
Як можна зчитувати з текстового файлу по декілька слів?

Власне потрібно зчитуванні слова формувати в шингли (послідовність слів).

Приклад шинглів:

▼Даний текст
Астероїди або малі планети, здебільшого обертаються між орбітами Марса 
і Юпітера й невидимі неозброєним оком.

Текст оброблюється (видаляються всі символи, та літери приводяться до нижнього регістру)

▼Текст поділений на шингли
астероїди або малі
або малі планети
малі планети здебільшого
планети здебільшого обертаються
здебільшого обертаються між 
між орбітами марса
орбітами марса і
марса і юпітера
юпітера й невидимі
й невидимі неозброєним
невидимі неозброєним оком

1. Є такий варіант: використати два цикла

  • перший, для зчитування доки не кінець файлу

  • другий, для посимвольної перевірки на наявність пробілу

Але такий варінт досить не ефективний при роботі з великими текстами.

2. Є інший варіант (яким я користувався):

  • зчитати весь текст у одну змінну

  • знаходити на кожній ітерації пробіли і вирізати слова формуючи їх в шингли

Також не влаштовує, тому що програмі потрібно буде зчитувати 2 тексти, обробити тексти, розбити на шигли і потім їх перевіряти між собою, що призведе до дуже довгої роботи.

Ось код працюючої програми (з використанням 2-го варіанту):

▼Прихований текст
#include <iostream>
#include <string>
#include <locale>
#include <fstream>

using namespace std;

// Приведення до нижнього регістру
string toLow(string inputText)
{
    for (int i = 0; i < inputText.length(); i++)
        inputText[i] = tolower(inputText[i]);
    return inputText;
}

// Видалення зайвих символів
string delSymbols(string inputText)
{
    for (int i = 0; i < inputText.length(); i++)
        if ((isalpha(inputText[i]) == false) && (inputText[i] != ' '))
        {
            inputText = inputText.erase(i, 1);
            i--;
        }
    return toLow(inputText);
}

// Видалення зайвих пропусків
string delSpace(string inputText)
{
    for (int i = 0; i < inputText.length(); i++)
        if (inputText[i] == ' ')
        {
            int j;
            j = i + 1;
            while (inputText[j] == ' ')
                inputText.erase(j, 1);
        }
    return delSymbols(inputText);
}

int main()
{
    string stringText, textString;    
    
    ifstream fileUse("TextFile__.txt");

    while (!fileUse.eof())
    {
        getline(fileUse, textString);
        stringText += textString;
    }

    fileUse.close();
    

    //getline(cin, stringText);
    stringText = delSpace(stringText);
    
    // Розбиття тексту на шигли
    const int n = 250;
    string str[n], strWork_01, strWork_02;

    int wordCount = 0;
    int firstSpace, lastSpace, secondSpace;

    stringText += " ";
    strWork_01 = stringText;
    strWork_02 = stringText;
    
    for(int i = 0; i < stringText.length(); i++)
    {
        firstSpace = strWork_01.find(" ");
        if (firstSpace != -1)
        {
            strWork_01.erase(0, firstSpace + 1);
            wordCount++;
        }
        else
            break;
    }

    strWork_01 = stringText;
    
    for(int i = 0; i < wordCount - 2; i++)
    {
        firstSpace = strWork_02.find(" ");
        strWork_02.erase(0, firstSpace + 1);
        secondSpace = firstSpace + strWork_02.find(" ");
        strWork_02.erase(0, secondSpace - firstSpace + 1);
        lastSpace = secondSpace + strWork_02.find(" ");
        secondSpace += 1;
        lastSpace += 2;
        str[i] = strWork_01.substr(0, lastSpace);
        strWork_01.erase(0, firstSpace + 1);
        strWork_02 = strWork_01;
        cout << str[i] << endl;
    }
    
    cout << endl;    
    system("pause");
    return 0;
}

Ось текстовий файл з яким працює програма:

Post's attachments

TextFile__.txt 1.43 kb, 938 downloads since 2014-01-02 

Подякували: Chemist-i1

2

Re: Зчитування з файлу

Почитайте про istringstream (є гарні приклади, у т.ч. - на StackOverflow).

Як варіант економії нервів - зчитати через istringstream всі слова до списку/вектора/абощо, а потім обробляти згідно власного фен-шуя. :)

З.І: власне, якщо потрібно саме одразу і потроху - то от:

istringstream ss( myRowOrMyText);

string word1, word2, word3;
ss >> word1 >> word2 >> word3;

3

Re: Зчитування з файлу

Дякую за допомогу з першою частиною питання, але як бути з наступною? Яким чином можна зробити, щоб кожен раз зчитувало наступне слово. Зараз в мене працює так:

▼Прихований текст

Текст

Астероїди або малі планети, здебільшого обертаються між орбітами Марса 
і Юпітера й невидимі неозброєним оком.

Розбиття

астероїди або малі
астероїди або малі
астероїди або малі
астероїди або малі
і так до кінця змінної тексту
▼Ось частина програми
    string firstWord, secondWord, thirtWord;
    string shingle[250];

    for (int i = 0; i < stringText.length(); i++)
    {
        istringstream searchWord(stringText);
        searchWord >> firstWord >> secondWord >> thirtWord;
        shingle[i] = firstWord + " " + secondWord + " " + thirtWord + " ";
        cout << shingle[i] << endl;
    }

4

Re: Зчитування з файлу

Якщо я правильно зрозумів, алгоритм шинглів використовується для порівняння тексту з певною бібліотекою, і цю бібліотеку зчитати в пам'ять неможливо (вона завелика за визначенням), тому треба оптимізувати роботу з нею. Як саме? Хешуванням і сортуванням. Тобто:
1. Придумуєте хеш-функцію. Скажімо, сумуєте коди всіх символів рядку, після додавання кожного коду циклічно зсуваєте суму праворуч. Або ще якось - аби результат був досить випадковим. До речі, можна скористатися ГПВЧ - ініціалізуючи його, знову ж таки, кодами символів рядку. Головне - рядок перетворюється на число.
2. Створюєте бібліотеку хешів - скажімо структурами з хешу, коду файла і позиції шингла в файлі.
3. Сортуєте цю бібліотеку (чи робите індекс, неважливо, для початківця легше сортувати). Або навіть розміщуєте в хеш-таблиці, тоді хеш зберігати не треба, але знову ж, не для початківця.
4. Зчитуєте з файла для перевірки по слову, обчислюєте хеш поточного шингла, шукаєте його бінарним пошуком (якщо сортували) чи прямо запитуєте (якщо робили хеш-таблицю) в бібліотеці. Якщо такий хеш знайдено - перевіряєте, чи це не колізія (два однакових хеші в різних шинглів) безпосередньо в файлі (у нас є позиція, не забувайте!)

Десь так...

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

5 Востаннє редагувалося koala (03.01.2014 00:06:53)

Re: Зчитування з файлу

А, то проблема просто в зчитуванні?

▼Прихований текст
#include <iostream>
#include <list>
#include <string>
#include <sstream>
using namespace std;

int main() {
  list< string > words;
  stringstream input( "Астероїди або малі планети, здебільшого обертаються між орбітами Марса \
і Юпітера й невидимі неозброєним оком." );
  string cur;
  while( input >> cur )
  {
    words.push_back( cur );
    if( words.size() > 3 ) words.pop_front();
    if( words.size() == 3 )
    {
      string shingle;
      for( list< string >::iterator s = words.begin(); s != words.end(); s++ )
        shingle += *s + " ";
      cout << shingle << endl;
    }
  }
  return 0;
}

list тут - оптимальний контейнер, але цілком можливо скористатися чимось іншим (навіть самописним), аби лиш можна було додавати в кінець і видаляти з початку.

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