Laboratoria nr 16 program nr 1

Poniżej przedstawiam zrefaktoryzwoany, przedstawiony wcześniej szkielet kodu aplikacji do przetwarzania tekstów (Labolatorium nr 15) . Aktualnie zaprezentowane zostały tematy związane z takimi zagadnieniami jak:

– biblioteka boost i wykorzystanie inteligentnych wskaźników (rozwiązanie problemów z ewentualnymi wyciekami pamięci np. przy wywoływaniu wyjątków),

– biblioteka standardowa STL,

– modyfikator const.

W miarę czasu postaram przedstawić zagadnienia związane z tampletami (ang. tamplates) stosowanymi do programowania ogólnego oraz wykorzystanie wyrażeń regularnych w budowaniu macierzy wyrażeń (ang. term matrix). Dobre wprowadzenie do biblioteki boost i wyrażeń regularnych zawiera Przemoc’s wiki. W dalszej kolejności planowane jest też pokazanie sposobów testowania kodu (ang. test unity) zamiast stosowania testów wewnątrz funkcji main().

Na koniec, a może nawet w następnym poście dotyczącym C/C++, chciałbym przedstawić zagadnienie związane z łączeniem PHP z C++. Maszyna zenda jest dość ciężka do opanowania (wiele pośrednich makr, dokumentacji etc.). Opanowanie jej zajmuje trochę czasu. Powstało jednakże bardziej elastyczne narzędzie w postaci SWIG w którym na pierwszy rzut oka zadanie to wydaje się o wiele elastyczniejsze i łatwiejsze niż poprzez hackowanie bezpośrednio zenda. Z rozwiązaniem tym pierwszy raz spotkałem się w Linux Magazine (artykuł pt. “PHP z C++”) a następnie na blogu IBMa  Build PHP extensions with SWIG, gdzie Martin Streicherwyjaśnia w bardzo przystępny sposób jak pisać rozszerzenia używając C/C++ do PHP.

Kod zrefaktoryzwoanej aplikacji wykorzystujący utworzone interfejsy przedstawia listing poniżej:

//============================================================================
// Name        : agencyText.cpp
// Author      : Marcin Mirończuk
// Version     : 1.0
// Copyright   : GPL
// Description : The agency to text retrive
//============================================================================

/**
 * Rejestracja bibliotek
 */
#include <iostream>
#include <string>
#include <vector>
#include "textAgent.h"

#include "boost/scoped_ptr.hpp"

/**
 * Rejestracja przestrzeni nazw
 */
using namespace std;
using namespace ta;
using namespace boost;

/**
 * Definicja typów
 * Wstep do tworzenia szablonow @see http://pl.wikibooks.org/wiki/C++/Szablony_klas
 */
typedef ta::textAgent agentInt;

/**
 * Program glowny
 */
