Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy/src/util/String.cc @ 2019

Last change on this file since 2019 was 2019, checked in by landauf, 17 years ago

many changes, most important: BaseObject takes now a pointer to it's creator which is needed to build a level hierarchy (with different scenes)

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