Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pch/src/util/String.cc @ 3163

Last change on this file since 3163 was 3146, checked in by rgrieder, 15 years ago

Found another few unnecessary includes in util (and added two others that followed due to this change).

  • Property svn:eol-style set to native
File size: 15.9 KB
RevLine 
[1505]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
[1791]29/**
[2171]30    @file
[1791]31    @brief Implementation of several string manipulation functions.
32*/
33
[1505]34#include "String.h"
35
36#include <cctype>
[2087]37#include "Convert.h"
38#include "Math.h"
[1625]39
[2171]40namespace orxonox
[2087]41{
[2171]42    std::string BLANKSTRING("");
[2087]43
[2171]44    std::string getUniqueNumberString()
45    {
46        return convertToString(getUniqueNumber());
47    }
[1505]48
[2171]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    }
[1505]63
[2171]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 = std::string(str);
72        strip(&output);
73        return output;
74    }
[1505]75
[2171]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;
[2662]84        int pos2 = (int)(str.size() - 1);
[2171]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    }
[1505]89
[2171]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)
[1505]97    {
[2171]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)
[1505]109                break;
[2171]110        }
[1505]111
[2171]112        return quote;
[1505]113    }
114
[2171]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)
[1505]122    {
[2171]123        if (pos == std::string::npos)
[1830]124            return false;
[1505]125
[2171]126        size_t quotecount = 0;
127        size_t quote = (size_t)-1;
128        while ((quote = getNextQuote(str, quote + 1)) < pos)
129        {
130            if (quote == pos)
131                return false;
132            quotecount++;
133        }
[1505]134
[2171]135        if (quote == std::string::npos)
136            return false;
[1505]137
[2171]138        return ((quotecount % 2) == 1);
139    }
[1505]140
[2171]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    }
[1505]152
[2171]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    }
[1505]167
[2171]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)
[1505]174    {
[2171]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++)
[1505]179        {
[2171]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;
[1505]188        }
189
[2171]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            }
[1505]197
[2171]198            if ((str[pos] != ' ') && (str[pos] != '\t') && (str[pos] != '\n'))
199                return str;
[1505]200        }
201
[2171]202        if ((start != std::string::npos) && (end != 0))
203            return str.substr(start + 1, end - start - 1);
204        else
[1505]205            return str;
206    }
207
[2171]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;
[1505]216
[2171]217        while (output.size() >= 2 && output[0] == '{' && output[output.size() - 1] == '}')
218            output = output.substr(1, output.size() - 2);
[1505]219
[2171]220        return output;
221    }
[1505]222
[2171]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
[1505]227
[2171]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        std::string teststring = getStripped(str);
[1505]234
[2171]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        }
[1505]250
[2171]251        return false;
[1505]252    }
[2171]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)
[1505]260    {
[2171]261        std::string temp = getStripped(str);
262        return ((temp == "") || (temp.size() == 0));
[1505]263    }
264
[2171]265    /**
266        @brief Determines if a string contains only numbers and maximal one '.'.
267        @param str The string to check
268        @return True = it's a number
269    */
270    bool isNumeric(const std::string& str)
271    {
272        bool foundPoint = false;
[1505]273
[2171]274        for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
[1505]275        {
[2171]276            if (((*it) < '0' || (*it) > '9'))
277            {
278                if ((*it) != '.' && !foundPoint)
279                    foundPoint = true;
280                else
281                    return false;
282            }
[1505]283        }
[2171]284
285        return true;
[1505]286    }
287
[2171]288    /**
289        @brief Adds backslashes to the given string which makes special chars visible. Existing slashes will be doubled.
290        @param str The string to manipulate
291        @return The string with added slashes
292    */
293    std::string addSlashes(const std::string& str)
294    {
295        std::string output = str;
[1505]296
[2171]297        for (size_t pos = 0; (pos = output.find('\\', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\\\"); }
298        for (size_t pos = 0; (pos = output.find('\n', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\n"); }
299        for (size_t pos = 0; (pos = output.find('\t', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\t"); }
300        for (size_t pos = 0; (pos = output.find('\v', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\v"); }
301        for (size_t pos = 0; (pos = output.find('\b', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\b"); }
302        for (size_t pos = 0; (pos = output.find('\r', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\r"); }
303        for (size_t pos = 0; (pos = output.find('\f', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\f"); }
304        for (size_t pos = 0; (pos = output.find('\a', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\a"); }
305        for (size_t pos = 0; (pos = output.find('"', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\\""); }
306        for (size_t pos = 0; (pos = output.find('\0', pos)) < std::string::npos; pos += 2) { output.replace(pos, 1, "\\0"); }
[1505]307
[2171]308        return output;
309    }
[1505]310
[2171]311    /**
312        @brief Removes backslashes from the given string. Double backslashes are interpreted as one backslash.
313        @param str The string to manipulate
314        @return The string with removed slashes
315    */
316    std::string removeSlashes(const std::string& str)
317    {
318        if (str.size() <= 1)
319            return str;
[1505]320
[2171]321        std::string output = "";
322        for (size_t pos = 0; pos < str.size() - 1; )
323        {
324            if (str[pos] == '\\')
325            {
326                if (str[pos + 1] == '\\') { output += '\\'; pos += 2; continue; }
327                else if (str[pos + 1] == 'n') { output += '\n'; pos += 2; continue; }
328                else if (str[pos + 1] == 't') { output += '\t'; pos += 2; continue; }
329                else if (str[pos + 1] == 'v') { output += '\v'; pos += 2; continue; }
330                else if (str[pos + 1] == 'b') { output += '\b'; pos += 2; continue; }
331                else if (str[pos + 1] == 'r') { output += '\r'; pos += 2; continue; }
332                else if (str[pos + 1] == 'f') { output += '\f'; pos += 2; continue; }
333                else if (str[pos + 1] == 'a') { output += '\a'; pos += 2; continue; }
334                else if (str[pos + 1] == '"') { output += '"'; pos += 2; continue; }
335                else if (str[pos + 1] == '0') { output += '\0'; pos += 2; continue; }
336            }
337            output += str[pos];
338            pos++;
339            if (pos == str.size() - 1)
340                output += str[pos];
341        }
[1505]342
[2171]343        return output;
344    }
345
346    /**
347        @brief Replaces each char between A and Z with its lowercase equivalent.
348        @param str The string to convert
349    */
350    void lowercase(std::string* str)
[1505]351    {
[2171]352        for (size_t i = 0; i < str->size(); ++i)
[1505]353        {
[2171]354            (*str)[i] = (char)tolower((*str)[i]);
[1505]355        }
356    }
357
[2171]358    /**
359        @brief Returns a copy of the given string without uppercase chars.
360        @param str The string
361        @return The copy
362    */
363    std::string getLowercase(const std::string& str)
364    {
365        std::string output = std::string(str);
366        lowercase(&output);
367        return output;
368    }
[1505]369
[2171]370    /**
371        @brief Replaces each char between a and z with its uppercase equivalent.
372        @param str The string to convert
373    */
374    void uppercase(std::string* str)
[1505]375    {
[2171]376        for (size_t i = 0; i < str->size(); ++i)
377        {
378            (*str)[i] = (char)toupper((*str)[i]);
379        }
[1505]380    }
381
[2171]382    /**
383        @brief Returns a copy of the given string without lowercase chars.
384        @param str The string
385        @return The copy
386    */
387    std::string getUppercase(const std::string& str)
388    {
389        std::string output = std::string(str);
390        uppercase(&output);
391        return output;
392    }
[1505]393
[2171]394    /**
395        @brief Compares two strings ignoring different casing.
396        @param s1 First string
397        @param s2 Second string
398    */
399    int nocaseCmp(const std::string& s1, const std::string& s2)
[1505]400    {
[2171]401        std::string::const_iterator it1=s1.begin();
402        std::string::const_iterator it2=s2.begin();
403
404        //stop when either string's end has been reached
405        while ( (it1!=s1.end()) && (it2!=s2.end()) )
406        {
407            if(::toupper(*it1) != ::toupper(*it2)) //letters differ?
408                // return -1 to indicate smaller than, 1 otherwise
409                return (::toupper(*it1)  < ::toupper(*it2)) ? -1 : 1;
410            //proceed to the next character in each string
411            ++it1;
412            ++it2;
413        }
414        size_t size1=s1.size(), size2=s2.size();// cache lengths
415        //return -1,0 or 1 according to strings' lengths
416        if (size1==size2)
417            return 0;
418        return (size1<size2) ? -1 : 1;
[1505]419    }
420
421
[2171]422    /**
423        @brief Compares the first 'len' chars of two strings ignoring different casing.
424        @param s1 First string
425        @param s2 Second string
426        @param len Maximal number of chars to compare
427    */
428    int nocaseCmp(const std::string& s1, const std::string& s2, size_t len)
[1505]429    {
[2171]430        if (len == 0)
431            return 0;
432        std::string::const_iterator it1=s1.begin();
433        std::string::const_iterator it2=s2.begin();
[1505]434
[2171]435        //stop when either string's end has been reached
436        while ( (it1!=s1.end()) && (it2!=s2.end()) && len-- > 0)
437        {
438            if(::toupper(*it1) != ::toupper(*it2)) //letters differ?
439                // return -1 to indicate smaller than, 1 otherwise
440                return (::toupper(*it1)  < ::toupper(*it2)) ? -1 : 1;
441            //proceed to the next character in each string
442            ++it1;
443            ++it2;
444        }
[1505]445        return 0;
[2171]446    }
[1505]447
[2171]448    /**
449        @brief Returns true if the string contains a comment, introduced by #, %, ; or //.
450        @param str The string
451        @return True if the string contains a comment
452    */
453    bool hasComment(const std::string& str)
[1505]454    {
[2171]455        return (getCommentPosition(str) != std::string::npos);
[1505]456    }
457
[2171]458    /**
459        @brief If the string contains a comment, the comment gets returned (including the comment symbol), an empty string otherwise.
460        @param str The string
461        @return The comment
462    */
463    std::string getComment(const std::string& str)
464    {
465        return str.substr(getCommentPosition(str));
466    }
[1505]467
[2171]468    /**
469        @brief If the string contains a comment, the position of the comment-symbol gets returned, std::string::npos otherwise.
470        @param str The string
471        @return The position
472    */
473    size_t getCommentPosition(const std::string& str)
474    {
475        return getNextCommentPosition(str, 0);
476    }
[1505]477
[2171]478    /**
479        @brief Returns the position of the next comment-symbol, starting with start.
480        @param str The string
481        @param start The startposition
482        @return The position
483    */
484    size_t getNextCommentPosition(const std::string& str, size_t start)
485    {
486        for (size_t i = start; i < str.size(); i++)
487            if (isComment(str.substr(i)))
488                return i;
[1505]489
[2171]490        return std::string::npos;
491    }
[1505]492}
Note: See TracBrowser for help on using the repository browser.