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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | //============================================================================ // 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | /* * 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | /* * 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | /* * 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | /* * 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 */ |