Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ggz/src/util/String.cc @ 2871

Last change on this file since 2871 was 2662, checked in by rgrieder, 16 years ago

Merged presentation branch back to trunk.

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