int main(int argc, char** argv) {

	/**
	 * Wystartowanie kilku agentow dynamicznych oraz statycznych, nazwanych jak i nienazwanych (anonimowych)
         * Zastosowanie inteligentnych wskaznikow z biblioteki boost do zarzadzania czasem zycia obiektow
	 */
	agentInt agentStatyczny(1220, 1, "przetwarzacz tekstu 1", "Agent T1");
	agentInt niezweryfikowanyAgentStatyczny;

	boost::scoped_ptr<agentInt> agentDynamiczny(new agentInt(12330, 2, "przetwarzacz tekstu 2", "Agnet T2"));
	boost::scoped_ptr<agentInt> niezweryfikowanyAgentDynamiczny(new agentInt());

	try {

		/**
		 * Pokazanie informacji o rezydujacych agentach
		 */
		cout << "Zarejestrowany agent i jego dane:" << endl;
		agentStatyczny.showData();

		cout << endl;

		cout << "Agent oczekujacy na rejestracje:" << endl;
		niezweryfikowanyAgentStatyczny.showData();

		cout << endl;

		cout << "Agent dynamiczny zarejstrowany:" << endl;
		agentDynamiczny->showData();

		cout << endl;

		cout << "Agent dynamiczny niezweryfikowany:" << endl;
		niezweryfikowanyAgentDynamiczny->showData();

		cout << endl;

		/**
		 * Rejestracja modulu (przybornika) do przetwarzania tekstow
                 * Dodatkowe testy przybornika
		 */
		tt::textTool tt;
                tt::textTool ttTest;
                
                cout << "Testowanie tollboksa do przetwarzania tekstu: " << endl;

                ttTest.extractSegments("A ja mam kota. I wiecej tekstu.");
                ttTest.showSegments();
                
                cout << endl;
                
		/**
		 * Rejestracja przybornika dla agenta dynamicznego
		 */
		agentDynamiczny->rejestrTextTool(tt);
		agentDynamiczny->rejestrTextTool().extractSegments("Ala ma kota.");

		cout << "Ilosc zliczonych segmentow: " <<  agentDynamiczny->rejestrTextTool().getCountSegments() << endl;
		cout << "Pokaz jakie segmenty zliczyles: " << endl;
		agentDynamiczny->rejestrTextTool().showSegments();

		cout << endl;

		/**
		 * Rejestracja przybornika dla agenta statycznego
		 */
                agentStatyczny.rejestrTextTool(tt);
		agentStatyczny.rejestrTextTool().extractSegments("A ja mam kota. I wiecej tekstu.");
                               	
                cout << "Ilosc zliczonych segmentow: " << agentStatyczny.rejestrTextTool().getCountSegments() << endl;
		cout << "Pokaz jakie segmenty zliczyles: " << endl;
		agentStatyczny.rejestrTextTool().showSegments();

		cout << endl;

		cout << "Testowanie usowania spacji:" << endl;

		std::string testString1 = " kota ";
		cout << "- Tekst przed filtracja: " << testString1 << endl;
		cout << "- Filtracja: " << "Tekst odfiltrowany: " << agentStatyczny.rejestrTextTool().stripWhiteSpace(testString1) << endl;
		cout << "- Filtracja: " << "Tekst pierwotny " << testString1 << endl;

		std::string *pTestString1 = &testString1;
		cout << "- Tekst przed filtracja wskaznik / zmienna: " << *pTestString1 << " / " << testString1 << endl;
		agentStatyczny.rejestrTextTool().stripWhiteSpace(pTestString1);
		cout << "- Filtracja: " << "Tekst odfiltrowany " << *pTestString1 << endl;
		cout << "- Filtracja: " << "Tekst pierwotny " << testString1 << endl;

		cout << endl;

		cout << "Testowanie tokenizacji:" << endl;
		std::string testString2 = "Ala ma kota. A kot ma na imie Ala.";
		cout << "- Tekst podlegajacy tokenizacji: " << testString2 << endl;
		agentStatyczny.rejestrTextTool().tokenize(testString2);
		cout << "- Ilosc tokenow: " <<  agentStatyczny.rejestrTextTool().getCountTokens() << endl;
		cout << "- Ilosc unikatowych tokenow: " <<  agentStatyczny.rejestrTextTool().getCountUniqueTokens();

                cout << endl;
                
                niezweryfikowanyAgentDynamiczny->rejestrTextTool();
                
	} catch (std::string exception) {
                cout << endl;
		cout<<"Wyjatek: "<< exception;
	}

	return 0;
}

Interfejs agenta który rejestruje moduł do przetwarzania tekstu i za pośrednictwem którego odbywają się wszelkie modyfikacja przedstawia listing poniżej:

/*
 * textAgent.h
 *
 *  Created on: 21-12-2011
 *  Author: Marcin Mirończuk
 *  Licenc: GPL
 *
 *  Klas modelujaca podstawowe elementy agenta do przetwarzania tekstu.
 *  Agent ma mozliwosc rejestrowania u siebie modulu do przetwarzania tekstu za omoca ktorego przetwarza tekst.
 *
 * @note::
 * + Metody [nazwaMetody]get() const nie zmieniaja stanu obiektow na zecz ktorych sa wywolywane.
 *   (pola tylko do odczytu)
 * + Czesc metod [nazwaMetody]get() moze byc wywolana inline 
 *  
 */

#include <string>
#include "textTool.h"

#ifndef TA_H_
#define TA_H_

