NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
database.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2020 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19#include <fstream>
20
21#include "database.hpp"
22#include "../ui/error.hpp"
23#include "../utils/tools.hpp"
24
25
26using namespace std;
27
28namespace NumeRe
29{
39 {
40 vector<string> vDBEntries;
41 string sLine;
42 string sFile = ValidFileName(m_dataBaseFile, ".ndb");
43 ifstream fDB;
44
45 // open the ifstream
46 fDB.open(sFile.c_str());
47 if (fDB.fail())
48 return vDBEntries;
49
50 // Read the entire file
51 while (!fDB.eof())
52 {
53 // Get a line and strip the spaces
54 getline(fDB, sLine);
55 StripSpaces(sLine);
56
57 // If the line has a length and doesn't start with the "#", then append it to the vector
58 if (sLine.length())
59 {
60 if (sLine[0] == '#')
61 continue;
62 vDBEntries.push_back(sLine);
63 }
64 }
65
66 // Return the read data base
67 return vDBEntries;
68 }
69
70
81 {
82 // Read the database to memory
83 vector<string> vDBEntries = getDBFileContent();
84 m_dataBase = vector<vector<string>>(vDBEntries.size(), vector<string>());
85
86 // Go through the database in memory
87 for (unsigned int i = 0; i < vDBEntries.size(); i++)
88 {
89 // If no field separator was found, simply append the overall line
90 if (vDBEntries[i].find('~') == string::npos)
91 m_dataBase[i].push_back(vDBEntries[i]);
92 else
93 {
94 // Split the database fields at the separators
95 while (vDBEntries[i].find('~') != string::npos)
96 {
97 // Append the next field
98 if (vDBEntries[i].substr(0, vDBEntries[i].find('~')).size())
99 m_dataBase[i].push_back(vDBEntries[i].substr(0, vDBEntries[i].find('~')));
100
101 // Erase the already appended field
102 vDBEntries[i].erase(0, vDBEntries[i].find('~') + 1);
103 }
104
105 // If there's one field remaining, append it here
106 if (vDBEntries[i].size())
107 m_dataBase[i].push_back(vDBEntries[i]);
108 }
109 }
110 }
111
112
123 size_t DataBase::findOrCreateRecord(const string& sRecord)
124 {
125 // Search for the record and return its ID
126 for (size_t i = 0; i < m_dataBase.size(); i++)
127 {
128 if (m_dataBase[i][0] == sRecord)
129 return i;
130 }
131
132 // Create a new one, because the searched
133 // one is not found
134 m_dataBase.push_back(vector<string>());
135 return m_dataBase.size()-1;
136 }
137
138
149 {
151 }
152
153
162 DataBase::DataBase(const string& sDataBaseFile) : DataBase()
163 {
164 m_dataBaseFile = sDataBaseFile;
165 readDataBase();
166 }
167
168
176 {
177 m_dataBase = data.m_dataBase;
179 }
180
181
190 DataBase::DataBase(const vector<string>& vDataColumn) : DataBase()
191 {
192 m_dataBaseFile = "Copied database";
193 m_dataBase = vector<vector<string>>(vDataColumn.size(), vector<string>(1, ""));
194
195 for (size_t i = 0; i < vDataColumn.size(); i++)
196 m_dataBase[i][0] = vDataColumn[i];
197 }
198
199
212 void DataBase::addData(const string& sDataBaseFile)
213 {
214 // If the internal database is still empty, use the
215 // passed file as default database
216 if (!m_dataBase.size())
217 {
218 m_dataBaseFile = sDataBaseFile;
219 readDataBase();
220 return;
221 }
222
223 // Read the database to memory
224 DataBase data(sDataBaseFile);
225
226 // Go through the database in memory
227 for (size_t i = 0; i < data.size(); i++)
228 {
229 // If no field separator was found, simply append the overall line
230 m_dataBase[findOrCreateRecord(data[i][0])] = data[i];
231 }
232 }
233
234
245 string DataBase::getElement(size_t i, size_t j) const
246 {
247 if (i < m_dataBase.size() && j < m_dataBase[i].size())
248 return m_dataBase[i][j];
249
250 return "";
251 }
252
253
265 vector<string> DataBase::getColumn(size_t j) const
266 {
267 vector<string> vColumn(m_dataBase.size(), "");
268
269 // Fill the vector with the elements of the
270 // selected column
271 for (size_t i = 0; i < m_dataBase.size(); i++)
272 vColumn[i] = getElement(i, j);
273
274 return vColumn;
275 }
276
277
288 vector<string>& DataBase::operator[](size_t i)
289 {
290 if (i < m_dataBase.size())
291 return m_dataBase[i];
292
294 }
295
296
306 {
307 m_dataBase = data.m_dataBase;
309
310 return *this;
311 }
312
321 {
322 srand(time(NULL));
323 size_t nthRecord = (rand() % m_dataBase.size());
324
325 if (nthRecord >= m_dataBase.size())
326 nthRecord = m_dataBase.size() - 1;
327
328 return nthRecord;
329 }
330
331
341 size_t DataBase::findRecord(const string& _sRecord) const
342 {
343 for (size_t i = 0; i < m_dataBase.size(); i++)
344 {
345 if (m_dataBase[i][0] == _sRecord)
346 return i;
347 }
348
349 return string::npos;
350 }
351
352
368 map<size_t,vector<size_t>> DataBase::find(const string& _sSearchString, bool findOnlyFirst) const
369 {
370 map<size_t,vector<size_t>> mMatches;
371
372 // Transform the searched string to lower case
373 string lower = toLowerCase(_sSearchString);
374
375 if (lower.length() && lower != " ")
376 {
377 // Search through the database
378 for (size_t i = 0; i < m_dataBase.size(); i++)
379 {
380 for (size_t j = 0; j < m_dataBase[i].size(); j++)
381 {
382 if (toLowerCase(m_dataBase[i][j]).find(lower) != string::npos)
383 {
384 // Store the match (will create a new vector automatically)
385 mMatches[i].push_back(j);
386
387 if (findOnlyFirst)
388 break;
389 }
390 }
391 }
392 }
393
394 return mMatches;
395 }
396
397
413 map<double,vector<size_t>> DataBase::findRecordsUsingRelevance(const string& _sSearchString, vector<double> vWeighting) const
414 {
415 vector<string> vKeyWords;
416 string sTemp = _sSearchString;
417 map<double,vector<size_t>> mRelevance;
418 static std::string sIGNOREWORDS = " " + _lang.get("COMMON_SEARCH_IGNOREWORDS") + " ";
419
420 if (sTemp.back() != ' ')
421 sTemp += " ";
422
423 // Create a keyword list to search independently
424 do
425 {
426 std::string sKeyWord = sTemp.substr(0, sTemp.find(" "));
427 sTemp.erase(0, sTemp.find(" ")+1);
428
429 // Do not use ingore words unless it's the only
430 // search term
431 if (sIGNOREWORDS.find(" " + sKeyWord + " ") == std::string::npos
432 || (!vKeyWords.size() && !sTemp.length()))
433 vKeyWords.push_back(sKeyWord);
434 }
435 while (sTemp.length());
436
437 // Create the result map with the first
438 // keyword
439 map<size_t,vector<size_t>> mMatches = find(vKeyWords.front());
440
441 // Search all following keywords and append
442 // their results to the existing map
443 for (size_t i = 1; i < vKeyWords.size(); i++)
444 {
445 map<size_t,vector<size_t>> mCurMatches = find(vKeyWords[i]);
446
447 for (auto iter = mCurMatches.begin(); iter != mCurMatches.end(); ++iter)
448 {
449 // Will automatically create a new vector,
450 // if it does not exist
451 mMatches[iter->first].insert(mMatches[iter->first].end(), iter->second.begin(), iter->second.end());
452 }
453 }
454
455 // Prepare the weighting or add additional
456 // zeros, if necessary
457 if (!vWeighting.size())
458 vWeighting.assign(getCols(), 1.0);
459 else if (vWeighting.size() < getCols())
460 vWeighting.insert(vWeighting.end(), getCols()-vWeighting.size(), 0.0);
461
462 // Calculate the relevance values and append
463 // their corresponding record IDs
464 for (auto iter = mMatches.begin(); iter != mMatches.end(); ++iter)
465 {
466 double weight = 0.0;
467
468 for (size_t i = 0; i < iter->second.size(); i++)
469 {
470 weight += vWeighting[iter->second[i]];
471 }
472
473 mRelevance[weight].push_back(iter->first);
474 }
475
476 return mRelevance;
477 }
478}
479
std::string toLowerCase(const std::string &)
Converts uppercase to lowercase letters.
This class implements the basic input/ output file system and provides functionalities to work with f...
Definition: filesystem.hpp:92
void initializeFromKernel()
Member function to remote-initialize the class from the kernel. Cannot be used during kernel start-up...
Definition: filesystem.cpp:750
std::string ValidFileName(std::string _sFileName, const std::string sExtension=".dat", bool checkExtension=true, bool doCleanPath=true) const
This member function evaluates, whether the passed filename is a valid filename. One may supply a pre...
Definition: filesystem.cpp:280
std::string get(const std::string &sMessage, const std::vector< std::string > &vTokens) const
This member function returns the language string for the passed language identifier and replaces all ...
Definition: language.cpp:292
This class is an implementation of a database. It will handle the *.ndb data format an provides an in...
Definition: database.hpp:37
std::vector< std::string > getDBFileContent()
This member function reads the contents of a database file linewise to a vector.
Definition: database.cpp:38
std::map< double, std::vector< size_t > > findRecordsUsingRelevance(const std::string &_sSearchString, std::vector< double > vWeighting=std::vector< double >()) const
This member function will search multiple search strings in the database and returns a map,...
Definition: database.cpp:413
std::map< size_t, std::vector< size_t > > find(const std::string &_sSearchString, bool findOnlyFirst=false) const
This member function can be used to search a string in the managed database. The return value is a ma...
Definition: database.cpp:368
std::vector< std::string > & operator[](size_t i)
This is an overload of the array access operator, which can be used with read and write permissions....
Definition: database.cpp:288
std::string getElement(size_t i, size_t j) const
This member function will return the contents of the selected database field, or an empty string,...
Definition: database.cpp:245
size_t findOrCreateRecord(const std::string &sRecord)
This member function will return the id of the searched record (value in the first column of the matr...
Definition: database.cpp:123
size_t getCols() const
Definition: database.hpp:59
size_t size() const
Definition: database.hpp:54
void readDataBase()
This function opens up a NumeRe Data base file and reads its contents to the internal vector<vector> ...
Definition: database.cpp:80
size_t findRecord(const std::string &_sRecord) const
This member function finds a selected record in the first column of the database table and returns it...
Definition: database.cpp:341
std::vector< std::vector< std::string > > m_dataBase
Definition: database.hpp:39
size_t randomRecord() const
This member function can be used to select and random record.
Definition: database.cpp:320
std::vector< std::string > getColumn(size_t j) const
This member function will return the whole selected column of the database as a vector<string>....
Definition: database.cpp:265
std::string m_dataBaseFile
Definition: database.hpp:40
DataBase & operator=(const DataBase &data)
This is an overload of the assignment operator.
Definition: database.cpp:305
DataBase()
The default constructor will initialize the FileSystem base class using the information from the kern...
Definition: database.cpp:148
void addData(const std::string &sDataBaseFile)
This member function will use the passed database file name to update its internal contents (i....
Definition: database.cpp:212
Common exception class for all exceptions thrown in NumeRe.
Definition: error.hpp:32
@ TOO_FEW_LINES
Definition: error.hpp:215
static size_t invalid_position
Definition: error.hpp:235
Language _lang
Definition: kernel.cpp:39
void StripSpaces(std::string &)
Removes leading and trailing white spaces and tabulator characters.