1
2
3
4 package net.sourceforge.pmd.util;
5
6 import java.util.ArrayList;
7 import java.util.Iterator;
8 import java.util.List;
9
10
11
12
13
14
15
16 public final class StringUtil {
17
18 public static final String[] EMPTY_STRINGS = new String[0];
19 private static final boolean SUPPORTS_UTF8 = System.getProperty("net.sourceforge.pmd.supportUTF8", "no").equals(
20 "yes");
21
22 private StringUtil() {
23 }
24
25
26
27
28
29
30
31
32
33 public static boolean startsWithAny(String text, String... prefixes) {
34
35 for (String prefix : prefixes) {
36 if (text.startsWith(prefix)) {
37 return true;
38 }
39 }
40
41 return false;
42 }
43
44
45
46
47
48
49
50
51 public static boolean isAnyOf(String text, String... tests) {
52
53 for (String test : tests) {
54 if (text.equals(test)) {
55 return true;
56 }
57 }
58
59 return false;
60 }
61
62
63
64
65
66
67
68
69
70 public static String withoutPrefixes(String text, String... prefixes) {
71
72 for (String prefix : prefixes) {
73 if (text.startsWith(prefix)) {
74 return text.substring(prefix.length());
75 }
76 }
77
78 return text;
79 }
80
81
82
83
84
85
86
87
88
89
90 public static boolean isEmpty(String value) {
91
92 if (value == null || "".equals(value)) {
93 return true;
94 }
95
96 for (int i = 0; i < value.length(); i++) {
97 if (!Character.isWhitespace(value.charAt(i))) {
98 return false;
99 }
100 }
101
102 return true;
103 }
104
105
106
107
108
109
110 public static boolean isNotEmpty(String value) {
111 return !isEmpty(value);
112 }
113
114
115
116
117
118
119
120
121
122 public static boolean areSemanticEquals(String a, String b) {
123
124 if (a == null) {
125 return isEmpty(b);
126 }
127 if (b == null) {
128 return isEmpty(a);
129 }
130
131 return a.equals(b);
132 }
133
134
135
136
137
138
139
140
141 public static String replaceString(final String original, char oldChar, final String newString) {
142 int index = original.indexOf(oldChar);
143 if (index < 0) {
144 return original;
145 } else {
146 final String replace = newString == null ? "" : newString;
147 final StringBuilder buf = new StringBuilder(Math.max(16, original.length() + replace.length()));
148 int last = 0;
149 while (index != -1) {
150 buf.append(original.substring(last, index));
151 buf.append(replace);
152 last = index + 1;
153 index = original.indexOf(oldChar, last);
154 }
155 buf.append(original.substring(last));
156 return buf.toString();
157 }
158 }
159
160
161
162
163
164
165
166
167 public static String replaceString(final String original, final String oldString, final String newString) {
168 int index = original.indexOf(oldString);
169 if (index < 0) {
170 return original;
171 } else {
172 final String replace = newString == null ? "" : newString;
173 final StringBuilder buf = new StringBuilder(Math.max(16, original.length() + replace.length()));
174 int last = 0;
175 while (index != -1) {
176 buf.append(original.substring(last, index));
177 buf.append(replace);
178 last = index + oldString.length();
179 index = original.indexOf(oldString, last);
180 }
181 buf.append(original.substring(last));
182 return buf.toString();
183 }
184 }
185
186
187
188
189
190
191
192
193
194
195 @Deprecated
196 public static void appendXmlEscaped(StringBuilder buf, String src) {
197 appendXmlEscaped(buf, src, SUPPORTS_UTF8);
198 }
199
200
201
202
203
204
205
206 public static String escapeWhitespace(Object o) {
207
208 if (o == null) {
209 return null;
210 }
211 String s = String.valueOf(o);
212 s = s.replace("\n", "\\n");
213 s = s.replace("\r", "\\r");
214 s = s.replace("\t", "\\t");
215 return s;
216 }
217
218
219
220
221
222
223 public static String htmlEncode(String string) {
224 String encoded = replaceString(string, '&', "&");
225 encoded = replaceString(encoded, '<', "<");
226 return replaceString(encoded, '>', ">");
227 }
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244 public static void appendXmlEscaped(StringBuilder buf, String src, boolean supportUTF8) {
245 char c;
246 for (int i = 0; i < src.length(); i++) {
247 c = src.charAt(i);
248 if (c > '~') {
249 if (!supportUTF8) {
250 int codepoint = c;
251
252 if (Character.isHighSurrogate(c)) {
253 char low = src.charAt(i + 1);
254 codepoint = Character.toCodePoint(c, low);
255 i += 1;
256 }
257 buf.append("&#x").append(Integer.toHexString(codepoint)).append(';');
258 } else {
259 buf.append(c);
260 }
261 } else if (c == '&') {
262 buf.append("&");
263 } else if (c == '"') {
264 buf.append(""");
265 } else if (c == '<') {
266 buf.append("<");
267 } else if (c == '>') {
268 buf.append(">");
269 } else {
270 buf.append(c);
271 }
272 }
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287 public static String[] substringsOf(String source, char delimiter) {
288
289 if (source == null || source.length() == 0) {
290 return EMPTY_STRINGS;
291 }
292
293 int delimiterCount = 0;
294 int length = source.length();
295 char[] chars = source.toCharArray();
296
297 for (int i = 0; i < length; i++) {
298 if (chars[i] == delimiter) {
299 delimiterCount++;
300 }
301 }
302
303 if (delimiterCount == 0) {
304 return new String[] { source };
305 }
306
307 String[] results = new String[delimiterCount + 1];
308
309 int i = 0;
310 int offset = 0;
311
312 while (offset <= length) {
313 int pos = source.indexOf(delimiter, offset);
314 if (pos < 0) {
315 pos = length;
316 }
317 results[i++] = pos == offset ? "" : source.substring(offset, pos);
318 offset = pos + 1;
319 }
320
321 return results;
322 }
323
324
325
326
327
328
329
330
331 public static String[] substringsOf(String str, String separator) {
332
333 if (str == null || str.length() == 0) {
334 return EMPTY_STRINGS;
335 }
336
337 int index = str.indexOf(separator);
338 if (index == -1) {
339 return new String[] { str };
340 }
341
342 List<String> list = new ArrayList<String>();
343 int currPos = 0;
344 int len = separator.length();
345 while (index != -1) {
346 list.add(str.substring(currPos, index));
347 currPos = index + len;
348 index = str.indexOf(separator, currPos);
349 }
350 list.add(str.substring(currPos));
351 return list.toArray(new String[list.size()]);
352 }
353
354
355
356
357
358
359
360
361
362 public static void asStringOn(StringBuffer sb, Iterator<?> iter, String separator) {
363
364 if (!iter.hasNext()) {
365 return;
366 }
367
368 sb.append(iter.next());
369
370 while (iter.hasNext()) {
371 sb.append(separator);
372 sb.append(iter.next());
373 }
374 }
375
376
377
378
379
380
381
382
383
384 public static void asStringOn(StringBuilder sb, Object[] items, String separator) {
385
386 if (items == null || items.length == 0) {
387 return;
388 }
389
390 sb.append(items[0]);
391
392 for (int i = 1; i < items.length; i++) {
393 sb.append(separator);
394 sb.append(items[i]);
395 }
396 }
397
398
399
400
401
402
403
404
405 public static int lengthOfShortestIn(String[] strings) {
406
407 if (CollectionUtil.isEmpty(strings)) {
408 return 0;
409 }
410
411 int minLength = Integer.MAX_VALUE;
412
413 for (int i = 0; i < strings.length; i++) {
414 if (strings[i] == null) {
415 return 0;
416 }
417 minLength = Math.min(minLength, strings[i].length());
418 }
419
420 return minLength;
421 }
422
423
424
425
426
427
428
429
430
431
432 public static int maxCommonLeadingWhitespaceForAll(String[] strings) {
433
434 int shortest = lengthOfShortestIn(strings);
435 if (shortest == 0) {
436 return 0;
437 }
438
439 char[] matches = new char[shortest];
440
441 String str;
442 for (int m = 0; m < matches.length; m++) {
443 matches[m] = strings[0].charAt(m);
444 if (!Character.isWhitespace(matches[m])) {
445 return m;
446 }
447 for (int i = 0; i < strings.length; i++) {
448 str = strings[i];
449 if (str.charAt(m) != matches[m]) {
450 return m;
451 }
452 }
453 }
454
455 return shortest;
456 }
457
458
459
460
461
462
463
464
465
466 public static String[] trimStartOn(String[] strings, int trimDepth) {
467
468 if (trimDepth == 0) {
469 return strings;
470 }
471
472 String[] results = new String[strings.length];
473 for (int i = 0; i < strings.length; i++) {
474 results[i] = strings[i].substring(trimDepth);
475 }
476 return results;
477 }
478
479
480
481
482
483
484
485
486 public static String lpad(String s, int length) {
487 String res = s;
488 if (length - s.length() > 0) {
489 char[] arr = new char[length - s.length()];
490 java.util.Arrays.fill(arr, ' ');
491 res = new StringBuilder(length).append(arr).append(s).toString();
492 }
493 return res;
494 }
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512 @SuppressWarnings("PMD.CompareObjectsWithEquals")
513 public static boolean isSame(String s1, String s2, boolean trim, boolean ignoreCase, boolean standardizeWhitespace) {
514 if (s1 == s2) {
515 return true;
516 } else if (s1 == null || s2 == null) {
517 return false;
518 } else {
519 if (trim) {
520 s1 = s1.trim();
521 s2 = s2.trim();
522 }
523 if (standardizeWhitespace) {
524
525
526 s1 = s1.replaceAll("\\s+", " ");
527 s2 = s2.replaceAll("\\s+", " ");
528 }
529 return ignoreCase ? s1.equalsIgnoreCase(s2) : s1.equals(s2);
530 }
531 }
532
533
534
535
536
537
538
539
540
541 public static String asString(Object[] items, String separator) {
542
543 if (items == null || items.length == 0) {
544 return "";
545 }
546 if (items.length == 1) {
547 return items[0].toString();
548 }
549
550 StringBuilder sb = new StringBuilder(items[0].toString());
551 for (int i = 1; i < items.length; i++) {
552 sb.append(separator).append(items[i]);
553 }
554
555 return sb.toString();
556 }
557 }