/**
 * Definicja przestrzeni nazw
 */
namespace ta {

	/**
	 *  Definicja klasy
	 */
	class textAgent {

		/**
		 * Skladowe i metody prywatne klasy
		 */
		private:

			/**
			 * @type int timeCreate Czas w sekundach  Unix timestamp
			 */
			int timeCreate;

			/**
			 * @type float priority Priorytet agebta
			 */
			int priority;

			/**
			 * @type string task Zadanie/praca do wykonania przez agebta
			 */
			std::string task;

			/**
			 * @type string name Nazwa agenta
			 */
			std::string name;

			/**
			 * @type bool isTextTool Flaga rejestracji modulu tekstu
			 */
			bool isTextTool;

			/**
			 * @type textTool textTool Uchwyt do modulu przetwarzajacego tekst
			 */
			tt::textTool textTool;

		/**
		 * Skladowe i metody publiczne klasy
		 */
		public:

			/**
			 * Konstruktor podstawowy domyslny
			 */
			textAgent();

			/**
			 * Konstruktor rozszerzony
			 */
			textAgent(int ptimeCreate, int ppriority, std::string ptask, std::string pname);

			/**
			 * Pobranie wieku agenta
			 *
			 * @return float
			 */
			int getTimeCreate() const;

			/**
			 * Pobranie wagi agenta
			 *
			 * @return float
			 */
			int getPriority() const;

			/**
			 * Pobranie zadania agenta
			 *
			 * @return string
			 */
			std::string getTask() const;

			/*
			 * Pobranie nazwy agenta
			 *
			 * @return string
			 */
			std::string getName() const;

			/**
			 * Pokazanie danych o agencie
			 *
			 * @return void
			 */
			void showData() const;

			/**
			 * Rejestracja modulu do przetwarzania tekstu
			 *
			 * @return tt::textTool
			 */
			const tt::textTool & rejestrTextTool(tt::textTool tt);

			/**
			 * Rejestracja, pobranie modulu do przetwarzania tekstu.
			 * 
			 * @return tt::textTool
			 * @thorw exception
			 */
			tt::textTool & rejestrTextTool() throw(std::string);

                        /**
                         * @see ta::textAgent::rejestrTextTool()
                         * 
			 * @return tt::textTool
			 * @thorw exception
                         */
                        tt::textTool & getTextTool();
                        
			/**
			 * Destruktor
			 */
			virtual ~textAgent();
	};

} /* namespace textagent */
#endif /* TA_H_ */

Interfejs programu (modułu) do przetwarzania strumienia danych tekstowych przedstawia listing poniżej:

/*
 * textAgent.cpp
 *
 *  Created on: 21-12-2011
 *  Author: Marcin Mirończuk
 *  Licenc: GPL
 *
 *  Implementacja interfejsu agenta do przetwarzania tekstu @see textAgent.h
 *
 */

#include <iostream>
#include "textAgent.h"
#include "textTool.h"

namespace ta {

	textAgent::textAgent() {
		this->timeCreate = 0;
		this->priority = 0;
		this->task = "unknown";
		this->name = "inkognito";

		this->isTextTool = false;
	}
        
	textAgent::textAgent(int ptimeCreate, int ppriority, std::string ptask, std::string pname) {
		this->timeCreate = ptimeCreate;
		this->priority = ppriority;
		this->task = ptask;
		this->name = pname;

		this->isTextTool = false;
	}

	int textAgent::getTimeCreate() const {
		return this->timeCreate;
	}

	int textAgent::getPriority() const {
		return this->priority;
	}

	std::string textAgent::getTask() const {
		return this->task;
	}

	std::string textAgent::getName() const {
		return this->name;
	}

	void textAgent::showData() const {
		std::cout << "Time create: " << this->timeCreate << std::endl;
		std::cout << "Priority: " << this->priority << std::endl;
		std::cout << "Name: " << this->name << std::endl;
		std::cout << "Task: " << this->task << std::endl;
	}

	const tt::textTool & textAgent::rejestrTextTool(tt::textTool tt) {
		if(this->isTextTool == false) {
			this->textTool = tt;

			this->isTextTool = true;

			return this->textTool;
		} else {
			return this->textTool;
		}
	}

