Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core4/src/util/StringUtils.cc @ 3250

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

Executing decision on #300: Renaming String.h to StringUtils.h (String.h doesn't exactly suggest you would find utilities for string manipulations there).

  • 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
[3250]34#include "StringUtils.h"
[1505]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.