1 /*-------------------------------------------------------------------------
2 * drawElements C++ Base Library
3 * -----------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief String utilities.
22 *//*--------------------------------------------------------------------*/
23
24 #include "deStringUtil.hpp"
25 #include "deString.h"
26
27 #include <algorithm>
28 #include <iterator>
29 #include <sstream>
30 #include <locale>
31 #include <iomanip>
32 #include <cctype>
33
34 using std::istream_iterator;
35 using std::istringstream;
36 using std::locale;
37 using std::string;
38 using std::vector;
39
40 namespace de
41 {
42 namespace
43 {
44
45 // Always use locale::classic to ensure consistent behavior in all environments.
46
47 struct ToLower
48 {
49 const locale &loc;
ToLowerde::__anonf879c5c90111::ToLower50 ToLower(void) : loc(locale::classic())
51 {
52 }
operator ()de::__anonf879c5c90111::ToLower53 char operator()(char c)
54 {
55 return std::tolower(c, loc);
56 }
57 };
58
59 struct ToUpper
60 {
61 const locale &loc;
ToUpperde::__anonf879c5c90111::ToUpper62 ToUpper(void) : loc(locale::classic())
63 {
64 }
operator ()de::__anonf879c5c90111::ToUpper65 char operator()(char c)
66 {
67 return std::toupper(c, loc);
68 }
69 };
70
71 } // namespace
72
73 //! Convert string to lowercase using the classic "C" locale
toLower(const string & str)74 string toLower(const string &str)
75 {
76 string ret;
77 std::transform(str.begin(), str.end(), std::inserter(ret, ret.begin()), ToLower());
78 return ret;
79 }
80
81 //! Convert string to uppercase using the classic "C" locale
toUpper(const string & str)82 string toUpper(const string &str)
83 {
84 string ret;
85 std::transform(str.begin(), str.end(), std::inserter(ret, ret.begin()), ToUpper());
86 return ret;
87 }
88
89 //! Convert string's first character to uppercase using the classic "C" locale
capitalize(const string & str)90 string capitalize(const string &str)
91 {
92 if (str.empty())
93 return str;
94 return ToUpper()(str[0]) + str.substr(1);
95 }
96
97 //! Split a string into tokens. If `delim` is `'\0'`, separate by spans of
98 //! whitespace. Otherwise use a single character `delim` as the separator.
99
splitString(const string & s,char delim)100 vector<string> splitString(const string &s, char delim)
101 {
102 istringstream tokenStream(s);
103
104 if (delim == '\0')
105 return vector<string>(istream_iterator<string>(tokenStream), istream_iterator<string>());
106 else
107 {
108 vector<string> ret;
109 string token;
110
111 while (std::getline(tokenStream, token, delim))
112 ret.push_back(token);
113
114 return ret;
115 }
116 }
117
118 //! Convert floating-point value to string with fixed number of fractional decimals.
floatToString(float val,int precision)119 std::string floatToString(float val, int precision)
120 {
121 std::ostringstream s;
122 s << std::fixed << std::setprecision(precision) << val;
123 return s.str();
124 }
125
beginsWith(const std::string & s,const std::string & prefix)126 bool beginsWith(const std::string &s, const std::string &prefix)
127 {
128 return deStringBeginsWith(s.c_str(), prefix.c_str()) == true;
129 }
130
endsWith(const std::string & s,const std::string & suffix)131 bool endsWith(const std::string &s, const std::string &suffix)
132 {
133 if (suffix.length() > s.length())
134 return false;
135 else
136 {
137 const std::string::size_type offset = s.length() - suffix.length();
138 return s.find(suffix, offset) == offset;
139 }
140 }
141
toUpper(char c)142 char toUpper(char c)
143 {
144 return std::toupper(c, std::locale::classic());
145 }
146
toLower(char c)147 char toLower(char c)
148 {
149 return std::tolower(c, std::locale::classic());
150 }
151
isUpper(char c)152 bool isUpper(char c)
153 {
154 return std::isupper(c, std::locale::classic());
155 }
156
isLower(char c)157 bool isLower(char c)
158 {
159 return std::islower(c, std::locale::classic());
160 }
161
isDigit(char c)162 bool isDigit(char c)
163 {
164 return std::isdigit(c, std::locale::classic());
165 }
166
StringUtil_selfTest(void)167 void StringUtil_selfTest(void)
168 {
169
170 DE_TEST_ASSERT(toString(42) == "42");
171 DE_TEST_ASSERT(toString("foo") == "foo");
172 DE_TEST_ASSERT(toLower("FooBar") == "foobar");
173 DE_TEST_ASSERT(toUpper("FooBar") == "FOOBAR");
174
175 {
176 vector<string> tokens(splitString(" foo bar\n\tbaz "));
177 DE_TEST_ASSERT(tokens.size() == 3);
178 DE_TEST_ASSERT(tokens[0] == "foo");
179 DE_TEST_ASSERT(tokens[1] == "bar");
180 DE_TEST_ASSERT(tokens[2] == "baz");
181 }
182
183 DE_TEST_ASSERT(floatToString(4, 1) == "4.0");
184
185 DE_TEST_ASSERT(beginsWith("foobar", "foobar"));
186 DE_TEST_ASSERT(beginsWith("foobar", "foo"));
187 DE_TEST_ASSERT(beginsWith("foobar", "f"));
188 DE_TEST_ASSERT(beginsWith("foobar", ""));
189 DE_TEST_ASSERT(beginsWith("", ""));
190 DE_TEST_ASSERT(!beginsWith("foobar", "bar"));
191 DE_TEST_ASSERT(!beginsWith("foobar", "foobarbaz"));
192 DE_TEST_ASSERT(!beginsWith("", "foo"));
193
194 DE_TEST_ASSERT(endsWith("foobar", "foobar"));
195 DE_TEST_ASSERT(endsWith("foobar", "bar"));
196 DE_TEST_ASSERT(endsWith("foobar", "r"));
197 DE_TEST_ASSERT(endsWith("foobar", ""));
198 DE_TEST_ASSERT(endsWith("", ""));
199 DE_TEST_ASSERT(!endsWith("foobar", "foo"));
200 DE_TEST_ASSERT(!endsWith("foobar", "bazfoobar"));
201 DE_TEST_ASSERT(!endsWith("foobar", "foobarbaz"));
202 DE_TEST_ASSERT(!endsWith("", "foo"));
203
204 DE_TEST_ASSERT(toUpper('a') == 'A');
205 DE_TEST_ASSERT(toUpper('A') == 'A');
206 DE_TEST_ASSERT(toLower('a') == 'a');
207 DE_TEST_ASSERT(toLower('A') == 'a');
208 DE_TEST_ASSERT(isUpper('A'));
209 DE_TEST_ASSERT(!isUpper('a'));
210 DE_TEST_ASSERT(isLower('a'));
211 DE_TEST_ASSERT(!isLower('A'));
212 DE_TEST_ASSERT(isDigit('0'));
213 DE_TEST_ASSERT(!isDigit('a'));
214 }
215
216 } // namespace de
217