Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/util/SubString.cc @ 7525

Last change on this file since 7525 was 7401, checked in by landauf, 14 years ago

merged doc branch back to trunk

  • Property svn:eol-style set to native
File size: 19.5 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//
29//  splitLine
30//  STL string tokenizer
31//
32//  Created by Clemens Wacha.
33//  Version 1.0
34//  Copyright (c) 2005 Clemens Wacha. All rights reserved.
35//
36
37 *   Extended by Fabian 'x3n' Landau by the SL_PARENTHESES mode.
38 */
39
40/**
41    @file
42    @brief Implementation of the SubString class.
43*/
44
45#include "SubString.h"
46#include <cstdio>
47#include "Debug.h"
48
49namespace orxonox
50{
51    const std::string SubString::WhiteSpaces          = " \n\t";
52    const std::string SubString::WhiteSpacesWithComma = " \n\t,";
53    const SubString SubString::NullSubString          = SubString();
54
55    /**
56        @brief Default constructor.
57    */
58    SubString::SubString()
59    {
60    }
61
62    /**
63        @brief Splits a string into multiple tokens.
64        @param line The line to split
65        @param delimiters Multiple characters at which to split the line
66        @param delimiterNeighbours Neighbours of the delimiters that will be erased as well (for example white-spaces)
67        @param bAllowEmptyEntries If true, empty tokens are also added to the SubString (if there are two delimiters without a char in between)
68        @param escapeChar The escape character that is used to escape safemode chars (for example if you want to use a quotation mark between two other quotation marks).
69        @param bRemoveEscapeChar If true, the escape char is removed from the tokens
70        @param safemodeChar Within these characters splitting won't happen (usually the quotation marks)
71        @param bRemoveSafemodeChar Removes the safemodeChar from the beginning and the ending of a token
72        @param openparenthesisChar The beginning of a safemode is marked with this (usually an opening brace)
73        @param closeparenthesisChar The ending of a safemode is marked with this (usually a closing brace)
74        @param bRemoveParenthesisChars Removes the parenthesis chars from the beginning and the ending of a token
75        @param commentChar The comment character (used to ignore the part of the line after the comment char).
76    */
77    SubString::SubString(const std::string& line,
78                         const std::string& delimiters, const std::string& delimiterNeighbours, bool bAllowEmptyEntries,
79                         char escapeChar, bool bRemoveEscapeChar, char safemodeChar, bool bRemoveSafemodeChar,
80                         char openparenthesisChar, char closeparenthesisChar, bool bRemoveParenthesisChars, char commentChar)
81    {
82        SubString::splitLine(this->tokens_, this->bTokenInSafemode_, line, delimiters, delimiterNeighbours, bAllowEmptyEntries, escapeChar, bRemoveEscapeChar, safemodeChar, bRemoveSafemodeChar, openparenthesisChar, closeparenthesisChar, bRemoveParenthesisChars, commentChar);
83    }
84
85    /**
86        @brief creates a new SubString based on a subset of an other SubString.
87        @param other The other SubString
88        @param begin The beginning of the subset
89
90        The subset ranges from the token with index @a begin to the end of the tokens.
91        If @a begin is greater than the greatest index, the new SubString will be empty.
92    */
93    SubString::SubString(const SubString& other, unsigned int begin)
94    {
95        for (unsigned int i = begin; i < other.size(); ++i)
96        {
97            this->tokens_.push_back(other[i]);
98            this->bTokenInSafemode_.push_back(other.isInSafemode(i));
99        }
100    }
101
102    /**
103        @brief creates a new SubString based on a subset of an other SubString.
104        @param other The other SubString
105        @param begin The beginning of the subset
106        @param end The end of the subset
107
108        The subset ranges from the token with index @a begin until (but not including) the token with index @a end.
109        If @a begin or @a end are beyond the allowed index, the resulting SubString will be empty.
110    */
111    SubString::SubString(const SubString& other, unsigned int begin, unsigned int end)
112    {
113        for (unsigned int i = begin; i < std::min(other.size(), end); ++i)
114        {
115            this->tokens_.push_back(other[i]);
116            this->bTokenInSafemode_.push_back(other.isInSafemode(i));
117        }
118    }
119
120    /**
121        @brief Creates a SubString from a count and values set.
122        @param argc The number of arguments
123        @param argv An array of pointers to the arguments
124    */
125    SubString::SubString(unsigned int argc, const char** argv)
126    {
127        for(unsigned int i = 0; i < argc; ++i)
128        {
129            this->tokens_.push_back(std::string(argv[i]));
130            this->bTokenInSafemode_.push_back(false);
131        }
132    }
133
134    /**
135        @brief Destructor
136    */
137    SubString::~SubString()
138    { }
139
140    /**
141        @brief Stores the tokens of @a other in this SubString
142        @return This SubString.
143    */
144    SubString& SubString::operator=(const SubString& other)
145    {
146        this->tokens_ = other.tokens_;
147        this->bTokenInSafemode_ = other.bTokenInSafemode_;
148        return *this;
149    }
150
151    /**
152        @brief Compares this SubString to another SubString and returns true if they contain the same values.
153    */
154    bool SubString::operator==(const SubString& other) const
155    {
156        return ((this->tokens_ == other.tokens_) && (this->bTokenInSafemode_ == other.bTokenInSafemode_));
157    }
158
159    /**
160        @copydoc operator==
161    */
162    bool SubString::compare(const SubString& other) const
163    {
164        return (*this == other);
165    }
166
167    /**
168        @brief Compares this SubString to another SubString and returns true if the first @a length values match.
169        @param other The other SubString
170        @param length How many tokens to compare
171    */
172    bool SubString::compare(const SubString& other, unsigned int length) const
173    {
174        if (length > this->size() || length > other.size())
175            return false;
176
177        for (unsigned int i = 0; i < length; ++i)
178            if ((this->tokens_[i] != other.tokens_[i]) || (this->bTokenInSafemode_[i] != other.bTokenInSafemode_[i]))
179                return false;
180        return true;
181    }
182
183    /**
184        @brief Concatenates the tokens of two SubStrings and returns the resulting new SubString
185        @return A new SubString that contains the tokens of this and the other SubString
186    */
187    SubString SubString::operator+(const SubString& other) const
188    {
189        return SubString(*this) += other;
190    }
191
192    /**
193        @brief Appends the tokens of @a other to this SubString
194        @return This SubString
195    */
196    SubString& SubString::operator+=(const SubString& other)
197    {
198        for (unsigned int i = 0; i < other.size(); ++i)
199        {
200            this->tokens_.push_back(other[i]);
201            this->bTokenInSafemode_.push_back(other.isInSafemode(i));
202        }
203        return *this;
204    }
205
206    /**
207        @copydoc SubString(const std::string&,const std::string&,const std::string&,bool,char,bool,char,bool,char,char,bool,char)
208    */
209    unsigned int SubString::split(const std::string& line,
210                                  const std::string& delimiters, const std::string& delimiterNeighbours, bool bAllowEmptyEntries,
211                                  char escapeChar, bool bRemoveEscapeChar, char safemodeChar, bool bRemoveSafemodeChar,
212                                  char openparenthesisChar, char closeparenthesisChar, bool bRemoveParenthesisChars, char commentChar)
213    {
214        this->tokens_.clear();
215        this->bTokenInSafemode_.clear();
216        SubString::splitLine(this->tokens_, this->bTokenInSafemode_, line, delimiters, delimiterNeighbours, bAllowEmptyEntries, escapeChar, bRemoveEscapeChar, safemodeChar, bRemoveSafemodeChar, openparenthesisChar, closeparenthesisChar, bRemoveParenthesisChars, commentChar);
217        return this->tokens_.size();
218    }
219
220    /**
221        @brief Joins the tokens of this SubString using the given delimiter and returns a string.
222        @param delimiter This delimiter will be placed between each two tokens
223        @return The joined string.
224    */
225    std::string SubString::join(const std::string& delimiter) const
226    {
227        if (!this->tokens_.empty())
228        {
229            std::string retVal = this->tokens_[0];
230            for (unsigned int i = 1; i < this->tokens_.size(); ++i)
231                retVal += delimiter + this->tokens_[i];
232            return retVal;
233        }
234        else
235            return "";
236    }
237
238    /**
239        @brief Creates a subset of this SubString.
240        @param begin The beginning of the subset
241        @return A new SubString containing the defined subset.
242
243        The subset ranges from the token with index @a begin to the end of the tokens.
244        If @a begin is greater than the greatest index, the new SubString will be empty.
245
246        This function is added for your convenience, and does the same as
247        SubString::SubString(const SubString& other, unsigned int begin)
248    */
249    SubString SubString::subSet(unsigned int begin) const
250    {
251        return SubString(*this, begin);
252    }
253
254    /**
255        @brief Creates a subset of this SubString.
256        @param begin The beginning of the subset
257        @param end The ending of the subset
258        @return A new SubString containing the defined subset.
259
260        The subset ranges from the token with index @a begin until (but not including) the token with index @a end.
261        If @a begin or @a end are beyond the allowed index, the resulting SubString will be empty.
262
263        This function is added for your convenience, and does the same as
264        SubString::SubString(const SubString& other, unsigned int begin, unsigned int end)
265    */
266    SubString SubString::subSet(unsigned int begin, unsigned int end) const
267    {
268        return SubString(*this, begin, end);
269    }
270
271    /**
272        @copydoc SubString(const std::string&,const std::string&,const std::string&,bool,char,bool,char,bool,char,char,bool,char)
273        @param tokens The array, where the splitted strings will be stored in
274        @param bTokenInSafemode A vector wich stores for each character of the string if it is in safemode or not
275        @param start_state The internal state of the parser
276
277        This is the actual splitting algorithm from Clemens Wacha.
278        Supports delimiters, escape characters, ignores special characters between safemodeChar and between commentChar and line end "\n".
279
280        Extended by Orxonox to support parenthesis as additional safe-mode.
281    */
282    SubString::SPLIT_LINE_STATE
283    SubString::splitLine(std::vector<std::string>& tokens,
284                         std::vector<bool>& bTokenInSafemode,
285                         const std::string& line,
286                         const std::string& delimiters,
287                         const std::string& delimiterNeighbours,
288                         bool bAllowEmptyEntries,
289                         char escapeChar,
290                         bool bRemoveEscapeChar,
291                         char safemodeChar,
292                         bool bRemoveSafemodeChar,
293                         char openparenthesisChar,
294                         char closeparenthesisChar,
295                         bool bRemoveParenthesisChars,
296                         char commentChar,
297                         SPLIT_LINE_STATE start_state)
298    {
299        SPLIT_LINE_STATE state = start_state;
300        unsigned int i = 0;
301        unsigned int fallBackNeighbours = 0;
302
303        std::string token;
304        bool inSafemode = false;
305
306        if(start_state != SL_NORMAL && tokens.size() > 0)
307        {
308            token = tokens[tokens.size()-1];
309            tokens.pop_back();
310        }
311        if(start_state != SL_NORMAL && bTokenInSafemode.size() > 0)
312        {
313            inSafemode = bTokenInSafemode[bTokenInSafemode.size()-1];
314            bTokenInSafemode.pop_back();
315        }
316
317        while(i < line.size())
318        {
319            switch(state)
320            {
321            case SL_NORMAL:
322                if(line[i] == escapeChar)
323                {
324                    state = SL_ESCAPE;
325                    if (!bRemoveEscapeChar)
326                        token += line[i];
327                    fallBackNeighbours = 0;
328                }
329                else if(line[i] == safemodeChar)
330                {
331                    state = SL_SAFEMODE;
332                    inSafemode = true;
333                    if (!bRemoveSafemodeChar)
334                        token += line[i];
335                    fallBackNeighbours = 0;
336                }
337                else if(line[i] == openparenthesisChar)
338                {
339                    state = SL_PARENTHESES;
340                    inSafemode = true;
341                    if (!bRemoveParenthesisChars)
342                        token += line[i];
343                    fallBackNeighbours = 0;
344                }
345                else if(line[i] == commentChar)
346                {
347                    if (fallBackNeighbours > 0)
348                        token = token.substr(0, token.size() - fallBackNeighbours);
349                    fallBackNeighbours = 0;
350                    // FINISH
351                    if(bAllowEmptyEntries || token.size() > 0)
352                    {
353                        tokens.push_back(token);
354                        token.clear();
355                        bTokenInSafemode.push_back(inSafemode);
356                        inSafemode = false;
357                    }
358                    token += line[i];       // EAT
359                    state = SL_COMMENT;
360                }
361                else if(delimiters.find(line[i]) != std::string::npos)
362                {
363                    // line[i] is a delimiter
364                    if (fallBackNeighbours > 0)
365                        token = token.substr(0, token.size() - fallBackNeighbours);
366                    fallBackNeighbours = 0;
367                    // FINISH
368                    if(bAllowEmptyEntries || token.size() > 0)
369                    {
370                        tokens.push_back(token);
371                        token.clear();
372                        bTokenInSafemode.push_back(inSafemode);
373                        inSafemode = false;
374                    }
375                    state = SL_NORMAL;
376                }
377                else
378                {
379                    if (delimiterNeighbours.find(line[i]) != std::string::npos)
380                    {
381                        if (token.size() > 0)
382                            ++fallBackNeighbours;
383                        else
384                        {
385                            ++i;
386                            continue;
387                        }
388                    }
389                    else
390                        fallBackNeighbours = 0;
391                    token += line[i];       // EAT
392                }
393                break;
394            case SL_ESCAPE:
395                if (!bRemoveSafemodeChar)
396                    token += line[i];
397                else
398                {
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                }
409                state = SL_NORMAL;
410                break;
411            case SL_SAFEMODE:
412                if(line[i] == safemodeChar)
413                {
414                    state = SL_NORMAL;
415                    if (!bRemoveSafemodeChar)
416                        token += line[i];
417                }
418                else if(line[i] == escapeChar)
419                {
420                    state = SL_SAFEESCAPE;
421                }
422                else
423                {
424                    token += line[i];       // EAT
425                }
426                break;
427
428            case SL_SAFEESCAPE:
429                if(line[i] == 'n') token += '\n';
430                else if(line[i] == 't') token += '\t';
431                else if(line[i] == 'v') token += '\v';
432                else if(line[i] == 'b') token += '\b';
433                else if(line[i] == 'r') token += '\r';
434                else if(line[i] == 'f') token += '\f';
435                else if(line[i] == 'a') token += '\a';
436                else if(line[i] == '?') token += '\?';
437                else token += line[i];  // EAT
438                state = SL_SAFEMODE;
439                break;
440
441            case SL_PARENTHESES:
442                if(line[i] == closeparenthesisChar)
443                {
444                    state = SL_NORMAL;
445                    if (!bRemoveParenthesisChars)
446                        token += line[i];
447                }
448                else if(line[i] == escapeChar)
449                {
450                    state = SL_PARENTHESESESCAPE;
451                }
452                else
453                {
454                    token += line[i];       // EAT
455                }
456                break;
457
458            case SL_PARENTHESESESCAPE:
459                if(line[i] == 'n') token += '\n';
460                else if(line[i] == 't') token += '\t';
461                else if(line[i] == 'v') token += '\v';
462                else if(line[i] == 'b') token += '\b';
463                else if(line[i] == 'r') token += '\r';
464                else if(line[i] == 'f') token += '\f';
465                else if(line[i] == 'a') token += '\a';
466                else if(line[i] == '?') token += '\?';
467                else token += line[i];  // EAT
468                state = SL_PARENTHESES;
469                break;
470
471            case SL_COMMENT:
472                if(line[i] == '\n')
473                {
474                    // FINISH
475                    if(token.size() > 0)
476                    {
477                        tokens.push_back(token);
478                        token.clear();
479                        bTokenInSafemode.push_back(inSafemode);
480                        inSafemode = false;
481                    }
482                    state = SL_NORMAL;
483                }
484                else
485                {
486                    token += line[i];       // EAT
487                }
488                break;
489
490            default:
491                // nothing
492                break;
493            }
494            ++i;
495        }
496
497        // FINISH
498        if (fallBackNeighbours > 0)
499            token = token.substr(0, token.size() - fallBackNeighbours);
500        if(bAllowEmptyEntries || token.size() > 0)
501        {
502            tokens.push_back(token);
503            token.clear();
504            bTokenInSafemode.push_back(inSafemode);
505            inSafemode = false;
506        }
507        return(state);
508    }
509
510    /**
511        @brief Some nice debug information about this SubString.
512    */
513    void SubString::debug() const
514    {
515        COUT(0) << "Substring-information::count=" << this->tokens_.size() << " ::";
516        for (unsigned int i = 0; i < this->tokens_.size(); ++i)
517            COUT(0) << "s" << i << "='" << this->tokens_[i].c_str() << "'::";
518        COUT(0) << std::endl;
519    }
520}
Note: See TracBrowser for help on using the repository browser.