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