Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/netp6/src/util/SubString.cc @ 4317

Last change on this file since 4317 was 3196, checked in by rgrieder, 15 years ago

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