Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/util/String.cc @ 2036

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