1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/core/platform/str_util.h"
17
18 #include <cctype>
19 #include <string>
20 #include <vector>
21
22 #include "absl/strings/ascii.h"
23 #include "absl/strings/escaping.h"
24 #include "absl/strings/match.h"
25 #include "absl/strings/strip.h"
26 #include "tensorflow/core/platform/logging.h"
27 #include "tensorflow/core/platform/stringpiece.h"
28
29 namespace tensorflow {
30 namespace str_util {
31
CEscape(StringPiece src)32 string CEscape(StringPiece src) { return absl::CEscape(src); }
33
CUnescape(StringPiece source,string * dest,string * error)34 bool CUnescape(StringPiece source, string* dest, string* error) {
35 return absl::CUnescape(source, dest, error);
36 }
37
StripTrailingWhitespace(string * s)38 void StripTrailingWhitespace(string* s) {
39 absl::StripTrailingAsciiWhitespace(s);
40 }
41
RemoveLeadingWhitespace(StringPiece * text)42 size_t RemoveLeadingWhitespace(StringPiece* text) {
43 absl::string_view new_text = absl::StripLeadingAsciiWhitespace(*text);
44 size_t count = text->size() - new_text.size();
45 *text = new_text;
46 return count;
47 }
48
RemoveTrailingWhitespace(StringPiece * text)49 size_t RemoveTrailingWhitespace(StringPiece* text) {
50 absl::string_view new_text = absl::StripTrailingAsciiWhitespace(*text);
51 size_t count = text->size() - new_text.size();
52 *text = new_text;
53 return count;
54 }
55
RemoveWhitespaceContext(StringPiece * text)56 size_t RemoveWhitespaceContext(StringPiece* text) {
57 absl::string_view new_text = absl::StripAsciiWhitespace(*text);
58 size_t count = text->size() - new_text.size();
59 *text = new_text;
60 return count;
61 }
62
ConsumeLeadingDigits(StringPiece * s,uint64 * val)63 bool ConsumeLeadingDigits(StringPiece* s, uint64* val) {
64 const char* p = s->data();
65 const char* limit = p + s->size();
66 uint64 v = 0;
67 while (p < limit) {
68 const char c = *p;
69 if (c < '0' || c > '9') break;
70 uint64 new_v = (v * 10) + (c - '0');
71 if (new_v / 8 < v) {
72 // Overflow occurred
73 return false;
74 }
75 v = new_v;
76 p++;
77 }
78 if (p > s->data()) {
79 // Consume some digits
80 s->remove_prefix(p - s->data());
81 *val = v;
82 return true;
83 } else {
84 return false;
85 }
86 }
87
ConsumeNonWhitespace(StringPiece * s,StringPiece * val)88 bool ConsumeNonWhitespace(StringPiece* s, StringPiece* val) {
89 const char* p = s->data();
90 const char* limit = p + s->size();
91 while (p < limit) {
92 const char c = *p;
93 if (isspace(c)) break;
94 p++;
95 }
96 const size_t n = p - s->data();
97 if (n > 0) {
98 *val = StringPiece(s->data(), n);
99 s->remove_prefix(n);
100 return true;
101 } else {
102 *val = StringPiece();
103 return false;
104 }
105 }
106
ConsumePrefix(StringPiece * s,StringPiece expected)107 bool ConsumePrefix(StringPiece* s, StringPiece expected) {
108 return absl::ConsumePrefix(s, expected);
109 }
110
ConsumeSuffix(StringPiece * s,StringPiece expected)111 bool ConsumeSuffix(StringPiece* s, StringPiece expected) {
112 return absl::ConsumeSuffix(s, expected);
113 }
114
StripPrefix(StringPiece s,StringPiece expected)115 StringPiece StripPrefix(StringPiece s, StringPiece expected) {
116 return absl::StripPrefix(s, expected);
117 }
118
StripSuffix(StringPiece s,StringPiece expected)119 StringPiece StripSuffix(StringPiece s, StringPiece expected) {
120 return absl::StripSuffix(s, expected);
121 }
122
123 // Return lower-cased version of s.
Lowercase(StringPiece s)124 string Lowercase(StringPiece s) { return absl::AsciiStrToLower(s); }
125
126 // Return upper-cased version of s.
Uppercase(StringPiece s)127 string Uppercase(StringPiece s) { return absl::AsciiStrToUpper(s); }
128
TitlecaseString(string * s,StringPiece delimiters)129 void TitlecaseString(string* s, StringPiece delimiters) {
130 bool upper = true;
131 for (string::iterator ss = s->begin(); ss != s->end(); ++ss) {
132 if (upper) {
133 *ss = toupper(*ss);
134 }
135 upper = (delimiters.find(*ss) != StringPiece::npos);
136 }
137 }
138
StringReplace(StringPiece s,StringPiece oldsub,StringPiece newsub,bool replace_all)139 string StringReplace(StringPiece s, StringPiece oldsub, StringPiece newsub,
140 bool replace_all) {
141 // TODO(jlebar): We could avoid having to shift data around in the string if
142 // we had a StringPiece::find() overload that searched for a StringPiece.
143 string res(s);
144 size_t pos = 0;
145 while ((pos = res.find(oldsub.data(), pos, oldsub.size())) != string::npos) {
146 res.replace(pos, oldsub.size(), newsub.data(), newsub.size());
147 pos += newsub.size();
148 if (oldsub.empty()) {
149 pos++; // Match at the beginning of the text and after every byte
150 }
151 if (!replace_all) {
152 break;
153 }
154 }
155 return res;
156 }
157
StartsWith(StringPiece text,StringPiece prefix)158 bool StartsWith(StringPiece text, StringPiece prefix) {
159 return absl::StartsWith(text, prefix);
160 }
161
EndsWith(StringPiece text,StringPiece suffix)162 bool EndsWith(StringPiece text, StringPiece suffix) {
163 return absl::EndsWith(text, suffix);
164 }
165
StrContains(StringPiece haystack,StringPiece needle)166 bool StrContains(StringPiece haystack, StringPiece needle) {
167 return absl::StrContains(haystack, needle);
168 }
169
Strnlen(const char * str,const size_t string_max_len)170 size_t Strnlen(const char* str, const size_t string_max_len) {
171 size_t len = 0;
172 while (len < string_max_len && str[len] != '\0') {
173 ++len;
174 }
175 return len;
176 }
177
ArgDefCase(StringPiece s)178 string ArgDefCase(StringPiece s) {
179 const size_t n = s.size();
180
181 // Compute the size of resulting string.
182 // Number of extra underscores we will need to add.
183 size_t extra_us = 0;
184 // Number of non-alpha chars in the beginning to skip.
185 size_t to_skip = 0;
186 for (size_t i = 0; i < n; ++i) {
187 // If we are skipping and current letter is non-alpha, skip it as well
188 if (i == to_skip && !isalpha(s[i])) {
189 ++to_skip;
190 continue;
191 }
192
193 // If we are here, we are not skipping any more.
194 // If this letter is upper case, not the very first char in the
195 // resulting string, and previous letter isn't replaced with an underscore,
196 // we will need to insert an underscore.
197 if (isupper(s[i]) && i != to_skip && i > 0 && isalnum(s[i - 1])) {
198 ++extra_us;
199 }
200 }
201
202 // Initialize result with all '_'s. There is no string
203 // constructor that does not initialize memory.
204 string result(n + extra_us - to_skip, '_');
205 // i - index into s
206 // j - index into result
207 for (size_t i = to_skip, j = 0; i < n; ++i, ++j) {
208 DCHECK_LT(j, result.size());
209 char c = s[i];
210 // If c is not alphanumeric, we don't need to do anything
211 // since there is already an underscore in its place.
212 if (isalnum(c)) {
213 if (isupper(c)) {
214 // If current char is upper case, we might need to insert an
215 // underscore.
216 if (i != to_skip) {
217 DCHECK_GT(j, 0);
218 if (result[j - 1] != '_') ++j;
219 }
220 result[j] = tolower(c);
221 } else {
222 result[j] = c;
223 }
224 }
225 }
226
227 return result;
228 }
229
230 } // namespace str_util
231 } // namespace tensorflow
232