	tt::textTool & textAgent::rejestrTextTool() throw(std::string) {
		if(this->isTextTool == false) {
			std::string exception = "Unregister text tool!";

			throw exception;
		} else {
			return this->textTool;
		}
	}

        tt::textTool & textAgent::getTextTool() {
            return this->rejestrTextTool();
        }
        
	textAgent::~textAgent() {
	}

} /* namespace ta */

Implementację interfejsu programu do przetwarzania tekstu zawiera listing poniżej:

/*
 * textTool.h
 *
 *  Created on: 21-12-2011
 *  Author: Marcin Mirończuk
 *  Licenc: GPL
 *
 *  Klas modelujaca modul (przybornik) do przetwarzania tekstu.
 *
 * @note::
 * + Metody [nazwaMetody]get() const nie zmieniaja stanu obiektow na rzecz ktorych sa wywolywane.
 *   (pola tylko do odczytu)
 * + Czesc metod [nazwaMetody]get() moze byc wywolana inline 
 * + Zabezpieczenie funkcji zwracajacych referencje modyfikatorem const tj.
 *   Uniemozliwienie wywolan typu ttTest.extractSegments("") = temp;
 *   @see http://rab.ict.pwr.wroc.pl/~kreczmer/po/materialy/referencje.pdf
 * 
 */

#include <map>
#include <vector>
#include <string>

#ifndef TT_H_
#define TT_H_

/**
 * Definicja przestrzeni nazw
 */
namespace tt {

	/**
	 *  Definicja klasy
	 */
	class textTool {

		/**
		 * Skladowe i metody prywatne klasy
		 */
		private:

			/**
			 * @type vector<string> segment Wektor segmentow
			 */
			std::vector<std::string> segments;

			/**
			 * @type vector<string> tokens Wektor tokenow (wyrazen)
			 */
			std::vector<std::string> tokens;

			/**
			 * @type vector<string> uniqueTokens Wektor unikalnych tokenow (wyrazen)
			 */
			std::vector<std::string> uniqueTokens;

			/**
			 * @type vector<string, int> tokensFrequ Tablica klucz=wartosc czestotliwosci wyrazen
			 */
			std::map<std::string, int> tokensFrequ;

			/**
			 * Usowanie duplikatow wyrazen z wektora wyrazen
			 *
			 * @see http://learningcppisfun.blogspot.com/2008/04/remove-duplicates-from-vector.html
			 * @see http://stackoverflow.com/questions/1041620/most-efficient-way-to-erase-duplicates-and-sort-a-c-vector
			 *
			 * @param vector<string> vec
			 *
			 * @return vector<string>
			 */
			const std::vector<std::string> & removeDuplicates(std::vector<std::string> vec);

		public:

			/**
			 * Domyslny konstruktor
			 */
			textTool();

			/**
			 * Wydobywanie segmentow z tekstu.
			 *
			 * @param string &text
			 *
			 * @return vector<string>
			 */
			const std::vector<std::string> & extractSegments(const std::string &text);

			/**
			 * Pobranie ilosci wydobytych segmentow z tekstu.
                         * 
			 * @return int
			 */
			int getCountSegments() const;

			/**
			 * Pokazanie wydobytych segmentow z tekstu.
			 *
			 * @return void
			 */
			void showSegments() const;

			/**
			 * Usuniecie spacji z poczatku jak i z konca lancucha znakow.
			 *
			 * @param string text
			 *
			 * @return string
			 */
			std::string stripWhiteSpace(std::string text);

			/**
			 * Przeciazona wersja usuniecia spacji z poczatku jak i z konca lancucha znakow.
			 *
			 * @param string *text
			 *
			 * @return void
			 */
			void stripWhiteSpace(std::string *text);

			/**
			 * Kalkulacja, wyznaczanie macierzy czetotliwosci wystepowania wyrazen w pojedynczym dokumencie tekstowym.
			 *
			 * @param string &text
			 *
			 * @return map<string, int>
			 */
			const std::map<std::string, int> & computeTokensFrequ(const std::string &text);

