Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/util/SubString.cc @ 3016

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

merged revisions 2111-2170 from objecthierarchy branch back to trunk.

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