Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/proxy/src/lib/util/substring.cc @ 9312

Last change on this file since 9312 was 9312, checked in by bensch, 18 years ago

minor lib cleanup

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