Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/weapon2/src/util/String.cc @ 2731

Last change on this file since 2731 was 2087, checked in by landauf, 16 years ago

merged objecthierarchy branch back to trunk

  • Property svn:eol-style set to native
File size: 14.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 String.cc
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
42std::string BLANKSTRING("");
43
44std::string getUniqueNumberString()
45{
46    return convertToString(getUniqueNumber());
47}
48
49/**
50    @brief Removes all whitespaces from a string.
51    @param str The string to strip
52*/
53void 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}
63
64/**
65    @brief Returns a copy of a string without whitespaces.
66    @param str The string to strip
67    @return The stripped line
68*/
69std::string getStripped(const std::string& str)
70{
71    std::string output = std::string(str);
72    strip(&output);
73    return output;
74}
75
76/**
77    @brief Returns a copy of a string without trailing whitespaces.
78    @param str The string
79    @return The modified copy
80*/
81std::string removeTrailingWhitespaces(const std::string& str)
82{
83    size_t pos1 = 0;
84    int pos2 = str.size() - 1;
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}
89
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*/
96size_t getNextQuote(const std::string& str, size_t start)
97{
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)
109            break;
110    }
111
112    return quote;
113}
114
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*/
121bool isBetweenQuotes(const std::string& str, size_t pos)
122{
123    if (pos == std::string::npos)
124        return false;
125
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    }
134
135    if (quote == std::string::npos)
136        return false;
137
138    return ((quotecount % 2) == 1);
139}
140
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*/
146bool 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}
152
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*/
158std::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    @brief str The string to strip
171    @return The string with removed quotes
172*/
173std::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*/
213std::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*/
230bool isComment(const std::string& str)
231{
232    // Strip the line, whitespaces are disturbing
233    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*/
259bool isEmpty(const std::string& str)
260{
261    std::string temp = getStripped(str);
262    return ((temp == "") || (temp.size() == 0));
263}
264
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*/
270bool isNumeric(const std::string& str)
271{
272    bool foundPoint = false;
273
274    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
275    {
276        if (((*it) < '0' || (*it) > '9'))
277        {
278            if ((*it) != '.' && !foundPoint)
279                foundPoint = true;
280            else
281                return false;
282        }
283    }
284
285    return true;
286}
287
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*/
293std::string addSlashes(const std::string& str)
294{
295    std::string output = str;
296
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"); }
307
308    return output;
309}
310
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*/
316std::string removeSlashes(const std::string& str)
317{
318    if (str.size() <= 1)
319        return str;
320
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    }
342
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*/
350void lowercase(std::string* str)
351{
352    for (size_t i = 0; i < str->size(); ++i)
353    {
354        (*str)[i] = (char)tolower((*str)[i]);
355    }
356}
357
358/**
359    @brief Returns a copy of the given string without uppercase chars.
360    @param str The string
361    @return The copy
362*/
363std::string getLowercase(const std::string& str)
364{
365    std::string output = std::string(str);
366    lowercase(&output);
367    return output;
368}
369
370/**
371    @brief Replaces each char between a and z with its uppercase equivalent.
372    @param str The string to convert
373*/
374void uppercase(std::string* str)
375{
376    for (size_t i = 0; i < str->size(); ++i)
377    {
378        (*str)[i] = (char)toupper((*str)[i]);
379    }
380}
381
382/**
383    @brief Returns a copy of the given string without lowercase chars.
384    @param str The string
385    @return The copy
386*/
387std::string getUppercase(const std::string& str)
388{
389    std::string output = std::string(str);
390    uppercase(&output);
391    return output;
392}
393
394/**
395    @brief Compares two strings ignoring different casing.
396    @param s1 First string
397    @param s2 Second string
398*/
399int nocaseCmp(const std::string& s1, const std::string& s2)
400{
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;
419}
420
421
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*/
428int nocaseCmp(const std::string& s1, const std::string& s2, size_t len)
429{
430    if (len == 0)
431        return 0;
432    std::string::const_iterator it1=s1.begin();
433    std::string::const_iterator it2=s2.begin();
434
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    }
445    return 0;
446}
447
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*/
453bool hasComment(const std::string& str)
454{
455    return (getCommentPosition(str) != std::string::npos);
456}
457
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*/
463std::string getComment(const std::string& str)
464{
465    return str.substr(getCommentPosition(str));
466}
467
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*/
473size_t getCommentPosition(const std::string& str)
474{
475    return getNextCommentPosition(str, 0);
476}
477
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*/
484size_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;
489
490    return std::string::npos;
491}
Note: See TracBrowser for help on using the repository browser.