Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/util/StringUtils.cc @ 8366

Last change on this file since 8366 was 8232, checked in by dafrick, 14 years ago

Extending and reorganizing ScreenshotManager and SkyboxGenerator.
The SkyboxGenerator now takes HD screenshots, thus the size of the faces generated by the SkyboxGenerator can now be specified freely (through a config value).

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