| StringUtil.java |
1 /**
2 * Distribution License:
3 * JSword is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 or later
5 * as published by the Free Software Foundation. This program is distributed
6 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * © CrossWire Bible Society, 2005 - 2016
18 *
19 */
20 package org.crosswire.common.util;
21
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.Reader;
25
26 /**
27 * A generic class of String utilities.
28 *
29 * @see gnu.lgpl.License The GNU Lesser General Public License for details.
30 * @author Joe Walker
31 */
32 public final class StringUtil {
33 /**
34 * Prevent instantiation
35 */
36 private StringUtil() {
37 }
38
39 /**
40 * The newline character
41 */
42 public static final String NEWLINE = System.getProperty("line.separator", "\r\n");
43
44 /**
45 * Compare two strings for equality such that both can be null.
46 *
47 * @param string1 the first string
48 * @param string2 the second string
49 * @return true when both are null or both have the same string value
50 */
51 public static boolean equals(String string1, String string2) {
52 if (string1 == null) {
53 return string2 == null;
54 }
55 return string1.equals(string2);
56 }
57
58 /**
59 * This method reads an InputStream <b>In its entirety</b>, and passes The
60 * text back as a string. If you are reading from a source that can block
61 * then be prepared for a long wait for this to return.
62 *
63 * @param in
64 * The Stream to read from.
65 * @return A string containing all the text from the Stream.
66 * @throws IOException when an I/O error occurred
67 */
68 public static String read(Reader in) throws IOException {
69 StringBuilder retcode = new StringBuilder();
70 // Quiet Android from complaining about using the default BufferReader buffer size.
71 // The actual buffer size is undocumented. So this is a good idea any way.
72 BufferedReader din = new BufferedReader(in, 8192);
73
74 while (true) {
75 String line = din.readLine();
76
77 if (line == null) {
78 break;
79 }
80
81 retcode.append(line);
82 retcode.append(NEWLINE);
83 }
84
85 return retcode.toString();
86 }
87
88 /**
89 * This function creates a readable title from a variable name type input.
90 * For example calling: StringUtil.createTitle("one_two") = "One Two"
91 * StringUtil.createTitle("oneTwo") = "One Two"
92 *
93 * @param variable the name of a variable
94 * @return the generated title
95 */
96 public static String createTitle(String variable) {
97 StringBuilder retcode = new StringBuilder();
98 boolean lastlower = false;
99 boolean lastspace = true;
100
101 for (int i = 0; i < variable.length(); i++) {
102 char c = variable.charAt(i);
103
104 if (lastlower && Character.isUpperCase(c) && !lastspace) {
105 retcode.append(' ');
106 }
107
108 lastlower = !Character.isUpperCase(c);
109
110 if (lastspace) {
111 c = Character.toUpperCase(c);
112 }
113
114 if (c == '_') {
115 c = ' ';
116 }
117
118 if (!lastspace || c != ' ') {
119 retcode.append(c);
120 }
121
122 lastspace = c == ' ';
123 }
124
125 return retcode.toString();
126 }
127
128 /**
129 * For example getInitials("Java DataBase Connectivity") = "JDC" and
130 * getInitials("Church of England") = "CoE".
131 *
132 * @param sentence
133 * The phrase from which to get the initial letters.
134 * @return The initial letters in the given words.
135 */
136 public static String getInitials(String sentence) {
137 String[] words = StringUtil.split(sentence);
138
139 StringBuilder retcode = new StringBuilder();
140 for (int i = 0; i < words.length; i++) {
141 String word = words[i];
142
143 char first = 0;
144 for (int j = 0; first == 0 && j < word.length(); j++) {
145 char c = word.charAt(j);
146 if (Character.isLetter(c)) {
147 first = c;
148 }
149 }
150
151 if (first != 0) {
152 retcode.append(first);
153 }
154 }
155
156 return retcode.toString();
157 }
158
159 /**
160 * Splits the provided text into an array, using whitespace as the
161 * separator. Whitespace is defined by {@link Character#isWhitespace(char)}.
162 *
163 * <p>
164 * The separator is not included in the returned String array. Adjacent
165 * separators are treated as one separator.
166 * </p>
167 *
168 * <pre>
169 * StringUtil.split(null) = []
170 * StringUtil.split("") = []
171 * StringUtil.split("abc def") = ["abc", "def"]
172 * StringUtil.split("abc def") = ["abc", "def"]
173 * StringUtil.split(" abc ") = ["abc"]
174 * </pre>
175 *
176 * @param str
177 * the String to parse, may be null
178 * @return an array of parsed Strings, <code>null</code> if null String
179 * input
180 */
181 public static String[] split(String str) {
182 if (str == null) {
183 return EMPTY_STRING_ARRAY.clone();
184 }
185
186 int len = str.length();
187 if (len == 0) {
188 return EMPTY_STRING_ARRAY.clone();
189 }
190
191 char[] cstr = str.toCharArray();
192
193 int count = 0;
194 int start = 0;
195 int i = 0;
196 while ((i = indexOfWhitespace(cstr, start)) != -1) {
197 // Don't count separator at beginning,
198 // after another or at the end
199 if (i > start) {
200 ++count;
201 }
202 start = i + 1;
203 }
204
205 // If it didn't end with a separator then add in the last part
206 if (start < len) {
207 ++count;
208 }
209
210 // Create the array
211 String[] list = new String[count];
212
213 // If there were no separators
214 // then we have one big part
215 if (start == 0) {
216 list[0] = str;
217 return list;
218 }
219
220 start = 0;
221 i = 0;
222 int x = 0;
223 while ((i = indexOfWhitespace(cstr, start)) != -1) {
224 // Don't count separator at beginning,
225 // after another or at the end
226 if (i > start) {
227 list[x++] = str.substring(start, i);
228 }
229 start = i + 1;
230 }
231 // If it didn't end with a separator then add in the last part
232 if (start < len) {
233 list[x++] = str.substring(start);
234 }
235
236 return list;
237 }
238
239 /**
240 * Splits the provided text into an array, using whitespace as the
241 * separator. Whitespace is defined by {@link Character#isWhitespace(char)}.
242 *
243 * <p>
244 * The separator is not included in the returned String array. Adjacent
245 * separators are treated as one separator.
246 * </p>
247 *
248 * <pre>
249 * StringUtil.split(null) = []
250 * StringUtil.split("") = []
251 * StringUtil.split("abc def") = ["abc", "def"]
252 * StringUtil.split("abc def") = ["abc", "def"]
253 * StringUtil.split(" abc ") = ["abc"]
254 * </pre>
255 *
256 * @param str
257 * the String to parse, may be null
258 * @param max the maximum number of elements to return
259 * @return an array of parsed Strings, <code>null</code> if null String
260 * input
261 */
262 public static String[] split(String str, int max) {
263 if (str == null) {
264 return EMPTY_STRING_ARRAY.clone();
265 }
266
267 int len = str.length();
268 if (len == 0) {
269 return EMPTY_STRING_ARRAY.clone();
270 }
271
272 char[] cstr = str.toCharArray();
273
274 int count = 0;
275 int start = 0;
276 int i = 0;
277 while ((i = indexOfWhitespace(cstr, start)) != -1) {
278 // Don't count separator at beginning,
279 // after another or at the end
280 if (i > start) {
281 ++count;
282 }
283 start = i + 1;
284 }
285
286 // If it didn't end with a separator then add in the last part
287 if (start < len) {
288 ++count;
289 }
290
291 // If there were no separators
292 // then we have one big part
293 if (start == 0) {
294 String[] list = new String[count];
295 list[0] = str;
296 return list;
297 }
298
299 // Limit the result
300 if (max > 0 && count > max) {
301 count = max;
302 }
303
304 // Create the array
305 String[] list = new String[count];
306
307 start = 0;
308 i = 0;
309 int x = 0;
310 while ((i = indexOfWhitespace(cstr, start)) != -1) {
311 // Don't count separator at beginning,
312 // after another or at the end
313 if (i > start && x < count) {
314 list[x++] = str.substring(start, i);
315 }
316 start = i + 1;
317 }
318 // If it didn't end with a separator then add in the last part
319 if (start < len && x < count) {
320 list[x++] = str.substring(start);
321 }
322
323 return list;
324 }
325
326 /**
327 * Splits the provided text into an array, separator specified. This is an
328 * alternative to using StringTokenizer.
329 *
330 * <p>
331 * The separator is not included in the returned String array. Adjacent
332 * separators are treated as one separator.
333 * </p>
334 *
335 * <p>
336 * A <code>null</code> input String returns <code>null</code>.
337 * </p>
338 *
339 * <pre>
340 * StringUtil.split(null, *) = []
341 * StringUtil.split("", *) = []
342 * StringUtil.split("a.b.c", '.') = ["a", "b", "c"]
343 * StringUtil.split("a..b.c", '.') = ["a", "b", "c"]
344 * StringUtil.split("a:b:c", '.') = ["a:b:c"]
345 * StringUtil.split("a b c", ' ') = ["a", "b", "c"]
346 * </pre>
347 *
348 * @param str
349 * the String to parse, may be null
350 * @param separatorChar
351 * the character used as the delimiter
352 * @return an array of parsed Strings
353 */
354 public static String[] split(String str, char separatorChar) {
355 if (str == null) {
356 return EMPTY_STRING_ARRAY.clone();
357 }
358
359 int len = str.length();
360 if (len == 0) {
361 return EMPTY_STRING_ARRAY.clone();
362 }
363
364 // Determine the size of the array
365 int count = 0;
366 int start = 0;
367 int i = 0;
368 while ((i = str.indexOf(separatorChar, start)) != -1) {
369 // Don't count separator at beginning,
370 // after another or at the end
371 if (i > start && i < len) {
372 ++count;
373 }
374 start = i + 1;
375 }
376 // If it didn't end with a separator then add in the last part
377 if (start < len) {
378 ++count;
379 }
380
381 // Create the array
382 String[] list = new String[count];
383
384 // If there were no separators
385 // then we have one big part
386 if (count == 1) {
387 list[0] = str;
388 return list;
389 }
390
391 start = 0;
392 i = 0;
393 int x = 0;
394 while ((i = str.indexOf(separatorChar, start)) != -1) {
395 // Don't count separator at beginning,
396 // after another or at the end
397 if (i > start) {
398 list[x++] = str.substring(start, i);
399 }
400 start = i + 1;
401 }
402 // If it didn't end with a separator then add in the last part
403 if (start < len) {
404 list[x++] = str.substring(start, len);
405 }
406
407 return list;
408 }
409
410 /**
411 * <p>
412 * Splits the provided text into an array, separator specified. This is an
413 * alternative to using StringTokenizer.
414 * </p>
415 *
416 * <p>
417 * The separator is not included in the returned String array. Adjacent
418 * separators are treated as one separator.
419 * </p>
420 *
421 * <p>
422 * A <code>null</code> input String returns <code>null</code>.
423 * </p>
424 *
425 * <pre>
426 * StringUtil.split(null, *, 2) = []
427 * StringUtil.split("", *, 2) = []
428 * StringUtil.split("a.b.c", '.', 2) = ["a", "b"]
429 * StringUtil.split("a..b.c", '.', 2) = ["a", "b"]
430 * StringUtil.split("a:b:c", '.', 2) = ["a:b:c"]
431 * StringUtil.split("a b c", ' ', 2) = ["a", "b"]
432 * </pre>
433 *
434 * @param str
435 * the String to parse, may be null
436 * @param separatorChar
437 * the character used as the delimiter
438 * @param max
439 * the maximum number of elements to include in the array.
440 * A zero or negative value implies no limit
441 * @return an array of parsed Strings
442 */
443 public static String[] split(String str, char separatorChar, int max) {
444 if (str == null) {
445 return EMPTY_STRING_ARRAY.clone();
446 }
447
448 int len = str.length();
449 if (len == 0) {
450 return EMPTY_STRING_ARRAY.clone();
451 }
452
453 // Determine the size of the array
454 int count = 0;
455 int start = 0;
456 int i = 0;
457 while ((i = str.indexOf(separatorChar, start)) != -1) {
458 // Don't count separator at beginning,
459 // after another or at the end
460 if (i > start) {
461 ++count;
462 }
463 start = i + 1;
464 }
465
466 // If it didn't end with a separator then add in the last part
467 if (start < len) {
468 ++count;
469 }
470
471 // If there were no separators
472 // then we have one big part
473 if (count == 1) {
474 String[] list = new String[count];
475 list[0] = str;
476 return list;
477 }
478
479 // Limit the result
480 if (max > 0 && count > max) {
481 count = max;
482 }
483
484 // Create the array
485 String[] list = new String[count];
486
487 start = 0;
488 i = 0;
489 int x = 0;
490 while ((i = str.indexOf(separatorChar, start)) != -1) {
491 // Don't count separator at beginning,
492 // after another or at the end
493 if (i > start && x < count) {
494 list[x++] = str.substring(start, i);
495 }
496 start = i + 1;
497 }
498 // If it didn't end with a separator then add in the last part
499 if (start < len && x < count) {
500 list[x++] = str.substring(start);
501 }
502
503 return list;
504 }
505
506 /**
507 * <p>
508 * Splits the provided text into an array, separators specified. This is an
509 * alternative to using StringTokenizer.
510 * </p>
511 *
512 * <p>
513 * The separator is not included in the returned String array. Adjacent
514 * separators are treated as one separator.
515 * </p>
516 *
517 * <p>
518 * A <code>null</code> input String returns <code>null</code>. A
519 * <code>null</code> separatorChars splits on whitespace.
520 * </p>
521 *
522 * <pre>
523 * StringUtil.split(null, *) = []
524 * StringUtil.split("", *) = []
525 * StringUtil.split("abc def", null) = ["abc", "def"]
526 * StringUtil.split("abc def", " ") = ["abc", "def"]
527 * StringUtil.split("abc def", " ") = ["abc", "def"]
528 * StringUtil.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
529 * </pre>
530 *
531 * @param str
532 * the String to parse, may be null
533 * @param separatorChars
534 * the characters used as the delimiters, <code>null</code>
535 * splits on whitespace
536 * @return an array of parsed Strings, <code>null</code> if null String
537 * input
538 */
539 public static String[] split(String str, String separatorChars) {
540 return split(str, separatorChars, -1);
541 }
542
543 /**
544 * <p>
545 * Splits the provided text into an array, separators specified. This is an
546 * alternative to using StringTokenizer.
547 * </p>
548 *
549 * <p>
550 * The separator is not included in the returned String array. Adjacent
551 * separators are treated as one separator.
552 * </p>
553 *
554 * <p>
555 * A <code>null</code> input String returns <code>null</code>. A
556 * <code>null</code> separatorChars splits on whitespace.
557 * </p>
558 *
559 * <pre>
560 * StringUtil.split(null, *, *) = []
561 * StringUtil.split("", *, *) = []
562 * StringUtil.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
563 * StringUtil.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
564 * StringUtil.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
565 * StringUtil.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
566 * </pre>
567 *
568 * @param str
569 * the String to parse, may be null
570 * @param separatorStr
571 * the characters used as the delimiters, <code>null</code>
572 * splits on whitespace
573 * @param max
574 * the maximum number of elements to include in the array. A zero
575 * or negative value implies no limit
576 * @return an array of parsed Strings
577 */
578 public static String[] split(String str, String separatorStr, int max) {
579 // Performance tuned for 2.0 (JDK1.4)
580 // Direct code is quicker than StringTokenizer.
581 // Also, StringTokenizer uses isSpace() not isWhitespace()
582
583 if (separatorStr == null) {
584 return split(str, max);
585 }
586
587 if (separatorStr.length() == 1) {
588 return split(str, separatorStr.charAt(0), max);
589 }
590
591 if (str == null) {
592 return EMPTY_STRING_ARRAY.clone();
593 }
594
595 int len = str.length();
596 if (len == 0) {
597 return EMPTY_STRING_ARRAY.clone();
598 }
599
600 char[] cstr = str.toCharArray();
601 char[] separatorChars = separatorStr.toCharArray();
602
603 int count = 0;
604 int start = 0;
605 int i = 0;
606 while ((i = indexOfAny(cstr, separatorChars, start)) != -1) {
607 // Don't count separator at beginning,
608 // after another or at the end
609 if (i > start) {
610 ++count;
611 }
612 start = i + 1;
613 }
614
615 // If it didn't end with a separator then add in the last part
616 if (start < len) {
617 ++count;
618 }
619
620 // If there were no separators
621 // then we have one big part
622 if (count == 1) {
623 String[] list = new String[count];
624 list[0] = str;
625 return list;
626 }
627
628 // Limit the result
629 if (max > 0 && count > max) {
630 count = max;
631 }
632
633 // Create the array
634 String[] list = new String[count];
635
636 start = 0;
637 i = 0;
638 int x = 0;
639 while ((i = indexOfAny(cstr, separatorChars, start)) != -1) {
640 // Don't count separator at beginning,
641 // after another or at the end
642 if (i > start && x < count) {
643 list[x++] = str.substring(start, i);
644 }
645 start = i + 1;
646 }
647 // If it didn't end with a separator then add in the last part
648 if (start < len && x < count) {
649 list[x++] = str.substring(start);
650 }
651
652 return list;
653 }
654
655 /**
656 * <p>
657 * Splits the provided text into an array, separator specified. This is an
658 * alternative to using StringTokenizer.
659 * </p>
660 *
661 * <p>
662 * The separator is not included in the returned String array. Adjacent
663 * separators are treated individually.
664 * </p>
665 *
666 * <p>
667 * A <code>null</code> input String returns <code>null</code>.
668 * </p>
669 *
670 * <pre>
671 * StringUtil.splitAll(null, *) = []
672 * StringUtil.splitAll("", *) = []
673 * StringUtil.splitAll("a.b.c", '.') = ["a", "b", "c"]
674 * StringUtil.splitAll("a..b.c", '.') = ["a", "", "b", "c"]
675 * StringUtil.splitAll("a:b:c", '.') = ["a:b:c"]
676 * </pre>
677 *
678 * @param str
679 * the String to parse, may be null
680 * @param separatorChar
681 * the character used as the delimiter
682 * @return an array of parsed Strings
683 */
684 public static String[] splitAll(String str, char separatorChar) {
685 if (str == null) {
686 return EMPTY_STRING_ARRAY.clone();
687 }
688
689 int len = str.length();
690 if (len == 0) {
691 return EMPTY_STRING_ARRAY.clone();
692 }
693
694 // Determine the size of the array
695 int count = 1;
696 int start = 0;
697 int i = 0;
698 while ((i = str.indexOf(separatorChar, start)) != -1) {
699 ++count;
700 start = i + 1;
701 }
702
703 // Create the array
704 String[] list = new String[count];
705
706 // If there were no separators
707 // then we have one big part
708 if (count == 1) {
709 list[0] = str;
710 return list;
711 }
712
713 start = 0;
714 i = 0;
715 for (int x = 0; x < count; x++) {
716 i = str.indexOf(separatorChar, start);
717 if (i != -1) {
718 list[x] = str.substring(start, i);
719 } else {
720 list[x] = str.substring(start);
721 }
722 start = i + 1;
723 }
724
725 return list;
726 }
727
728 /**
729 * <p>
730 * Splits the provided text into an array, separator specified. This is an
731 * alternative to using StringTokenizer.
732 * </p>
733 *
734 * <p>
735 * The separator is not included in the returned String array. Adjacent
736 * separators are treated individually.
737 * </p>
738 *
739 * <p>
740 * A <code>null</code> input String returns <code>null</code>.
741 * </p>
742 *
743 * <pre>
744 * StringUtil.splitAll(null, *, 2) = []
745 * StringUtil.splitAll("", *, 2) = []
746 * StringUtil.splitAll("a.b.c", '.', 2) = ["a", "b"]
747 * StringUtil.splitAll("a..b.c", '.', 2) = ["a", ""]
748 * StringUtil.splitAll("a:b:c", '.', 2) = ["a:b:c"]
749 * StringUtil.splitAll("a b c", ' ', 2) = ["a", "b"]
750 * </pre>
751 *
752 * @param str
753 * the String to parse, may be null
754 * @param separatorChar
755 * the character used as the delimiter
756 * @param max
757 * the maximum number of elements to include in the array.
758 * A zero or negative value implies no limit
759 * @return an array of parsed Strings
760 */
761 public static String[] splitAll(String str, char separatorChar, int max) {
762 if (str == null) {
763 return EMPTY_STRING_ARRAY.clone();
764 }
765
766 int len = str.length();
767 if (len == 0) {
768 return EMPTY_STRING_ARRAY.clone();
769 }
770
771 // Determine the size of the array
772 int count = 1;
773 int start = 0;
774 int i = 0;
775 while ((i = str.indexOf(separatorChar, start)) != -1) {
776 ++count;
777 start = i + 1;
778 }
779
780 // If there were no separators
781 // then we have one big part
782 if (count == 1) {
783 String[] list = new String[count];
784 list[0] = str;
785 return list;
786 }
787
788 // Limit the result
789 if (max > 0 && count > max) {
790 count = max;
791 }
792
793 // Create the array
794 String[] list = new String[count];
795
796 start = 0;
797 i = 0;
798 for (int x = 0; x < count; x++) {
799 i = str.indexOf(separatorChar, start);
800 if (i != -1) {
801 list[x] = str.substring(start, i);
802 } else {
803 list[x] = str.substring(start, len);
804 }
805 start = i + 1;
806 }
807
808 return list;
809 }
810
811 /**
812 * <p>
813 * Joins the elements of the provided array into a single String containing
814 * the provided list of elements.
815 * </p>
816 *
817 * <p>
818 * No delimiter is added before or after the list. A <code>null</code>
819 * separator is the same as an empty String (""). Null objects or empty
820 * strings within the array are represented by empty strings.
821 * </p>
822 *
823 * <pre>
824 * StringUtil.join(null, *) = null
825 * StringUtil.join([], *) = ""
826 * StringUtil.join([null], *) = ""
827 * StringUtil.join(["a", "b", "c"], "--") = "a--b--c"
828 * StringUtil.join(["a", "b", "c"], null) = "abc"
829 * StringUtil.join(["a", "b", "c"], "") = "abc"
830 * StringUtil.join([null, "", "a"], ',') = ",,a"
831 * </pre>
832 *
833 * @param array
834 * the array of values to join together, may be null
835 * @param aSeparator
836 * the separator character to use, null treated as ""
837 * @return the joined String, <code>null</code> if null array input
838 */
839 public static String join(Object[] array, String aSeparator) {
840 String separator = aSeparator;
841 if (array == null) {
842 return null;
843 }
844 if (separator == null) {
845 separator = "";
846 }
847 int arraySize = array.length;
848
849 // ArraySize == 0: Len = 0
850 // ArraySize > 0: Len = NofStrings *(len(firstString) + len(separator))
851 // (Assuming that all Strings are roughly equally long)
852 int bufSize = arraySize == 0 ? 0 : arraySize * ((array[0] == null ? 16 : array[0].toString().length()) + separator.length());
853
854 StringBuilder buf = new StringBuilder(bufSize);
855
856 for (int i = 0; i < arraySize; i++) {
857 if (i > 0) {
858 buf.append(separator);
859 }
860 if (array[i] != null) {
861 buf.append(array[i]);
862 }
863 }
864 return buf.toString();
865 }
866
867 /**
868 * Find the first occurrence of a separator in the character buffer beginning
869 * at the given offset.
870 *
871 * @param str
872 * the String to parse, may be null
873 * @param separatorChars
874 * the characters used as the delimiters, <code>null</code>
875 * splits on whitespace
876 * @param offset
877 * the index of the first character to consider
878 * @return the index of a separator char in the string or -1
879 */
880 public static int indexOfAny(char[] str, char[] separatorChars, int offset) {
881 int strlen = str.length;
882 int seplen = separatorChars.length;
883 for (int i = offset; i < strlen; i++) {
884 char ch = str[i];
885 for (int j = 0; j < seplen; j++) {
886 if (separatorChars[j] == ch) {
887 return i;
888 }
889 }
890 }
891 return -1;
892 }
893
894 /**
895 * Find the first occurrence of a whitespace in the character buffer beginning
896 * at the given offset.
897 * Whitespace is defined by {@link Character#isWhitespace(char)}.
898 *
899 * @param str
900 * the String to parse, may be null
901 * @param offset
902 * the index of the first character to consider
903 * @return the index of a separator char in the string or -1
904 */
905 public static int indexOfWhitespace(char[] str, int offset) {
906 int strlen = str.length;
907 for (int i = offset; i < strlen; i++) {
908 if (Character.isWhitespace(str[i])) {
909 return i;
910 }
911 }
912 return -1;
913 }
914
915 /**
916 * An empty immutable <code>String</code> array.
917 */
918 public static final String[] EMPTY_STRING_ARRAY = new String[0];
919
920 }
921