12 sty
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