Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/util/SubString.cc @ 1640

Last change on this file since 1640 was 1505, checked in by rgrieder, 16 years ago

f* svn: It doesn't even inform you if you attempt to set a non existing property. It is svn:eol-style and not eol-style when using the command by the way…

  • Property svn:eol-style set to native
File size: 17.1 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Christian Meyer
24 *   Co-authors:
25 *      Benjamin Grauer
26 *
27//
28//  splitLine
29//  STL string tokenizer
30//
31//  Created by Clemens Wacha.
32//  Version 1.0
33//  Copyright (c) 2005 Clemens Wacha. All rights reserved.
34//
35 */
36
37#include "SubString.h"
38
39/**
40 * @brief default constructor
41 */
42SubString::SubString()
43{}
44
45
46/**
47 * @brief create a SubString from
48 * @param string the String to Split
49 * @param delimiter the Character at which to split string (delimiter)
50 */
51SubString::SubString(const std::string& string, char delimiter)
52{
53  this->split(string, delimiter);
54}
55
56
57/**
58 * @brief Splits a String into multiple splitters.
59 * @param string the String to split
60 * @param delimiters multiple set of characters at what to split. (delimiters)
61 * @param delimiterNeighbours neighbours of the delimiters, that will be erased only when near a delimiter.
62 * @param emptyEntries If empty entries should be allewed or removed.
63 * @param escapeChar The Escape Character that overrides splitters commends and so on...
64 * @param safemode_char within these characters splitting won't happen
65 * @param comment_char the Comment character.
66 */
67SubString::SubString(const std::string& string,
68                     const std::string& delimiters, const std::string& delimiterNeighbours, bool emptyEntries,
69                     char escapeChar, bool removeEscapeChar, char safemode_char, bool removeSafemodeChar,
70                     char openparenthesis_char, char closeparenthesis_char, bool removeParenthesisChars, char comment_char)
71{
72  SubString::splitLine(this->strings, this->bInSafemode, string, delimiters, delimiterNeighbours, emptyEntries, escapeChar, removeEscapeChar, safemode_char, removeSafemodeChar, openparenthesis_char, closeparenthesis_char, removeParenthesisChars, comment_char);
73}
74
75/**
76 * @brief creates a SubSet of a SubString.
77 * @param subString the SubString to take a set from.
78 * @param subSetBegin the beginning to the end
79 */
80SubString::SubString(const SubString& subString, unsigned int subSetBegin)
81{
82  for (unsigned int i = subSetBegin; i < subString.size(); i++)
83  {
84    this->strings.push_back(subString[i]);
85    this->bInSafemode.push_back(subString.isInSafemode(i));
86  }
87}
88
89
90/**
91 * @brief creates a SubSet of a SubString.
92 * @param subString the SubString to take a Set from
93 * @param subSetBegin the beginning to the end
94 * @param subSetEnd the end of the SubSet (max subString.size() will be checked internaly)
95 */
96SubString::SubString(const SubString& subString, unsigned int subSetBegin, unsigned int subSetEnd)
97{
98  for (unsigned int i = subSetBegin; i < subString.size() && i < subSetEnd; i++)
99  {
100    this->strings.push_back(subString[i]);
101    this->bInSafemode.push_back(subString.isInSafemode(i));
102  }
103}
104
105/**
106 * @brief creates a Substring from a count and values set.
107 * @param argc: the Arguments Count.
108 * @param argv: Argument Values.
109 */
110SubString::SubString(unsigned int argc, const char** argv)
111{
112  for(unsigned int i = 0; i < argc; ++i)
113  {
114    this->strings.push_back(std::string(argv[i]));
115    this->bInSafemode.push_back(false);
116  }
117}
118
119/**
120 * @brief removes the object from memory
121 */
122SubString::~SubString()
123{ }
124
125/** @brief An empty String */
126// const std::string SubString::emptyString = "";
127/** @brief Helper that gets you a String consisting of all White Spaces */
128const std::string SubString::WhiteSpaces = " \n\t";
129/** @brief Helper that gets you a String consisting of all WhiteSpaces and the Comma */
130const std::string SubString::WhiteSpacesWithComma = " \n\t,";
131/** An Empty SubString */
132const SubString SubString::NullSubString = SubString();
133
134/**
135 * @brief stores the Value of subString in this SubString
136 * @param subString will be copied into this String.
137 * @returns this SubString.
138 */
139SubString& SubString::operator=(const SubString& subString)
140{
141  this->strings = subString.strings;
142  this->bInSafemode = subString.bInSafemode;
143  return *this;
144}
145
146
147/**
148 * @brief comparator.
149 * @param subString the SubString to compare against this one.
150 * @returns true if the Stored Strings match
151 */
152bool SubString::operator==(const SubString& subString) const
153{
154  return ((this->strings == subString.strings) && (this->bInSafemode == subString.bInSafemode));
155}
156
157/**
158 * @brief comparator.
159 * @param subString the SubString to compare against this one.
160 * @returns true if the Stored Strings match
161 */
162bool SubString::compare(const SubString& subString) const
163{
164  return (*this == subString);
165}
166
167/**
168 * @brief comparator.
169 * @param subString the SubString to compare against this one.
170 * @param length how many entries to compare. (from 0 to length)
171 * @returns true if the Stored Strings match
172 */
173bool SubString::compare(const SubString& subString, unsigned int length) const
174{
175  if (length > this->size() || length > subString.size())
176    return false;
177
178  for (unsigned int i = 0; i < length; i++)
179    if ((this->strings[i] != subString.strings[i]) || (this->bInSafemode[i] != subString.bInSafemode[i]))
180      return false;
181  return true;
182}
183
184
185/**
186 * @brief append operator
187 * @param subString the String to append.
188 * @returns a SubString where this and subString are appended.
189 */
190SubString SubString::operator+(const SubString& subString) const
191{
192  return SubString(*this) += subString;
193}
194
195
196/**
197 * @brief append operator.
198 * @param subString append subString to this SubString.
199 * @returns this substring appended with subString
200 */
201SubString& SubString::operator+=(const SubString& subString)
202{
203  for (unsigned int i = 0; i < subString.size(); i++)
204  {
205    this->strings.push_back(subString[i]);
206    this->bInSafemode.push_back(subString.isInSafemode(i));
207  }
208  return *this;
209}
210
211
212/**
213 * @brief Split the String at
214 * @param string where to split
215 * @param splitter delimiter.
216 */
217unsigned int SubString::split(const std::string& string, char splitter)
218{
219  this->strings.clear();
220  this->bInSafemode.clear();
221  char split[2];
222  split[0] = splitter;
223  split[1] = '\0';
224  SubString::splitLine(this->strings, this->bInSafemode, string, split);
225  return strings.size();
226}
227
228
229/**
230 * @brief Splits a String into multiple splitters.
231 * @param string the String to split
232 * @param delimiters multiple set of characters at what to split. (delimiters)
233 * @param delimiterNeighbours: Neighbours to the Delimiters that will be erased too.
234 * @param emptyEntries: If empty entries are added to the List of SubStrings
235 * @param escapeChar The Escape Character that overrides splitters commends and so on...
236 * @param safemode_char within these characters splitting won't happen
237 * @param comment_char the Comment character.
238 */
239unsigned int SubString::split(const std::string& string,
240                              const std::string& delimiters, const std::string& delimiterNeighbours, bool emptyEntries,
241                              char escapeChar, bool removeExcapeChar, char safemode_char, bool removeSafemodeChar,
242                              char openparenthesis_char, char closeparenthesis_char, bool removeParenthesisChars, char comment_char)
243{
244  this->strings.clear();
245  this->bInSafemode.clear();
246  SubString::splitLine(this->strings, this->bInSafemode, string, delimiters, delimiterNeighbours, emptyEntries, escapeChar, removeExcapeChar, safemode_char, removeSafemodeChar, openparenthesis_char, closeparenthesis_char, removeParenthesisChars, comment_char);
247  return this->strings.size();
248}
249
250
251/**
252 * @brief joins together all Strings of this Substring.
253 * @param delimiter the String between the subStrings.
254 * @returns the joined String.
255 */
256std::string SubString::join(const std::string& delimiter) const
257{
258  if (!this->strings.empty())
259  {
260    std::string retVal = this->strings[0];
261    for (unsigned int i = 1; i < this->strings.size(); i++)
262      retVal += delimiter + this->strings[i];
263    return retVal;
264  }
265  else
266  {
267    static std::string empty;
268    return empty;
269  }
270}
271
272
273/**
274 * @brief creates a SubSet of a SubString.
275 * @param subSetBegin the beginning to the end
276 * @returns the SubSet
277 *
278 * This function is added for your convenience, and does the same as
279 * SubString::SubString(const SubString& subString, unsigned int subSetBegin)
280 */
281SubString SubString::subSet(unsigned int subSetBegin) const
282{
283  return SubString(*this, subSetBegin);
284}
285
286
287/**
288 * @brief creates a SubSet of a SubString.
289 * @param subSetBegin the beginning to
290 * @param subSetEnd the end of the SubSet to select (if bigger than subString.size() it will be downset.)
291 * @returns the SubSet
292 *
293 * This function is added for your convenience, and does the same as
294 * SubString::SubString(const SubString& subString, unsigned int subSetBegin)
295 */
296SubString SubString::subSet(unsigned int subSetBegin, unsigned int subSetEnd) const
297{
298  return SubString(*this, subSetBegin, subSetEnd);
299}
300
301
302/**
303 * @brief splits line into tokens and stores them in ret.
304 * @param ret the Array, where the Splitted strings will be stored in
305 * to the beginning of the current token is stored
306 * @param line the inputLine to split
307 * @param delimiters a String of Delimiters (here the input will be splitted)
308 * @param delimiterNeighbours Naighbours to the Delimitter, that will be removed if they are to the left or the right of a Delimiter.
309 * @param emptyEntries: if empty Strings are added to the List of Strings.
310 * @param escape_char: Escape carater (escapes splitters)
311 * @param safemode_char: the beginning of the safemode is marked with this
312 * @param removeSafemodeChar removes the safemode_char from the beginning and the ending of a token
313 * @param openparenthesis_char the beginning of a safemode is marked with this
314 * @param closeparenthesis_char the ending of a safemode is marked with this
315 * @param removeParenthesisChars removes the parenthesis from the beginning and the ending of a token
316 * @param comment_char: the beginning of a comment is marked with this: (until the end of a Line)
317 * @param start_state: the Initial state on how to parse the String.
318 * @return SPLIT_LINE_STATE the parser was in when returning
319 *
320 * This is the Actual Splitting Algorithm from Clemens Wacha
321 * Supports delimiters, escape characters,
322 * ignores special  characters between safemode_char and between comment_char and linend '\n'.
323 */
324SubString::SPLIT_LINE_STATE
325SubString::splitLine(std::vector<std::string>& ret,
326                     std::vector<bool>& bInSafemode,
327                     const std::string& line,
328                     const std::string& delimiters,
329                     const std::string& delimiterNeighbours,
330                     bool emptyEntries,
331                     char escape_char,
332                     bool removeExcapeChar,
333                     char safemode_char,
334                     bool removeSafemodeChar,
335                     char openparenthesis_char,
336                     char closeparenthesis_char,
337                     bool removeParenthesisChars,
338                     char comment_char,
339                     SPLIT_LINE_STATE start_state)
340{
341  SPLIT_LINE_STATE state = start_state;
342  unsigned int i = 0;
343  unsigned int fallBackNeighbours = 0;
344
345  std::string token;
346  bool inSafemode = false;
347
348  if(start_state != SL_NORMAL && ret.size() > 0)
349  {
350    token = ret[ret.size()-1];
351    ret.pop_back();
352  }
353  if(start_state != SL_NORMAL && bInSafemode.size() > 0)
354  {
355    inSafemode = bInSafemode[bInSafemode.size()-1];
356    bInSafemode.pop_back();
357  }
358
359  while(i < line.size())
360  {
361    switch(state)
362    {
363      case SL_NORMAL:
364        if(line[i] == escape_char)
365        {
366          state = SL_ESCAPE;
367          if (!removeExcapeChar)
368            token += line[i];
369        }
370        else if(line[i] == safemode_char)
371        {
372          state = SL_SAFEMODE;
373          inSafemode = true;
374          if (!removeSafemodeChar)
375            token += line[i];
376        }
377        else if(line[i] == openparenthesis_char)
378        {
379          state = SL_PARENTHESES;
380          inSafemode = true;
381          if (!removeParenthesisChars)
382            token += line[i];
383        }
384        else if(line[i] == comment_char)
385        {
386          if (fallBackNeighbours > 0)
387            token = token.substr(0, token.size() - fallBackNeighbours);
388          /// FINISH
389          if(emptyEntries || token.size() > 0)
390          {
391            ret.push_back(token);
392            token.clear();
393            bInSafemode.push_back(inSafemode);
394            inSafemode = false;
395          }
396          token += line[i];       // EAT
397          state = SL_COMMENT;
398        }
399        else if(delimiters.find(line[i]) != std::string::npos)
400        {
401          // line[i] is a delimiter
402          if (fallBackNeighbours > 0)
403            token = token.substr(0, token.size() - fallBackNeighbours);
404          /// FINISH
405          if(emptyEntries || token.size() > 0)
406          {
407            ret.push_back(token);
408            token.clear();
409            bInSafemode.push_back(inSafemode);
410            inSafemode = false;
411          }
412          state = SL_NORMAL;
413        }
414        else
415        {
416          if (delimiterNeighbours.find(line[i]) != std::string::npos)
417          {
418            if (token.size() > 0)
419              ++fallBackNeighbours;
420            else
421            {
422              i++;
423              continue;
424            }
425          }
426          else
427            fallBackNeighbours = 0;
428          token += line[i];       // EAT
429        }
430        break;
431      case SL_ESCAPE:
432        if (!removeSafemodeChar)
433          token += line[i];
434        else
435        {
436          if(line[i] == 'n') token += '\n';
437          else if(line[i] == 't') token += '\t';
438          else if(line[i] == 'v') token += '\v';
439          else if(line[i] == 'b') token += '\b';
440          else if(line[i] == 'r') token += '\r';
441          else if(line[i] == 'f') token += '\f';
442          else if(line[i] == 'a') token += '\a';
443          else if(line[i] == '?') token += '\?';
444          else token += line[i];  // EAT
445        }
446        state = SL_NORMAL;
447        break;
448      case SL_SAFEMODE:
449        if(line[i] == safemode_char)
450        {
451          state = SL_NORMAL;
452          if (!removeSafemodeChar)
453            token += line[i];
454        }
455        else if(line[i] == escape_char)
456        {
457          state = SL_SAFEESCAPE;
458        }
459        else
460        {
461          token += line[i];       // EAT
462        }
463        break;
464
465      case SL_SAFEESCAPE:
466        if(line[i] == 'n') token += '\n';
467        else if(line[i] == 't') token += '\t';
468        else if(line[i] == 'v') token += '\v';
469        else if(line[i] == 'b') token += '\b';
470        else if(line[i] == 'r') token += '\r';
471        else if(line[i] == 'f') token += '\f';
472        else if(line[i] == 'a') token += '\a';
473        else if(line[i] == '?') token += '\?';
474        else token += line[i];  // EAT
475        state = SL_SAFEMODE;
476        break;
477
478      case SL_PARENTHESES:
479        if(line[i] == closeparenthesis_char)
480        {
481          state = SL_NORMAL;
482          if (!removeParenthesisChars)
483            token += line[i];
484        }
485        else if(line[i] == escape_char)
486        {
487          state = SL_PARENTHESESESCAPE;
488        }
489        else
490        {
491          token += line[i];       // EAT
492        }
493        break;
494
495      case SL_PARENTHESESESCAPE:
496        if(line[i] == 'n') token += '\n';
497        else if(line[i] == 't') token += '\t';
498        else if(line[i] == 'v') token += '\v';
499        else if(line[i] == 'b') token += '\b';
500        else if(line[i] == 'r') token += '\r';
501        else if(line[i] == 'f') token += '\f';
502        else if(line[i] == 'a') token += '\a';
503        else if(line[i] == '?') token += '\?';
504        else token += line[i];  // EAT
505        state = SL_PARENTHESES;
506        break;
507
508      case SL_COMMENT:
509        if(line[i] == '\n')
510        {
511          /// FINISH
512          if(token.size() > 0)
513          {
514            ret.push_back(token);
515            token.clear();
516            bInSafemode.push_back(inSafemode);
517            inSafemode = false;
518          }
519          state = SL_NORMAL;
520        }
521        else
522        {
523          token += line[i];       // EAT
524        }
525        break;
526
527      default:
528        // nothing
529        break;
530    }
531    i++;
532  }
533
534  /// FINISH
535  if (fallBackNeighbours > 0)
536    token = token.substr(0, token.size() - fallBackNeighbours);
537  if(emptyEntries || token.size() > 0)
538  {
539    ret.push_back(token);
540    token.clear();
541    bInSafemode.push_back(inSafemode);
542    inSafemode = false;
543  }
544  return(state);
545}
546
547
548/**
549 * @brief Some nice debug information about this SubString
550 */
551void SubString::debug() const
552{
553  printf("Substring-information::count=%d ::", this->strings.size());
554  for (unsigned int i = 0; i < this->strings.size(); i++)
555    printf("s%d='%s'::", i, this->strings[i].c_str());
556  printf("\n");
557}
Note: See TracBrowser for help on using the repository browser.