Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7275 was 7165, checked in by landauf, 14 years ago

for some reason MinGW with gcc 4.5 needs some additional _UtilExport keywords
also fixed 2 warnings

  • 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            return "";
273    }
274
275
276    /**
277     * @brief creates a SubSet of a SubString.
278     * @param subSetBegin the beginning to the end
279     * @returns the SubSet
280     *
281     * This function is added for your convenience, and does the same as
282     * SubString::SubString(const SubString& subString, unsigned int subSetBegin)
283     */
284    SubString SubString::subSet(unsigned int subSetBegin) const
285    {
286        return SubString(*this, subSetBegin);
287    }
288
289
290    /**
291     * @brief creates a SubSet of a SubString.
292     * @param subSetBegin the beginning to
293     * @param subSetEnd the end of the SubSet to select (if bigger than subString.size() it will be downset.)
294     * @returns the SubSet
295     *
296     * This function is added for your convenience, and does the same as
297     * SubString::SubString(const SubString& subString, unsigned int subSetBegin)
298     */
299    SubString SubString::subSet(unsigned int subSetBegin, unsigned int subSetEnd) const
300    {
301        return SubString(*this, subSetBegin, subSetEnd);
302    }
303
304
305    /**
306     * @brief splits line into tokens and stores them in ret.
307     * @param ret the Array, where the Splitted strings will be stored in
308     * to the beginning of the current token is stored
309     * @param line the inputLine to split
310     * @param delimiters a String of Delimiters (here the input will be splitted)
311     * @param delimiterNeighbours Naighbours to the Delimitter, that will be removed if they are to the left or the right of a Delimiter.
312     * @param emptyEntries: if empty Strings are added to the List of Strings.
313     * @param escape_char: Escape carater (escapes splitters)
314     * @param safemode_char: the beginning of the safemode is marked with this
315     * @param removeSafemodeChar removes the safemode_char from the beginning and the ending of a token
316     * @param openparenthesis_char the beginning of a safemode is marked with this
317     * @param closeparenthesis_char the ending of a safemode is marked with this
318     * @param removeParenthesisChars removes the parenthesis from the beginning and the ending of a token
319     * @param comment_char: the beginning of a comment is marked with this: (until the end of a Line)
320     * @param start_state: the Initial state on how to parse the String.
321     * @return SPLIT_LINE_STATE the parser was in when returning
322     *
323     * This is the Actual Splitting Algorithm from Clemens Wacha
324     * Supports delimiters, escape characters,
325     * ignores special  characters between safemode_char and between comment_char and linend '\n'.
326     */
327    SubString::SPLIT_LINE_STATE
328    SubString::splitLine(std::vector<std::string>& ret,
329                         std::vector<bool>& bInSafemode,
330                         const std::string& line,
331                         const std::string& delimiters,
332                         const std::string& delimiterNeighbours,
333                         bool emptyEntries,
334                         char escape_char,
335                         bool removeExcapeChar,
336                         char safemode_char,
337                         bool removeSafemodeChar,
338                         char openparenthesis_char,
339                         char closeparenthesis_char,
340                         bool removeParenthesisChars,
341                         char comment_char,
342                         SPLIT_LINE_STATE start_state)
343    {
344        SPLIT_LINE_STATE state = start_state;
345        unsigned int i = 0;
346        unsigned int fallBackNeighbours = 0;
347
348        std::string token;
349        bool inSafemode = false;
350
351        if(start_state != SL_NORMAL && ret.size() > 0)
352        {
353            token = ret[ret.size()-1];
354            ret.pop_back();
355        }
356        if(start_state != SL_NORMAL && bInSafemode.size() > 0)
357        {
358            inSafemode = bInSafemode[bInSafemode.size()-1];
359            bInSafemode.pop_back();
360        }
361
362        while(i < line.size())
363        {
364            switch(state)
365            {
366            case SL_NORMAL:
367                if(line[i] == escape_char)
368                {
369                    state = SL_ESCAPE;
370                    if (!removeExcapeChar)
371                        token += line[i];
372                }
373                else if(line[i] == safemode_char)
374                {
375                    state = SL_SAFEMODE;
376                    inSafemode = true;
377                    if (!removeSafemodeChar)
378                        token += line[i];
379                }
380                else if(line[i] == openparenthesis_char)
381                {
382                    state = SL_PARENTHESES;
383                    inSafemode = true;
384                    if (!removeParenthesisChars)
385                        token += line[i];
386                }
387                else if(line[i] == comment_char)
388                {
389                    if (fallBackNeighbours > 0)
390                        token = token.substr(0, token.size() - fallBackNeighbours);
391                    /// FINISH
392                    if(emptyEntries || token.size() > 0)
393                    {
394                        ret.push_back(token);
395                        token.clear();
396                        bInSafemode.push_back(inSafemode);
397                        inSafemode = false;
398                    }
399                    token += line[i];       // EAT
400                    state = SL_COMMENT;
401                }
402                else if(delimiters.find(line[i]) != std::string::npos)
403                {
404                    // line[i] is a delimiter
405                    if (fallBackNeighbours > 0)
406                        token = token.substr(0, token.size() - fallBackNeighbours);
407                    /// FINISH
408                    if(emptyEntries || token.size() > 0)
409                    {
410                        ret.push_back(token);
411                        token.clear();
412                        bInSafemode.push_back(inSafemode);
413                        inSafemode = false;
414                    }
415                    state = SL_NORMAL;
416                }
417                else
418                {
419                    if (delimiterNeighbours.find(line[i]) != std::string::npos)
420                    {
421                        if (token.size() > 0)
422                            ++fallBackNeighbours;
423                        else
424                        {
425                            i++;
426                            continue;
427                        }
428                    }
429                    else
430                        fallBackNeighbours = 0;
431                    token += line[i];       // EAT
432                }
433                break;
434            case SL_ESCAPE:
435                if (!removeSafemodeChar)
436                    token += line[i];
437                else
438                {
439                    if(line[i] == 'n') token += '\n';
440                    else if(line[i] == 't') token += '\t';
441                    else if(line[i] == 'v') token += '\v';
442                    else if(line[i] == 'b') token += '\b';
443                    else if(line[i] == 'r') token += '\r';
444                    else if(line[i] == 'f') token += '\f';
445                    else if(line[i] == 'a') token += '\a';
446                    else if(line[i] == '?') token += '\?';
447                    else token += line[i];  // EAT
448                }
449                state = SL_NORMAL;
450                break;
451            case SL_SAFEMODE:
452                if(line[i] == safemode_char)
453                {
454                    state = SL_NORMAL;
455                    if (!removeSafemodeChar)
456                        token += line[i];
457                }
458                else if(line[i] == escape_char)
459                {
460                    state = SL_SAFEESCAPE;
461                }
462                else
463                {
464                    token += line[i];       // EAT
465                }
466                break;
467
468            case SL_SAFEESCAPE:
469                if(line[i] == 'n') token += '\n';
470                else if(line[i] == 't') token += '\t';
471                else if(line[i] == 'v') token += '\v';
472                else if(line[i] == 'b') token += '\b';
473                else if(line[i] == 'r') token += '\r';
474                else if(line[i] == 'f') token += '\f';
475                else if(line[i] == 'a') token += '\a';
476                else if(line[i] == '?') token += '\?';
477                else token += line[i];  // EAT
478                state = SL_SAFEMODE;
479                break;
480
481            case SL_PARENTHESES:
482                if(line[i] == closeparenthesis_char)
483                {
484                    state = SL_NORMAL;
485                    if (!removeParenthesisChars)
486                        token += line[i];
487                }
488                else if(line[i] == escape_char)
489                {
490                    state = SL_PARENTHESESESCAPE;
491                }
492                else
493                {
494                    token += line[i];       // EAT
495                }
496                break;
497
498            case SL_PARENTHESESESCAPE:
499                if(line[i] == 'n') token += '\n';
500                else if(line[i] == 't') token += '\t';
501                else if(line[i] == 'v') token += '\v';
502                else if(line[i] == 'b') token += '\b';
503                else if(line[i] == 'r') token += '\r';
504                else if(line[i] == 'f') token += '\f';
505                else if(line[i] == 'a') token += '\a';
506                else if(line[i] == '?') token += '\?';
507                else token += line[i];  // EAT
508                state = SL_PARENTHESES;
509                break;
510
511            case SL_COMMENT:
512                if(line[i] == '\n')
513                {
514                    /// FINISH
515                    if(token.size() > 0)
516                    {
517                        ret.push_back(token);
518                        token.clear();
519                        bInSafemode.push_back(inSafemode);
520                        inSafemode = false;
521                    }
522                    state = SL_NORMAL;
523                }
524                else
525                {
526                    token += line[i];       // EAT
527                }
528                break;
529
530            default:
531                // nothing
532                break;
533            }
534            i++;
535        }
536
537        /// FINISH
538        if (fallBackNeighbours > 0)
539            token = token.substr(0, token.size() - fallBackNeighbours);
540        if(emptyEntries || token.size() > 0)
541        {
542            ret.push_back(token);
543            token.clear();
544            bInSafemode.push_back(inSafemode);
545            inSafemode = false;
546        }
547        return(state);
548    }
549
550
551    /**
552     * @brief Some nice debug information about this SubString
553     */
554    void SubString::debug() const
555    {
556        printf("Substring-information::count=%d ::", this->strings.size());
557        for (unsigned int i = 0; i < this->strings.size(); i++)
558            printf("s%d='%s'::", i, this->strings[i].c_str());
559        printf("\n");
560    }
561}
Note: See TracBrowser for help on using the repository browser.