			/**
			 * Tokenizacja tekstu tj. rozbicie tekstu na wektor wyrazen.
			 * @see http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
			 *
			 * @param string &text
			 *
			 * @return vector<string>
			 */
			const std::vector<std::string> & tokenize(const std::string &text);

			/**
			 * Pobranie ilosci wyrazen.
			 *
			 * @return int
			 */
			int getCountTokens() const;

			/**
			 * Pobranie ilosci unikalnych wyrazen.
			 *
			 * @return int
			 */
			int getCountUniqueTokens();

			/**
			 * Domyslny destruktor
			 */
			virtual ~textTool();
		};

	} /* namespace tt */
#endif /* TT_H_ */

Implementację powyżej zaprezentowanego interfejsu programu do przetwarzania tekstu zawiera listing poniżej:

/*
 * textTool.cpp
 *
 *  Created on: 21-12-2011
 *  Author: Marcin Mirończuk
 *  Licenc: GPL
 *
 *  Implementacja interfejsu modulu do przetwarzania tekstu @see textTool.h
 *
 */

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include "textTool.h"

namespace tt {

	textTool::textTool() {
	}

	/**
	 * Bardzo naiwna, prezentacyja wersji algorytmu do rozbijania tekstu na segmenty (zdania)
	 */
	const std::vector<std::string> & textTool::extractSegments(const std::string &text) {

                std::string tempSegment;

		for(int i = 0; i < text.length(); i++) {
			if(text[i] == '.' || text[i] == '?' || text[i] == '!') {
				tempSegment = (std::string) tempSegment;
				this->segments.push_back(this->stripWhiteSpace(tempSegment));
				tempSegment.clear();
			} else {
				tempSegment += text[i];
			}
		}

		return this->segments;
	}

	int textTool::getCountSegments() const {
		return this->segments.size();
	}

	std::string textTool::stripWhiteSpace(std::string text) {

		if(text[0] == ' ') {
			text.replace(0, 1, "");
		}

		if(text[text.length()-1] == ' ') {
			text.replace(text.length()-1, 1, "");
		}

		return text;
	}

	void textTool::stripWhiteSpace(std::string *text) {
		std::string::iterator it;

		it = text->begin();

		if(*it == ' ') {
			text->replace(0, 1, "");
		}

		it = text->end();

		if(*(it-1) == ' ') {
			text->replace(text->length()-1, 1, "");
		}
	}

	void textTool::showSegments() const {
		for(int i = 0; i < this->segments.size(); i++) {
			std::cout << this->segments[i] << std::endl;
		}
	}

	const std::map<std::string, int> & textTool::computeTokensFrequ(const std::string &text) {
		this->tokenize(text);
		this->removeDuplicates(this->tokens);

		std::vector<std::string>::iterator it;

                //@todo :: Zaimplementowac algorytm do tworzenia macierzy wyrazen (term matrix, tm)
		for (it = this->uniqueTokens.begin(); it < this->uniqueTokens.end(); it++) {
		    std::cout << " " << *it;
		}

		return this->tokensFrequ;
	}

	const std::vector<std::string> & textTool::tokenize(const std::string &text) {
            
            // Buforowany string
	    std::string buf;

	    // Wstawienie stringu z potoku
	    std::stringstream ss(text);

	    while (ss >> buf) {
	    	this->tokens.push_back(buf);
		}

		return this->tokens;
	}

	int textTool::getCountTokens() const {
		return this->tokens.size();
	}

	int textTool::getCountUniqueTokens() {
		if(this->tokens.size() != 0 && this->uniqueTokens.size() == 0) {
			this->removeDuplicates(this->tokens);

			return this->uniqueTokens.size();
		} else {
			return this->uniqueTokens.size();
		}
	}

	const std::vector<std::string> & textTool::removeDuplicates(std::vector<std::string> vec) {
            
            std::sort(vec.begin(), vec.end());
	    vec.erase(std::unique(vec.begin(), vec.end()), vec.end());

	    this->uniqueTokens = vec;
            
            return this->uniqueTokens;
	 }

	textTool::~textTool() {

	}

} /* namespace tt */

Skomentuj ten wpis