Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gamestate/src/libraries/util/StringUtils.cc @ 7023

Last change on this file since 7023 was 6424, checked in by rgrieder, 15 years ago

Fixed a bug in removeSlashes: An escape sequence at the third and second to last position was not handled correctly. Example: "
aa" was transformed to "\a" instead of "\aa"
Also almost doubled removeSlashes and removeSlashes performance.

  • Property svn:eol-style set to native
File size: 16.0 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 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      Benjamin Grauer
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of several string manipulation functions.
32*/
33
34#include "StringUtils.h"
35
36#include <cctype>
37#include "Convert.h"
38#include "Math.h"
39
40namespace orxonox
41{
42    std::string BLANKSTRING;
43
44    std::string getUniqueNumberString()
45    {
46        return multi_cast<std::string>(getUniqueNumber());
47    }
48
49    /**
50        @brief Removes all whitespaces from a string.
51        @param str The string to strip
52    */
53    void strip(std::string* str)
54    {
55        size_t pos;
56        while ((pos = str->find(' ')) < str->length())
57            str->erase(pos, 1);
58        while ((pos = str->find('\t')) < str->length())
59            str->erase(pos, 1);
60        while ((pos = str->find('\n')) < str->length())
61            str->erase(pos, 1);
62    }
63
64    /**
65        @brief Returns a copy of a string without whitespaces.
66        @param str The string to strip
67        @return The stripped line
68    */
69    std::string getStripped(const std::string& str)
70    {
71        std::string output(str);
72        strip(&output);
73        return output;
74    }
75
76    /**
77        @brief Returns a copy of a string without trailing whitespaces.
78        @param str The string
79        @return The modified copy
80    */
81    std::string removeTrailingWhitespaces(const std::string& str)
82    {
83        size_t pos1 = 0;
84        int pos2 = static_cast<int>(str.size() - 1);
85        for (; pos1 < str.size() && (str[pos1] == ' ' || str[pos1] == '\t' || str[pos1] == '\n'); pos1++);
86        for (; pos2 > 0         && (str[pos2] == ' ' || str[pos2] == '\t' || str[pos2] == '\n'); pos2--);
87        return str.substr(pos1, pos2 - pos1 + 1);
88    }
89
90    /**
91        @brief Returns the position of the next quote in the string, starting with start.
92        @param str The string
93        @param start The startposition
94        @return The position of the next quote (std::string::npos if there is no next quote)
95    */
96    size_t getNextQuote(const std::string& str, size_t start)
97    {
98        size_t quote = start - 1;
99
100        while ((quote = str.find('"', quote + 1)) != std::string::npos)
101        {
102            size_t backslash = quote;
103            size_t numbackslashes = 0;
104            for (; backslash > 0; backslash--, numbackslashes++)
105                if (str[backslash - 1] != '\\')
106                    break;
107
108            if (numbackslashes % 2 == 0)
109                break;
110        }
111
112        return quote;
113    }
114
115    /**
116        @brief Returns true if pos is between two quotes.
117        @param str The string
118        @param pos The position to check
119        @return True if pos is between two quotes
120    */
121    bool isBetweenQuotes(const std::string& str, size_t pos)
122    {
123        if (pos == std::string::npos)
124            return false;
125
126        size_t quotecount = 0;
127        size_t quote = static_cast<size_t>(-1);
128        while ((quote = getNextQuote(str, quote + 1)) < pos)
129        {
130            if (quote == pos)
131                return false;
132            quotecount++;
133        }
134
135        if (quote == std::string::npos)
136            return false;
137
138        return ((quotecount % 2) == 1);
139    }
140
141    /**
142        @brief Returns true if the string contains something like '..."between quotes"...'.
143        @param The string
144        @return True if there is something between quotes
145    */
146    bool hasStringBetweenQuotes(const std::string& str)
147    {
148        size_t pos1 = getNextQuote(str, 0);
149        size_t pos2 = getNextQuote(str, pos1 + 1);
150        return (pos1 != std::string::npos && pos2 != std::string::npos && pos2 > pos1 + 1);
151    }
152
153    /**
154        @brief If the string contains something like '..."between quotes"...' then 'between quotes' gets returned (without quotes).
155        @param The string
156        @param The string between the quotes
157    */
158    std::string getStringBetweenQuotes(const std::string& str)
159    {
160        size_t pos1 = getNextQuote(str, 0);
161        size_t pos2 = getNextQuote(str, pos1 + 1);
162        if (pos1 != std::string::npos && pos2 != std::string::npos)
163            return str.substr(pos1, pos2 - pos1 + 1);
164        else
165            return "";
166    }
167
168    /**
169        @brief Removes enclosing quotes if available (including whitespaces at the outside of the quotes).
170        @brief str The string to strip
171        @return The string with removed quotes
172    */
173    std::string stripEnclosingQuotes(const std::string& str)
174    {
175        size_t start = std::string::npos;
176        size_t end = 0;
177
178        for (size_t pos = 0; (pos < str.size()) && (pos < std::string::npos); pos++)
179        {
180            if (str[pos] == '"')
181            {
182                start = pos;
183                break;
184            }
185
186            if ((str[pos] != ' ') && (str[pos] != '\t') && (str[pos] != '\n'))
187                return str;
188        }
189
190        for (size_t pos = str.size() - 1; pos < std::string::npos; pos--)
191        {
192            if (str[pos] == '"')
193            {
194                end = pos;
195                break;
196            }
197
198            if ((str[pos] != ' ') && (str[pos] != '\t') && (str[pos] != '\n'))
199                return str;
200        }
201
202        if ((start != std::string::npos) && (end != 0))
203            return str.substr(start + 1, end - start - 1);
204        else
205            return str;
206    }
207
208    /**
209        @brief Removes enclosing {braces} (braces must be exactly on the beginning and the end of the string).
210        @param str The string to strip
211        @return The striped string
212    */
213    std::string stripEnclosingBraces(const std::string& str)
214    {
215        std::string output = str;
216
217        while (output.size() >= 2 && output[0] == '{' && output[output.size() - 1] == '}')
218            output = output.substr(1, output.size() - 2);
219
220        return output;
221    }
222
223    /**
224        @brief Determines if a string is a comment (starts with a comment-symbol).
225        @param str The string to check
226        @return True = it's a comment
227
228        A comment is defined by a leading '#', '%', ';' or '//'.
229    */
230    bool isComment(const std::string& str)
231    {
232        // Strip the line, whitespaces are disturbing
233        const std::string& teststring = getStripped(str);
234
235        // There are four possible comment-symbols:
236        //  1) #comment in script-language style
237        //  2) %comment in matlab style
238        //  3) ;comment in unreal tournament config-file style
239        //  4) //comment in code style
240        if (teststring.size() >= 2)
241        {
242            if (teststring[0] == '#' || teststring[0] == '%' || teststring[0] == ';' || (teststring[0] == '/' && teststring[1] == '/'))
243                return true;
244        }
245        else if (teststring.size() == 1)
246        {
247            if (teststring[0] == '#' || teststring[0] == '%' || teststring[0] == ';')
248                return true;
249        }
250
251        return false;
252    }
253
254    /**
255        @brief Determines if a string is empty (contains only whitespaces).
256        @param str The string to check
257        @return True = it's empty
258    */
259    bool isEmpty(const std::string& str)
260    {
261        return getStripped(str).empty();
262    }
263
264    /**
265        @brief Determines if a string contains only numbers and maximal one '.'.
266        @param str The string to check
267        @return True = it's a number
268    */
269    bool isNumeric(const std::string& str)
270    {
271        bool foundPoint = false;
272
273        for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
274        {
275            if (((*it) < '0' || (*it) > '9'))
276            {
277                if ((*it) != '.' && !foundPoint)
278                    foundPoint = true;
279                else
280                    return false;
281            }
282        }
283
284        return true;
285    }
286
287    /**
288        @brief Adds backslashes to the given string which makes special chars visible. Existing slashes will be doubled.
289        @param str The string to manipulate
290        @return The string with added slashes
291    */
292    std::string addSlashes(const std::string& str)
293    {
294        std::string output(str.size() * 2, ' ');
295        size_t i = 0;
296        for (size_t pos = 0; pos < str.size(); ++pos)
297        {
298            switch (str[pos])
299            {
300            case '\\': output[i] = '\\'; output[i + 1] = '\\'; break;
301            case '\n': output[i] = '\\'; output[i + 1] =  'n'; break;
302            case '\t': output[i] = '\\'; output[i + 1] =  't'; break;
303            case '\v': output[i] = '\\'; output[i + 1] =  'v'; break;
304            case '\b': output[i] = '\\'; output[i + 1] =  'b'; break;
305            case '\r': output[i] = '\\'; output[i + 1] =  'r'; break;
306            case '\f': output[i] = '\\'; output[i + 1] =  'f'; break;
307            case '\a': output[i] = '\\'; output[i + 1] =  'a'; break;
308            case  '"': output[i] = '\\'; output[i + 1] =  '"'; break;
309            case '\0': output[i] = '\\'; output[i + 1] =  '0'; break;
310            default  : output[i] = str[pos]; ++i; continue;
311            }
312            i += 2;
313        }
314        output.resize(i);
315
316        return output;
317    }
318
319    /**
320        @brief Removes backslashes from the given string. Double backslashes are interpreted as one backslash.
321        @param str The string to manipulate
322        @return The string with removed slashes
323    */
324    std::string removeSlashes(const std::string& str)
325    {
326        if (str.size() <= 1)
327            return str;
328
329        std::string output(str.size(), ' ');
330        size_t i = 0;
331        size_t pos = 0;
332        while (pos < str.size() - 1)
333        {
334            if (str[pos] == '\\')
335            {
336                switch (str[pos + 1])
337                {
338                case '\\': output[i] = '\\'; break;
339                case  'n': output[i] = '\n'; break;
340                case  't': output[i] = '\t'; break;
341                case  'v': output[i] = '\v'; break;
342                case  'b': output[i] = '\b'; break;
343                case  'r': output[i] = '\r'; break;
344                case  'f': output[i] = '\f'; break;
345                case  'a': output[i] = '\a'; break;
346                case  '"': output[i] =  '"'; break;
347                case  '0': output[i] = '\0'; break;
348                default: ++pos; continue;
349                }
350                pos += 2; ++i;
351            }
352            else
353                output[i++] = str[pos++];
354        }
355        if (pos < str.size())
356            output[i++] = str[pos];
357        output.resize(i);
358
359        return output;
360    }
361
362    /**
363        @brief Replaces each char between A and Z with its lowercase equivalent.
364        @param str The string to convert
365    */
366    void lowercase(std::string* str)
367    {
368        for (size_t i = 0; i < str->size(); ++i)
369        {
370            (*str)[i] = static_cast<char>(tolower((*str)[i]));
371        }
372    }
373
374    /**
375        @brief Returns a copy of the given string without uppercase chars.
376        @param str The string
377        @return The copy
378    */
379    std::string getLowercase(const std::string& str)
380    {
381        std::string output(str);
382        lowercase(&output);
383        return output;
384    }
385
386    /**
387        @brief Replaces each char between a and z with its uppercase equivalent.
388        @param str The string to convert
389    */
390    void uppercase(std::string* str)
391    {
392        for (size_t i = 0; i < str->size(); ++i)
393        {
394            (*str)[i] = static_cast<char>(toupper((*str)[i]));
395        }
396    }
397
398    /**
399        @brief Returns a copy of the given string without lowercase chars.
400        @param str The string
401        @return The copy
402    */
403    std::string getUppercase(const std::string& str)
404    {
405        std::string output(str);
406        uppercase(&output);
407        return output;
408    }
409
410    /**
411        @brief Compares two strings ignoring different casing.
412        @param s1 First string
413        @param s2 Second string
414    */
415    int nocaseCmp(const std::string& s1, const std::string& s2)
416    {
417        std::string::const_iterator it1=s1.begin();
418        std::string::const_iterator it2=s2.begin();
419
420        //stop when either string's end has been reached
421        while ( (it1!=s1.end()) && (it2!=s2.end()) )
422        {
423            if(::toupper(*it1) != ::toupper(*it2)) //letters differ?
424                // return -1 to indicate smaller than, 1 otherwise
425                return (::toupper(*it1)  < ::toupper(*it2)) ? -1 : 1;
426            //proceed to the next character in each string
427            ++it1;
428            ++it2;
429        }
430        size_t size1=s1.size(), size2=s2.size();// cache lengths
431        //return -1,0 or 1 according to strings' lengths
432        if (size1==size2)
433            return 0;
434        return (size1<size2) ? -1 : 1;
435    }
436
437
438    /**
439        @brief Compares the first 'len' chars of two strings ignoring different casing.
440        @param s1 First string
441        @param s2 Second string
442        @param len Maximal number of chars to compare
443    */
444    int nocaseCmp(const std::string& s1, const std::string& s2, size_t len)
445    {
446        if (len == 0)
447            return 0;
448        std::string::const_iterator it1=s1.begin();
449        std::string::const_iterator it2=s2.begin();
450
451        //stop when either string's end has been reached
452        while ( (it1!=s1.end()) && (it2!=s2.end()) && len-- > 0)
453        {
454            if(::toupper(*it1) != ::toupper(*it2)) //letters differ?
455                // return -1 to indicate smaller than, 1 otherwise
456                return (::toupper(*it1)  < ::toupper(*it2)) ? -1 : 1;
457            //proceed to the next character in each string
458            ++it1;
459            ++it2;
460        }
461        return 0;
462    }
463
464    /**
465        @brief Returns true if the string contains a comment, introduced by #, %, ; or //.
466        @param str The string
467        @return True if the string contains a comment
468    */
469    bool hasComment(const std::string& str)
470    {
471        return (getCommentPosition(str) != std::string::npos);
472    }
473
474    /**
475        @brief If the string contains a comment, the comment gets returned (including the comment symbol), an empty string otherwise.
476        @param str The string
477        @return The comment
478    */
479    std::string getComment(const std::string& str)
480    {
481        return str.substr(getCommentPosition(str));
482    }
483
484    /**
485        @brief If the string contains a comment, the position of the comment-symbol gets returned, std::string::npos otherwise.
486        @param str The string
487        @return The position
488    */
489    size_t getCommentPosition(const std::string& str)
490    {
491        return getNextCommentPosition(str, 0);
492    }
493
494    /**
495        @brief Returns the position of the next comment-symbol, starting with start.
496        @param str The string
497        @param start The startposition
498        @return The position
499    */
500    size_t getNextCommentPosition(const std::string& str, size_t start)
501    {
502        for (size_t i = start; i < str.size(); i++)
503            if (isComment(str.substr(i)))
504                return i;
505
506        return std::string::npos;
507    }
508
509    /**
510        @brief Replaces individual charaters
511        @param str String to be manipulated
512        @param target Character to be replaced
513        @param replacement Replacement character
514        @return Number of replacements
515    */
516    _UtilExport size_t replaceCharacters(std::string& str, char target, char replacement)
517    {
518        size_t j = 0;
519        for (size_t i = 0; i < str.size(); ++i)
520        {
521            if (str[i] == target)
522            {
523                str[i] = replacement;
524                ++j;
525            }
526        }
527        return j;
528    }
529}
Note: See TracBrowser for help on using the repository browser.