Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/doc/src/libraries/util/StringUtils.cc @ 7297

Last change on this file since 7297 was 7297, checked in by landauf, 14 years ago

fixed lots of Doxygen warnings

Note: Doxygen prints a warning if only a part of the parameters of a function are documented.

Added documentation for missing parameters (as good as I could), removed documentation of obsolete parameters and fixed names of renamed parameters.
Some parameters are tagged with "FIXME", please replace this with an appropriate documentation if you know what it does.

  • Property svn:eol-style set to native
File size: 17.4 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 <boost/scoped_array.hpp>
38#include "Convert.h"
39#include "Math.h"
40
41namespace orxonox
42{
43    std::string BLANKSTRING;
44
45    std::string getUniqueNumberString()
46    {
47        return multi_cast<std::string>(getUniqueNumber());
48    }
49
50    /**
51        @brief Removes all whitespaces from a string.
52        @param str The string to strip
53    */
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    /**
66        @brief Returns a copy of a string without whitespaces.
67        @param str The string to strip
68        @return The stripped line
69    */
70    std::string getStripped(const std::string& str)
71    {
72        std::string output(str);
73        strip(&output);
74        return output;
75    }
76
77    /**
78        @brief Returns a copy of a string without trailing whitespaces.
79        @param str The string
80        @return The modified copy
81    */
82    std::string removeTrailingWhitespaces(const std::string& str)
83    {
84        size_t pos1 = 0;
85        int pos2 = static_cast<int>(str.size() - 1);
86        for (; pos1 < str.size() && (str[pos1] == ' ' || str[pos1] == '\t' || str[pos1] == '\n'); pos1++);
87        for (; pos2 > 0         && (str[pos2] == ' ' || str[pos2] == '\t' || str[pos2] == '\n'); pos2--);
88        return str.substr(pos1, pos2 - pos1 + 1);
89    }
90
91    /**
92        @brief Returns the position of the next quote in the string, starting with start.
93        @param str The string
94        @param start The startposition
95        @return The position of the next quote (std::string::npos if there is no next quote)
96    */
97    size_t getNextQuote(const std::string& str, size_t start)
98    {
99        size_t quote = start - 1;
100
101        while ((quote = str.find('"', quote + 1)) != std::string::npos)
102        {
103            size_t backslash = quote;
104            size_t numbackslashes = 0;
105            for (; backslash > 0; backslash--, numbackslashes++)
106                if (str[backslash - 1] != '\\')
107                    break;
108
109            if (numbackslashes % 2 == 0)
110                break;
111        }
112
113        return quote;
114    }
115
116    /**
117        @brief Returns true if pos is between two quotes.
118        @param str The string
119        @param pos The position to check
120        @return True if pos is between two quotes
121    */
122    bool isBetweenQuotes(const std::string& str, size_t pos)
123    {
124        if (pos == std::string::npos)
125            return false;
126
127        size_t quotecount = 0;
128        size_t quote = static_cast<size_t>(-1);
129        while ((quote = getNextQuote(str, quote + 1)) < pos)
130        {
131            if (quote == pos)
132                return false;
133            quotecount++;
134        }
135
136        if (quote == std::string::npos)
137            return false;
138
139        return ((quotecount % 2) == 1);
140    }
141
142    /**
143        @brief Returns true if the string contains something like '..."between quotes"...'.
144        @param str The string
145        @return True if there is something between quotes
146    */
147    bool hasStringBetweenQuotes(const std::string& str)
148    {
149        size_t pos1 = getNextQuote(str, 0);
150        size_t pos2 = getNextQuote(str, pos1 + 1);
151        return (pos1 != std::string::npos && pos2 != std::string::npos && pos2 > pos1 + 1);
152    }
153
154    /**
155        @brief If the string contains something like '..."between quotes"...' then 'between quotes' gets returned (without quotes).
156        @param str 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        @param 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    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
530    /**
531        @brief Calculates the Levenshtein distance between two strings.
532
533        The Levenshtein distance is defined by the number of transformations needed to convert str1
534        into str2. Possible transformations are substituted, added, or removed characters.
535    */
536    unsigned int getLevenshteinDistance(const std::string& str1, const std::string& str2)
537    {
538        size_t cols = str1.size() + 1;
539        size_t rows = str2.size() + 1;
540        boost::scoped_array<int> matrix(new int[rows * cols]);
541
542        for (size_t r = 0; r < rows; ++r)
543            for (size_t c = 0; c < cols; ++c)
544                matrix[r*cols + c] = 0;
545
546        for (size_t i = 1; i < cols; ++i)
547            matrix[0*cols + i] = i;
548        for (size_t i = 1; i < rows; ++i)
549            matrix[i*cols + 0] = i;
550
551        for (size_t r = 1; r < rows; ++r)
552            for (size_t c = 1; c < cols; ++c)
553                matrix[r*cols + c] = (str1[c-1] != str2[r-1]);
554
555        for (size_t r = 1; r < rows; ++r)
556            for (size_t c = 1; c < cols; ++c)
557                matrix[r*cols + c] = std::min(std::min(matrix[(r-1)*cols + c] + 1,
558                                                       matrix[r*cols + c-1] + 1),
559                                              matrix[(r-1)*cols + c-1] + (str1[c-1] != str2[r-1]));
560
561        return matrix[(rows-1)*cols + cols-1];
562    }
563}
Note: See TracBrowser for help on using the repository browser.