Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core/src/util/SubString.cc @ 849

Last change on this file since 849 was 849, checked in by landauf, 16 years ago

and here comes the extended SubString class (added parenthesis support), I had problems with svn

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