1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache license, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the license for the specific language governing permissions and
15 * limitations under the license.
16 */
17 package org.apache.logging.log4j.util;
18
19 import java.util.Iterator;
20 import java.util.Locale;
21 import java.util.Objects;
22
23 /**
24 * <em>Consider this class private.</em>
25 *
26 * @see <a href="http://commons.apache.org/proper/commons-lang/">Apache Commons Lang</a>
27 */
28 public final class Strings {
29
30 private static final ThreadLocal<StringBuilder> tempStr = ThreadLocal.withInitial(StringBuilder::new);
31
32 /**
33 * The empty string.
34 */
35 public static final String EMPTY = "";
36 private static final String COMMA_DELIMITED_RE = "\\s*,\\s*";
37
38 /**
39 * The empty array.
40 */
41 public static final String[] EMPTY_ARRAY = {};
42
43 /**
44 * OS-dependent line separator, defaults to {@code "\n"} if the system property {@code ""line.separator"} cannot be
45 * read.
46 */
47 public static final String LINE_SEPARATOR = PropertiesUtil.getProperties().getStringProperty("line.separator",
48 "\n");
49
50 /**
51 * Returns a double quoted string.
52 *
53 * @param str a String
54 * @return {@code "str"}
55 */
56 public static String dquote(final String str) {
57 return Chars.DQUOTE + str + Chars.DQUOTE;
58 }
59
60 /**
61 * Checks if a String is blank. A blank string is one that is either
62 * {@code null}, empty, or all characters are {@link Character#isWhitespace(char)}.
63 *
64 * @param s the String to check, may be {@code null}
65 * @return {@code true} if the String is {@code null}, empty, or or all characters are {@link Character#isWhitespace(char)}
66 */
67 public static boolean isBlank(final String s) {
68 if (s == null || s.isEmpty()) {
69 return true;
70 }
71 for (int i = 0; i < s.length(); i++) {
72 char c = s.charAt(i);
73 if (!Character.isWhitespace(c)) {
74 return false;
75 }
76 }
77 return true;
78 }
79
80 /**
81 * <p>
82 * Checks if a CharSequence is empty ("") or null.
83 * </p>
84 *
85 * <pre>
86 * Strings.isEmpty(null) = true
87 * Strings.isEmpty("") = true
88 * Strings.isEmpty(" ") = false
89 * Strings.isEmpty("bob") = false
90 * Strings.isEmpty(" bob ") = false
91 * </pre>
92 *
93 * <p>
94 * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence. That functionality is
95 * available in isBlank().
96 * </p>
97 *
98 * <p>
99 * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isEmpty(CharSequence)
100 * </p>
101 *
102 * @param cs the CharSequence to check, may be null
103 * @return {@code true} if the CharSequence is empty or null
104 */
105 public static boolean isEmpty(final CharSequence cs) {
106 return cs == null || cs.length() == 0;
107 }
108
109 /**
110 * Checks if a String is not blank. The opposite of {@link #isBlank(String)}.
111 *
112 * @param s the String to check, may be {@code null}
113 * @return {@code true} if the String is non-{@code null} and has content after being trimmed.
114 */
115 public static boolean isNotBlank(final String s) {
116 return !isBlank(s);
117 }
118
119 /**
120 * <p>
121 * Checks if a CharSequence is not empty ("") and not null.
122 * </p>
123 *
124 * <pre>
125 * Strings.isNotEmpty(null) = false
126 * Strings.isNotEmpty("") = false
127 * Strings.isNotEmpty(" ") = true
128 * Strings.isNotEmpty("bob") = true
129 * Strings.isNotEmpty(" bob ") = true
130 * </pre>
131 *
132 * <p>
133 * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isNotEmpty(CharSequence)
134 * </p>
135 *
136 * @param cs the CharSequence to check, may be null
137 * @return {@code true} if the CharSequence is not empty and not null
138 */
139 public static boolean isNotEmpty(final CharSequence cs) {
140 return !isEmpty(cs);
141 }
142
143 /**
144 * <p>Joins the elements of the provided {@code Iterable} into
145 * a single String containing the provided elements.</p>
146 *
147 * <p>No delimiter is added before or after the list. Null objects or empty
148 * strings within the iteration are represented by empty strings.</p>
149 *
150 * @param iterable the {@code Iterable} providing the values to join together, may be null
151 * @param separator the separator character to use
152 * @return the joined String, {@code null} if null iterator input
153 */
154 public static String join(final Iterable<?> iterable, final char separator) {
155 if (iterable == null) {
156 return null;
157 }
158 return join(iterable.iterator(), separator);
159 }
160
161 /**
162 * <p>Joins the elements of the provided {@code Iterator} into
163 * a single String containing the provided elements.</p>
164 *
165 * <p>No delimiter is added before or after the list. Null objects or empty
166 * strings within the iteration are represented by empty strings.</p>
167 *
168 * @param iterator the {@code Iterator} of values to join together, may be null
169 * @param separator the separator character to use
170 * @return the joined String, {@code null} if null iterator input
171 */
172 public static String join(final Iterator<?> iterator, final char separator) {
173
174 // handle null, zero and one elements before building a buffer
175 if (iterator == null) {
176 return null;
177 }
178 if (!iterator.hasNext()) {
179 return EMPTY;
180 }
181 final Object first = iterator.next();
182 if (!iterator.hasNext()) {
183 return Objects.toString(first, EMPTY);
184 }
185
186 // two or more elements
187 final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
188 if (first != null) {
189 buf.append(first);
190 }
191
192 while (iterator.hasNext()) {
193 buf.append(separator);
194 final Object obj = iterator.next();
195 if (obj != null) {
196 buf.append(obj);
197 }
198 }
199
200 return buf.toString();
201 }
202
203 public static String[] splitList(String string) {
204 return string != null ? string.split(COMMA_DELIMITED_RE) : new String[0];
205 }
206
207 /**
208 * <p>Gets the leftmost {@code len} characters of a String.</p>
209 *
210 * <p>If {@code len} characters are not available, or the
211 * String is {@code null}, the String will be returned without
212 * an exception. An empty String is returned if len is negative.</p>
213 *
214 * <pre>
215 * StringUtils.left(null, *) = null
216 * StringUtils.left(*, -ve) = ""
217 * StringUtils.left("", *) = ""
218 * StringUtils.left("abc", 0) = ""
219 * StringUtils.left("abc", 2) = "ab"
220 * StringUtils.left("abc", 4) = "abc"
221 * </pre>
222 *
223 * <p>
224 * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.
225 * </p>
226 *
227 * @param str the String to get the leftmost characters from, may be null
228 * @param len the length of the required String
229 * @return the leftmost characters, {@code null} if null String input
230 */
231 public static String left(final String str, final int len) {
232 if (str == null) {
233 return null;
234 }
235 if (len < 0) {
236 return EMPTY;
237 }
238 if (str.length() <= len) {
239 return str;
240 }
241 return str.substring(0, len);
242 }
243
244 /**
245 * Returns a quoted string.
246 *
247 * @param str a String
248 * @return {@code 'str'}
249 */
250 public static String quote(final String str) {
251 return Chars.QUOTE + str + Chars.QUOTE;
252 }
253
254 /**
255 * <p>
256 * Removes control characters (char <= 32) from both ends of this String returning {@code null} if the String is
257 * empty ("") after the trim or if it is {@code null}.
258 *
259 * <p>
260 * The String is trimmed using {@link String#trim()}. Trim removes start and end characters <= 32.
261 * </p>
262 *
263 * <pre>
264 * Strings.trimToNull(null) = null
265 * Strings.trimToNull("") = null
266 * Strings.trimToNull(" ") = null
267 * Strings.trimToNull("abc") = "abc"
268 * Strings.trimToNull(" abc ") = "abc"
269 * </pre>
270 *
271 * <p>
272 * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.trimToNull(String)
273 * </p>
274 *
275 * @param str the String to be trimmed, may be null
276 * @return the trimmed String, {@code null} if only chars <= 32, empty or null String input
277 */
278 public static String trimToNull(final String str) {
279 final String ts = str == null ? null : str.trim();
280 return isEmpty(ts) ? null : ts;
281 }
282
283 private Strings() {
284 // empty
285 }
286
287 /**
288 * Shorthand for {@code str.toLowerCase(Locale.ROOT);}
289 * @param str The string to upper case.
290 * @return a new string
291 * @see String#toLowerCase(Locale)
292 */
293 public static String toRootLowerCase(final String str) {
294 return str.toLowerCase(Locale.ROOT);
295 }
296
297 /**
298 * Shorthand for {@code str.toUpperCase(Locale.ROOT);}
299 * @param str The string to lower case.
300 * @return a new string
301 * @see String#toLowerCase(Locale)
302 */
303 public static String toRootUpperCase(final String str) {
304 return str.toUpperCase(Locale.ROOT);
305 }
306
307 /**
308 * Concatenates 2 Strings without allocation.
309 * @param str1 the first string.
310 * @param str2 the second string.
311 * @return the concatenated String.
312 */
313 public static String concat(String str1, String str2) {
314 if (isEmpty(str1)) {
315 return str2;
316 } else if (isEmpty(str2)) {
317 return str1;
318 }
319 StringBuilder sb = tempStr.get();
320 try {
321 return sb.append(str1).append(str2).toString();
322 } finally {
323 sb.setLength(0);
324 }
325 }
326
327 /**
328 * Creates a new string repeating given {@code str} {@code count} times.
329 * @param str input string
330 * @param count the repetition count
331 * @return the new string
332 * @throws IllegalArgumentException if either {@code str} is null or {@code count} is negative
333 */
334 public static String repeat(final String str, final int count) {
335 Objects.requireNonNull(str, "str");
336 if (count < 0) {
337 throw new IllegalArgumentException("count");
338 }
339 StringBuilder sb = tempStr.get();
340 try {
341 for (int index = 0; index < count; index++) {
342 sb.append(str);
343 }
344 return sb.toString();
345 } finally {
346 sb.setLength(0);
347 }
348 }
349
350 }
351