1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package com.reuters.msgtest.load.output.csv;
34
35 import java.util.HashMap;
36 import java.util.regex.Pattern;
37
38
39 /***
40 * Utilities for String formatting, manipulation, and queries.
41 * More information about this class is available from <a target="_top" href=
42 * "http://ostermiller.org/utils/StringHelper.html">ostermiller.org</a>.
43 *
44 * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
45 * @since ostermillerutils 1.00.00
46 */
47 public class StringHelper {
48 private static HashMap htmlEntities = new HashMap();
49
50 static {
51 htmlEntities.put("nbsp", new Integer(160));
52 htmlEntities.put("iexcl", new Integer(161));
53 htmlEntities.put("cent", new Integer(162));
54 htmlEntities.put("pound", new Integer(163));
55 htmlEntities.put("curren", new Integer(164));
56 htmlEntities.put("yen", new Integer(165));
57 htmlEntities.put("brvbar", new Integer(166));
58 htmlEntities.put("sect", new Integer(167));
59 htmlEntities.put("uml", new Integer(168));
60 htmlEntities.put("copy", new Integer(169));
61 htmlEntities.put("ordf", new Integer(170));
62 htmlEntities.put("laquo", new Integer(171));
63 htmlEntities.put("not", new Integer(172));
64 htmlEntities.put("shy", new Integer(173));
65 htmlEntities.put("reg", new Integer(174));
66 htmlEntities.put("macr", new Integer(175));
67 htmlEntities.put("deg", new Integer(176));
68 htmlEntities.put("plusmn", new Integer(177));
69 htmlEntities.put("sup2", new Integer(178));
70 htmlEntities.put("sup3", new Integer(179));
71 htmlEntities.put("acute", new Integer(180));
72 htmlEntities.put("micro", new Integer(181));
73 htmlEntities.put("para", new Integer(182));
74 htmlEntities.put("middot", new Integer(183));
75 htmlEntities.put("cedil", new Integer(184));
76 htmlEntities.put("sup1", new Integer(185));
77 htmlEntities.put("ordm", new Integer(186));
78 htmlEntities.put("raquo", new Integer(187));
79 htmlEntities.put("frac14", new Integer(188));
80 htmlEntities.put("frac12", new Integer(189));
81 htmlEntities.put("frac34", new Integer(190));
82 htmlEntities.put("iquest", new Integer(191));
83 htmlEntities.put("Agrave", new Integer(192));
84 htmlEntities.put("Aacute", new Integer(193));
85 htmlEntities.put("Acirc", new Integer(194));
86 htmlEntities.put("Atilde", new Integer(195));
87 htmlEntities.put("Auml", new Integer(196));
88 htmlEntities.put("Aring", new Integer(197));
89 htmlEntities.put("AElig", new Integer(198));
90 htmlEntities.put("Ccedil", new Integer(199));
91 htmlEntities.put("Egrave", new Integer(200));
92 htmlEntities.put("Eacute", new Integer(201));
93 htmlEntities.put("Ecirc", new Integer(202));
94 htmlEntities.put("Euml", new Integer(203));
95 htmlEntities.put("Igrave", new Integer(204));
96 htmlEntities.put("Iacute", new Integer(205));
97 htmlEntities.put("Icirc", new Integer(206));
98 htmlEntities.put("Iuml", new Integer(207));
99 htmlEntities.put("ETH", new Integer(208));
100 htmlEntities.put("Ntilde", new Integer(209));
101 htmlEntities.put("Ograve", new Integer(210));
102 htmlEntities.put("Oacute", new Integer(211));
103 htmlEntities.put("Ocirc", new Integer(212));
104 htmlEntities.put("Otilde", new Integer(213));
105 htmlEntities.put("Ouml", new Integer(214));
106 htmlEntities.put("times", new Integer(215));
107 htmlEntities.put("Oslash", new Integer(216));
108 htmlEntities.put("Ugrave", new Integer(217));
109 htmlEntities.put("Uacute", new Integer(218));
110 htmlEntities.put("Ucirc", new Integer(219));
111 htmlEntities.put("Uuml", new Integer(220));
112 htmlEntities.put("Yacute", new Integer(221));
113 htmlEntities.put("THORN", new Integer(222));
114 htmlEntities.put("szlig", new Integer(223));
115 htmlEntities.put("agrave", new Integer(224));
116 htmlEntities.put("aacute", new Integer(225));
117 htmlEntities.put("acirc", new Integer(226));
118 htmlEntities.put("atilde", new Integer(227));
119 htmlEntities.put("auml", new Integer(228));
120 htmlEntities.put("aring", new Integer(229));
121 htmlEntities.put("aelig", new Integer(230));
122 htmlEntities.put("ccedil", new Integer(231));
123 htmlEntities.put("egrave", new Integer(232));
124 htmlEntities.put("eacute", new Integer(233));
125 htmlEntities.put("ecirc", new Integer(234));
126 htmlEntities.put("euml", new Integer(235));
127 htmlEntities.put("igrave", new Integer(236));
128 htmlEntities.put("iacute", new Integer(237));
129 htmlEntities.put("icirc", new Integer(238));
130 htmlEntities.put("iuml", new Integer(239));
131 htmlEntities.put("eth", new Integer(240));
132 htmlEntities.put("ntilde", new Integer(241));
133 htmlEntities.put("ograve", new Integer(242));
134 htmlEntities.put("oacute", new Integer(243));
135 htmlEntities.put("ocirc", new Integer(244));
136 htmlEntities.put("otilde", new Integer(245));
137 htmlEntities.put("ouml", new Integer(246));
138 htmlEntities.put("divide", new Integer(247));
139 htmlEntities.put("oslash", new Integer(248));
140 htmlEntities.put("ugrave", new Integer(249));
141 htmlEntities.put("uacute", new Integer(250));
142 htmlEntities.put("ucirc", new Integer(251));
143 htmlEntities.put("uuml", new Integer(252));
144 htmlEntities.put("yacute", new Integer(253));
145 htmlEntities.put("thorn", new Integer(254));
146 htmlEntities.put("yuml", new Integer(255));
147 htmlEntities.put("fnof", new Integer(402));
148 htmlEntities.put("Alpha", new Integer(913));
149 htmlEntities.put("Beta", new Integer(914));
150 htmlEntities.put("Gamma", new Integer(915));
151 htmlEntities.put("Delta", new Integer(916));
152 htmlEntities.put("Epsilon", new Integer(917));
153 htmlEntities.put("Zeta", new Integer(918));
154 htmlEntities.put("Eta", new Integer(919));
155 htmlEntities.put("Theta", new Integer(920));
156 htmlEntities.put("Iota", new Integer(921));
157 htmlEntities.put("Kappa", new Integer(922));
158 htmlEntities.put("Lambda", new Integer(923));
159 htmlEntities.put("Mu", new Integer(924));
160 htmlEntities.put("Nu", new Integer(925));
161 htmlEntities.put("Xi", new Integer(926));
162 htmlEntities.put("Omicron", new Integer(927));
163 htmlEntities.put("Pi", new Integer(928));
164 htmlEntities.put("Rho", new Integer(929));
165 htmlEntities.put("Sigma", new Integer(931));
166 htmlEntities.put("Tau", new Integer(932));
167 htmlEntities.put("Upsilon", new Integer(933));
168 htmlEntities.put("Phi", new Integer(934));
169 htmlEntities.put("Chi", new Integer(935));
170 htmlEntities.put("Psi", new Integer(936));
171 htmlEntities.put("Omega", new Integer(937));
172 htmlEntities.put("alpha", new Integer(945));
173 htmlEntities.put("beta", new Integer(946));
174 htmlEntities.put("gamma", new Integer(947));
175 htmlEntities.put("delta", new Integer(948));
176 htmlEntities.put("epsilon", new Integer(949));
177 htmlEntities.put("zeta", new Integer(950));
178 htmlEntities.put("eta", new Integer(951));
179 htmlEntities.put("theta", new Integer(952));
180 htmlEntities.put("iota", new Integer(953));
181 htmlEntities.put("kappa", new Integer(954));
182 htmlEntities.put("lambda", new Integer(955));
183 htmlEntities.put("mu", new Integer(956));
184 htmlEntities.put("nu", new Integer(957));
185 htmlEntities.put("xi", new Integer(958));
186 htmlEntities.put("omicron", new Integer(959));
187 htmlEntities.put("pi", new Integer(960));
188 htmlEntities.put("rho", new Integer(961));
189 htmlEntities.put("sigmaf", new Integer(962));
190 htmlEntities.put("sigma", new Integer(963));
191 htmlEntities.put("tau", new Integer(964));
192 htmlEntities.put("upsilon", new Integer(965));
193 htmlEntities.put("phi", new Integer(966));
194 htmlEntities.put("chi", new Integer(967));
195 htmlEntities.put("psi", new Integer(968));
196 htmlEntities.put("omega", new Integer(969));
197 htmlEntities.put("thetasym", new Integer(977));
198 htmlEntities.put("upsih", new Integer(978));
199 htmlEntities.put("piv", new Integer(982));
200 htmlEntities.put("bull", new Integer(8226));
201 htmlEntities.put("hellip", new Integer(8230));
202 htmlEntities.put("prime", new Integer(8242));
203 htmlEntities.put("Prime", new Integer(8243));
204 htmlEntities.put("oline", new Integer(8254));
205 htmlEntities.put("frasl", new Integer(8260));
206 htmlEntities.put("weierp", new Integer(8472));
207 htmlEntities.put("image", new Integer(8465));
208 htmlEntities.put("real", new Integer(8476));
209 htmlEntities.put("trade", new Integer(8482));
210 htmlEntities.put("alefsym", new Integer(8501));
211 htmlEntities.put("larr", new Integer(8592));
212 htmlEntities.put("uarr", new Integer(8593));
213 htmlEntities.put("rarr", new Integer(8594));
214 htmlEntities.put("darr", new Integer(8595));
215 htmlEntities.put("harr", new Integer(8596));
216 htmlEntities.put("crarr", new Integer(8629));
217 htmlEntities.put("lArr", new Integer(8656));
218 htmlEntities.put("uArr", new Integer(8657));
219 htmlEntities.put("rArr", new Integer(8658));
220 htmlEntities.put("dArr", new Integer(8659));
221 htmlEntities.put("hArr", new Integer(8660));
222 htmlEntities.put("forall", new Integer(8704));
223 htmlEntities.put("part", new Integer(8706));
224 htmlEntities.put("exist", new Integer(8707));
225 htmlEntities.put("empty", new Integer(8709));
226 htmlEntities.put("nabla", new Integer(8711));
227 htmlEntities.put("isin", new Integer(8712));
228 htmlEntities.put("notin", new Integer(8713));
229 htmlEntities.put("ni", new Integer(8715));
230 htmlEntities.put("prod", new Integer(8719));
231 htmlEntities.put("sum", new Integer(8721));
232 htmlEntities.put("minus", new Integer(8722));
233 htmlEntities.put("lowast", new Integer(8727));
234 htmlEntities.put("radic", new Integer(8730));
235 htmlEntities.put("prop", new Integer(8733));
236 htmlEntities.put("infin", new Integer(8734));
237 htmlEntities.put("ang", new Integer(8736));
238 htmlEntities.put("and", new Integer(8743));
239 htmlEntities.put("or", new Integer(8744));
240 htmlEntities.put("cap", new Integer(8745));
241 htmlEntities.put("cup", new Integer(8746));
242 htmlEntities.put("int", new Integer(8747));
243 htmlEntities.put("there4", new Integer(8756));
244 htmlEntities.put("sim", new Integer(8764));
245 htmlEntities.put("cong", new Integer(8773));
246 htmlEntities.put("asymp", new Integer(8776));
247 htmlEntities.put("ne", new Integer(8800));
248 htmlEntities.put("equiv", new Integer(8801));
249 htmlEntities.put("le", new Integer(8804));
250 htmlEntities.put("ge", new Integer(8805));
251 htmlEntities.put("sub", new Integer(8834));
252 htmlEntities.put("sup", new Integer(8835));
253 htmlEntities.put("nsub", new Integer(8836));
254 htmlEntities.put("sube", new Integer(8838));
255 htmlEntities.put("supe", new Integer(8839));
256 htmlEntities.put("oplus", new Integer(8853));
257 htmlEntities.put("otimes", new Integer(8855));
258 htmlEntities.put("perp", new Integer(8869));
259 htmlEntities.put("sdot", new Integer(8901));
260 htmlEntities.put("lceil", new Integer(8968));
261 htmlEntities.put("rceil", new Integer(8969));
262 htmlEntities.put("lfloor", new Integer(8970));
263 htmlEntities.put("rfloor", new Integer(8971));
264 htmlEntities.put("lang", new Integer(9001));
265 htmlEntities.put("rang", new Integer(9002));
266 htmlEntities.put("loz", new Integer(9674));
267 htmlEntities.put("spades", new Integer(9824));
268 htmlEntities.put("clubs", new Integer(9827));
269 htmlEntities.put("hearts", new Integer(9829));
270 htmlEntities.put("diams", new Integer(9830));
271 htmlEntities.put("quot", new Integer(34));
272 htmlEntities.put("amp", new Integer(38));
273 htmlEntities.put("lt", new Integer(60));
274 htmlEntities.put("gt", new Integer(62));
275 htmlEntities.put("OElig", new Integer(338));
276 htmlEntities.put("oelig", new Integer(339));
277 htmlEntities.put("Scaron", new Integer(352));
278 htmlEntities.put("scaron", new Integer(353));
279 htmlEntities.put("Yuml", new Integer(376));
280 htmlEntities.put("circ", new Integer(710));
281 htmlEntities.put("tilde", new Integer(732));
282 htmlEntities.put("ensp", new Integer(8194));
283 htmlEntities.put("emsp", new Integer(8195));
284 htmlEntities.put("thinsp", new Integer(8201));
285 htmlEntities.put("zwnj", new Integer(8204));
286 htmlEntities.put("zwj", new Integer(8205));
287 htmlEntities.put("lrm", new Integer(8206));
288 htmlEntities.put("rlm", new Integer(8207));
289 htmlEntities.put("ndash", new Integer(8211));
290 htmlEntities.put("mdash", new Integer(8212));
291 htmlEntities.put("lsquo", new Integer(8216));
292 htmlEntities.put("rsquo", new Integer(8217));
293 htmlEntities.put("sbquo", new Integer(8218));
294 htmlEntities.put("ldquo", new Integer(8220));
295 htmlEntities.put("rdquo", new Integer(8221));
296 htmlEntities.put("bdquo", new Integer(8222));
297 htmlEntities.put("dagger", new Integer(8224));
298 htmlEntities.put("Dagger", new Integer(8225));
299 htmlEntities.put("permil", new Integer(8240));
300 htmlEntities.put("lsaquo", new Integer(8249));
301 htmlEntities.put("rsaquo", new Integer(8250));
302 htmlEntities.put("euro", new Integer(8364));
303 }
304
305 /***
306 * Pad the beginning of the given String with spaces until
307 * the String is of the given length.
308 * <p>
309 * If a String is longer than the desired length,
310 * it will not be truncated, however no padding
311 * will be added.
312 *
313 * @param s String to be padded.
314 * @param length desired length of result.
315 * @return padded String.
316 * @throws NullPointerException if s is null.
317 *
318 * @since ostermillerutils 1.00.00
319 */
320 public static String prepad(String s, int length) {
321 return prepad(s, length, ' ');
322 }
323
324 /***
325 * Pre-pend the given character to the String until
326 * the result is the desired length.
327 * <p>
328 * If a String is longer than the desired length,
329 * it will not be truncated, however no padding
330 * will be added.
331 *
332 * @param s String to be padded.
333 * @param length desired length of result.
334 * @param c padding character.
335 * @return padded String.
336 * @throws NullPointerException if s is null.
337 *
338 * @since ostermillerutils 1.00.00
339 */
340 public static String prepad(String s, int length, char c) {
341 int needed = length - s.length();
342
343 if (needed <= 0) {
344 return s;
345 }
346
347 StringBuffer sb = new StringBuffer(length);
348
349 for (int i = 0; i < needed; i++) {
350 sb.append(c);
351 }
352
353 sb.append(s);
354
355 return (sb.toString());
356 }
357
358 /***
359 * Pad the end of the given String with spaces until
360 * the String is of the given length.
361 * <p>
362 * If a String is longer than the desired length,
363 * it will not be truncated, however no padding
364 * will be added.
365 *
366 * @param s String to be padded.
367 * @param length desired length of result.
368 * @return padded String.
369 * @throws NullPointerException if s is null.
370 *
371 * @since ostermillerutils 1.00.00
372 */
373 public static String postpad(String s, int length) {
374 return postpad(s, length, ' ');
375 }
376
377 /***
378 * Append the given character to the String until
379 * the result is the desired length.
380 * <p>
381 * If a String is longer than the desired length,
382 * it will not be truncated, however no padding
383 * will be added.
384 *
385 * @param s String to be padded.
386 * @param length desired length of result.
387 * @param c padding character.
388 * @return padded String.
389 * @throws NullPointerException if s is null.
390 *
391 * @since ostermillerutils 1.00.00
392 */
393 public static String postpad(String s, int length, char c) {
394 int needed = length - s.length();
395
396 if (needed <= 0) {
397 return s;
398 }
399
400 StringBuffer sb = new StringBuffer(length);
401 sb.append(s);
402
403 for (int i = 0; i < needed; i++) {
404 sb.append(c);
405 }
406
407 return (sb.toString());
408 }
409
410 /***
411 * Pad the beginning and end of the given String with spaces until
412 * the String is of the given length. The result is that the original
413 * String is centered in the middle of the new string.
414 * <p>
415 * If the number of characters to pad is even, then the padding
416 * will be split evenly between the beginning and end, otherwise,
417 * the extra character will be added to the end.
418 * <p>
419 * If a String is longer than the desired length,
420 * it will not be truncated, however no padding
421 * will be added.
422 *
423 * @param s String to be padded.
424 * @param length desired length of result.
425 * @return padded String.
426 * @throws NullPointerException if s is null.
427 *
428 * @since ostermillerutils 1.00.00
429 */
430 public static String midpad(String s, int length) {
431 return midpad(s, length, ' ');
432 }
433
434 /***
435 * Pad the beginning and end of the given String with the given character
436 * until the result is the desired length. The result is that the original
437 * String is centered in the middle of the new string.
438 * <p>
439 * If the number of characters to pad is even, then the padding
440 * will be split evenly between the beginning and end, otherwise,
441 * the extra character will be added to the end.
442 * <p>
443 * If a String is longer than the desired length,
444 * it will not be truncated, however no padding
445 * will be added.
446 *
447 * @param s String to be padded.
448 * @param length desired length of result.
449 * @param c padding character.
450 * @return padded String.
451 * @throws NullPointerException if s is null.
452 *
453 * @since ostermillerutils 1.00.00
454 */
455 public static String midpad(String s, int length, char c) {
456 int needed = length - s.length();
457
458 if (needed <= 0) {
459 return s;
460 }
461
462 int beginning = needed / 2;
463 int end = beginning + (needed % 2);
464 StringBuffer sb = new StringBuffer(length);
465
466 for (int i = 0; i < beginning; i++) {
467 sb.append(c);
468 }
469
470 sb.append(s);
471
472 for (int i = 0; i < end; i++) {
473 sb.append(c);
474 }
475
476 return (sb.toString());
477 }
478
479 /***
480 * Split the given String into tokens.
481 * <P>
482 * This method is meant to be similar to the split
483 * function in other programming languages but it does
484 * not use regular expressions. Rather the String is
485 * split on a single String literal.
486 * <P>
487 * Unlike java.util.StringTokenizer which accepts
488 * multiple character tokens as delimiters, the delimiter
489 * here is a single String literal.
490 * <P>
491 * Each null token is returned as an empty String.
492 * Delimiters are never returned as tokens.
493 * <P>
494 * If there is no delimiter because it is either empty or
495 * null, the only element in the result is the original String.
496 * <P>
497 * StringHelper.split("1-2-3", "-");<br>
498 * result: {"1", "2", "3"}<br>
499 * StringHelper.split("-1--2-", "-");<br>
500 * result: {"", "1", ,"", "2", ""}<br>
501 * StringHelper.split("123", "");<br>
502 * result: {"123"}<br>
503 * StringHelper.split("1-2---3----4", "--");<br>
504 * result: {"1-2", "-3", "", "4"}<br>
505 *
506 * @param s String to be split.
507 * @param delimiter String literal on which to split.
508 * @return an array of tokens.
509 * @throws NullPointerException if s is null.
510 *
511 * @since ostermillerutils 1.00.00
512 */
513 public static String[] split(String s, String delimiter) {
514 int delimiterLength;
515
516
517
518 int stringLength = s.length();
519
520 if ((delimiter == null) ||
521 ((delimiterLength = delimiter.length()) == 0)) {
522
523
524
525
526
527
528
529 return new String[] { s };
530 }
531
532
533
534
535
536 int count;
537 int start;
538 int end;
539
540
541 count = 0;
542 start = 0;
543
544 while ((end = s.indexOf(delimiter, start)) != -1) {
545 count++;
546 start = end + delimiterLength;
547 }
548
549 count++;
550
551
552
553 String[] result = new String[count];
554
555
556 count = 0;
557 start = 0;
558
559 while ((end = s.indexOf(delimiter, start)) != -1) {
560 result[count] = (s.substring(start, end));
561 count++;
562 start = end + delimiterLength;
563 }
564
565 end = stringLength;
566 result[count] = s.substring(start, end);
567
568 return (result);
569 }
570
571 /***
572 * Replace occurrences of a substring.
573 *
574 * StringHelper.replace("1-2-3", "-", "|");<br>
575 * result: "1|2|3"<br>
576 * StringHelper.replace("-1--2-", "-", "|");<br>
577 * result: "|1||2|"<br>
578 * StringHelper.replace("123", "", "|");<br>
579 * result: "123"<br>
580 * StringHelper.replace("1-2---3----4", "--", "|");<br>
581 * result: "1-2|-3||4"<br>
582 * StringHelper.replace("1-2---3----4", "--", "---");<br>
583 * result: "1-2----3------4"<br>
584 *
585 * @param s String to be modified.
586 * @param find String to find.
587 * @param replace String to replace.
588 * @return a string with all the occurrences of the string to find replaced.
589 * @throws NullPointerException if s is null.
590 *
591 * @since ostermillerutils 1.00.00
592 */
593 public static String replace(String s, String find, String replace) {
594 int findLength;
595
596
597
598 int stringLength = s.length();
599
600 if ((find == null) || ((findLength = find.length()) == 0)) {
601
602 return s;
603 }
604
605 if (replace == null) {
606
607
608 replace = "";
609 }
610
611 int replaceLength = replace.length();
612
613
614
615
616
617
618 int length;
619
620 if (findLength == replaceLength) {
621
622
623 length = stringLength;
624 } else {
625 int count;
626 int start;
627 int end;
628
629
630 count = 0;
631 start = 0;
632
633 while ((end = s.indexOf(find, start)) != -1) {
634 count++;
635 start = end + findLength;
636 }
637
638 if (count == 0) {
639
640
641 return s;
642 }
643
644 length = stringLength - (count * (findLength - replaceLength));
645 }
646
647 int start = 0;
648 int end = s.indexOf(find, start);
649
650 if (end == -1) {
651
652
653
654
655 return s;
656 }
657
658
659
660 StringBuffer sb = new StringBuffer(length);
661
662
663 while (end != -1) {
664 sb.append(s.substring(start, end));
665 sb.append(replace);
666 start = end + findLength;
667 end = s.indexOf(find, start);
668 }
669
670 end = stringLength;
671 sb.append(s.substring(start, end));
672
673 return (sb.toString());
674 }
675
676 /***
677 * Replaces characters that may be confused by a HTML
678 * parser with their equivalent character entity references.
679 * <p>
680 * Any data that will appear as text on a web page should
681 * be be escaped. This is especially important for data
682 * that comes from untrusted sources such as Internet users.
683 * A common mistake in CGI programming is to ask a user for
684 * data and then put that data on a web page. For example:<pre>
685 * Server: What is your name?
686 * User: <b>Joe<b>
687 * Server: Hello <b>Joe</b>, Welcome</pre>
688 * If the name is put on the page without checking that it doesn't
689 * contain HTML code or without sanitizing that HTML code, the user
690 * could reformat the page, insert scripts, and control the the
691 * content on your web server.
692 * <p>
693 * This method will replace HTML characters such as > with their
694 * HTML entity reference (&gt;) so that the html parser will
695 * be sure to interpret them as plain text rather than HTML or script.
696 * <p>
697 * This method should be used for both data to be displayed in text
698 * in the html document, and data put in form elements. For example:<br>
699 * <code><html><body><i>This in not a &lt;tag&gt;
700 * in HTML</i></body></html></code><br>
701 * and<br>
702 * <code><form><input type="hidden" name="date" value="<i>This data could
703 * be &quot;malicious&quot;</i>"></form></code><br>
704 * In the second example, the form data would be properly be resubmitted
705 * to your cgi script in the URLEncoded format:<br>
706 * <code><i>This data could be %22malicious%22</i></code>
707 *
708 * @param s String to be escaped
709 * @return escaped String
710 * @throws NullPointerException if s is null.
711 *
712 * @since ostermillerutils 1.00.00
713 */
714 public static String escapeHTML(String s) {
715 int length = s.length();
716 int newLength = length;
717 boolean someCharacterEscaped = false;
718
719
720
721
722 for (int i = 0; i < length; i++) {
723 char c = s.charAt(i);
724 int cint = 0xffff & c;
725
726 if (cint < 32) {
727 switch (c) {
728 case '\r':
729 case '\n':
730 case '\t':
731 case '\f': {
732 }
733
734 break;
735
736 default: {
737 newLength -= 1;
738 someCharacterEscaped = true;
739 }
740 }
741 } else {
742 switch (c) {
743 case '\"': {
744 newLength += 5;
745 someCharacterEscaped = true;
746 }
747
748 break;
749
750 case '&':
751 case '\'': {
752 newLength += 4;
753 someCharacterEscaped = true;
754 }
755
756 break;
757
758 case '<':
759 case '>': {
760 newLength += 3;
761 someCharacterEscaped = true;
762 }
763
764 break;
765 }
766 }
767 }
768
769 if (!someCharacterEscaped) {
770
771 return s;
772 }
773
774 StringBuffer sb = new StringBuffer(newLength);
775
776 for (int i = 0; i < length; i++) {
777 char c = s.charAt(i);
778 int cint = 0xffff & c;
779
780 if (cint < 32) {
781 switch (c) {
782 case '\r':
783 case '\n':
784 case '\t':
785 case '\f':sb.append(c);
786
787 break;
788
789 default: {
790
791 }
792 }
793 } else {
794 switch (c) {
795 case '\"':sb.append(""");
796
797 break;
798
799 case '\'':sb.append("'");
800
801 break;
802
803 case '&':sb.append("&");
804
805 break;
806
807 case '<':sb.append("<");
808
809 break;
810
811 case '>':sb.append(">");
812
813 break;
814
815 default:sb.append(c);
816 }
817 }
818 }
819
820 return sb.toString();
821 }
822
823 /***
824 * Replaces characters that may be confused by an SQL
825 * parser with their equivalent escape characters.
826 * <p>
827 * Any data that will be put in an SQL query should
828 * be be escaped. This is especially important for data
829 * that comes from untrusted sources such as Internet users.
830 * <p>
831 * For example if you had the following SQL query:<br>
832 * <code>"SELECT * FROM addresses WHERE name='" + name + "' AND private='N'"</code><br>
833 * Without this function a user could give <code>" OR 1=1 OR ''='"</code>
834 * as their name causing the query to be:<br>
835 * <code>"SELECT * FROM addresses WHERE name='' OR 1=1 OR ''='' AND private='N'"</code><br>
836 * which will give all addresses, including private ones.<br>
837 * Correct usage would be:<br>
838 * <code>"SELECT * FROM addresses WHERE name='" + StringHelper.escapeSQL(name) + "' AND private='N'"</code><br>
839 * <p>
840 * Another way to avoid this problem is to use a PreparedStatement
841 * with appropriate placeholders.
842 *
843 * @param s String to be escaped
844 * @return escaped String
845 * @throws NullPointerException if s is null.
846 *
847 * @since ostermillerutils 1.00.00
848 */
849 public static String escapeSQL(String s) {
850 int length = s.length();
851 int newLength = length;
852
853
854
855
856 for (int i = 0; i < length; i++) {
857 char c = s.charAt(i);
858
859 switch (c) {
860 case '//':
861 case '\"':
862 case '\'':
863 case '\0':newLength += 1;
864
865 break;
866 }
867 }
868
869 if (length == newLength) {
870
871 return s;
872 }
873
874 StringBuffer sb = new StringBuffer(newLength);
875
876 for (int i = 0; i < length; i++) {
877 char c = s.charAt(i);
878
879 switch (c) {
880 case '//':sb.append("////");
881
882 break;
883
884 case '\"':sb.append("//\"");
885
886 break;
887
888 case '\'':sb.append("//\'");
889
890 break;
891
892 case '\0':sb.append("//0");
893
894 break;
895
896 default:sb.append(c);
897 }
898 }
899
900 return sb.toString();
901 }
902
903 /***
904 * Replaces characters that are not allowed in a Java style
905 * string literal with their escape characters. Specifically
906 * quote ("), single quote ('), new line (\n), carriage return (\r),
907 * and backslash (\), and tab (\t) are escaped.
908 *
909 * @param s String to be escaped
910 * @return escaped String
911 * @throws NullPointerException if s is null.
912 *
913 * @since ostermillerutils 1.00.00
914 */
915 public static String escapeJavaLiteral(String s) {
916 int length = s.length();
917 int newLength = length;
918
919
920
921
922 for (int i = 0; i < length; i++) {
923 char c = s.charAt(i);
924
925 switch (c) {
926 case '\"':
927 case '\'':
928 case '\n':
929 case '\r':
930 case '\t':
931 case '//':newLength += 1;
932
933 break;
934 }
935 }
936
937 if (length == newLength) {
938
939 return s;
940 }
941
942 StringBuffer sb = new StringBuffer(newLength);
943
944 for (int i = 0; i < length; i++) {
945 char c = s.charAt(i);
946
947 switch (c) {
948 case '\"':sb.append("//\"");
949
950 break;
951
952 case '\'':sb.append("//\'");
953
954 break;
955
956 case '\n':sb.append("//n");
957
958 break;
959
960 case '\r':sb.append("//r");
961
962 break;
963
964 case '\t':sb.append("//t");
965
966 break;
967
968 case '//':sb.append("////");
969
970 break;
971
972 default:sb.append(c);
973 }
974 }
975
976 return sb.toString();
977 }
978
979 /***
980 * Trim any of the characters contained in the second
981 * string from the beginning and end of the first.
982 *
983 * @param s String to be trimmed.
984 * @param c list of characters to trim from s.
985 * @return trimmed String.
986 * @throws NullPointerException if s is null.
987 *
988 * @since ostermillerutils 1.00.00
989 */
990 public static String trim(String s, String c) {
991 int length = s.length();
992
993 if (c == null) {
994 return s;
995 }
996
997 int cLength = c.length();
998
999 if (c.length() == 0) {
1000 return s;
1001 }
1002
1003 int start = 0;
1004 int end = length;
1005 boolean found;
1006 int i;
1007
1008
1009
1010 found = false;
1011
1012 for (i = 0; !found && (i < length); i++) {
1013 char ch = s.charAt(i);
1014 found = true;
1015
1016 for (int j = 0; found && (j < cLength); j++) {
1017 if (c.charAt(j) == ch) {
1018 found = false;
1019 }
1020 }
1021 }
1022
1023
1024 if (!found) {
1025 return "";
1026 }
1027
1028 start = i - 1;
1029
1030
1031
1032 found = false;
1033
1034 for (i = length - 1; !found && (i >= 0); i--) {
1035 char ch = s.charAt(i);
1036 found = true;
1037
1038 for (int j = 0; found && (j < cLength); j++) {
1039 if (c.charAt(j) == ch) {
1040 found = false;
1041 }
1042 }
1043 }
1044
1045 end = i + 2;
1046
1047 return s.substring(start, end);
1048 }
1049
1050 /***
1051 * Turn any HTML escape entities in the string into
1052 * characters and return the resulting string.
1053 *
1054 * @param s String to be unescaped.
1055 * @return unescaped String.
1056 * @throws NullPointerException if s is null.
1057 *
1058 * @since ostermillerutils 1.00.00
1059 */
1060 public static String unescapeHTML(String s) {
1061 StringBuffer result = new StringBuffer(s.length());
1062 int ampInd = s.indexOf("&");
1063 int lastEnd = 0;
1064
1065 while (ampInd >= 0) {
1066 int nextAmp = s.indexOf("&", ampInd + 1);
1067 int nextSemi = s.indexOf(";", ampInd + 1);
1068
1069 if ((nextSemi != -1) && ((nextAmp == -1) || (nextSemi < nextAmp))) {
1070 int value = -1;
1071 String escape = s.substring(ampInd + 1, nextSemi);
1072
1073 try {
1074 if (escape.startsWith("#")) {
1075 value = Integer.parseInt(escape.substring(1), 10);
1076 } else {
1077 if (htmlEntities.containsKey(escape)) {
1078 value = ((Integer) (htmlEntities.get(escape))).intValue();
1079 }
1080 }
1081 } catch (NumberFormatException x) {
1082 }
1083
1084 result.append(s.substring(lastEnd, ampInd));
1085 lastEnd = nextSemi + 1;
1086
1087 if ((value >= 0) && (value <= 0xffff)) {
1088 result.append((char) value);
1089 } else {
1090 result.append("&").append(escape).append(";");
1091 }
1092 }
1093
1094 ampInd = nextAmp;
1095 }
1096
1097 result.append(s.substring(lastEnd));
1098
1099 return result.toString();
1100 }
1101
1102 /***
1103 * Escapes characters that have special meaning to
1104 * regular expressions
1105 *
1106 * @param s String to be escaped
1107 * @return escaped String
1108 * @throws NullPointerException if s is null.
1109 *
1110 * @since ostermillerutils 1.02.25
1111 */
1112 public static String escapeRegularExpressionLiteral(String s) {
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127 int length = s.length();
1128 int newLength = length;
1129
1130
1131
1132
1133 for (int i = 0; i < length; i++) {
1134 char c = s.charAt(i);
1135
1136 if (!(((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) ||
1137 ((c >= 'a') && (c <= 'z')))) {
1138 newLength += 1;
1139 }
1140 }
1141
1142 if (length == newLength) {
1143
1144 return s;
1145 }
1146
1147 StringBuffer sb = new StringBuffer(newLength);
1148
1149 for (int i = 0; i < length; i++) {
1150 char c = s.charAt(i);
1151
1152 if (!(((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) ||
1153 ((c >= 'a') && (c <= 'z')))) {
1154 sb.append('//');
1155 }
1156
1157 sb.append(c);
1158 }
1159
1160 return sb.toString();
1161 }
1162
1163 /***
1164 * Build a regular expression that is each of the terms or'd together.
1165 *
1166 * @param terms a list of search terms.
1167 * @param sb place to build the regular expression.
1168 * @throws IllegalArgumentException if the length of terms is zero.
1169 *
1170 * @since ostermillerutils 1.02.25
1171 */
1172 private static void buildFindAnyPattern(String[] terms, StringBuffer sb) {
1173 if (terms.length == 0) {
1174 throw new IllegalArgumentException(
1175 "There must be at least one term to find.");
1176 }
1177
1178 sb.append("(?:");
1179
1180 for (int i = 0; i < terms.length; i++) {
1181 if (i > 0) {
1182 sb.append("|");
1183 }
1184
1185 sb.append("(?:");
1186 sb.append(escapeRegularExpressionLiteral(terms[i]));
1187 sb.append(")");
1188 }
1189
1190 sb.append(")");
1191 }
1192
1193 /***
1194 * Compile a pattern that can will match a string if the string
1195 * contains any of the given terms.
1196 * <p>
1197 * Usage:<br>
1198 * <code>boolean b = getContainsAnyPattern(terms).matcher(s).matches();</code>
1199 * <p>
1200 * If multiple strings are matched against the same set of terms,
1201 * it is more efficient to reuse the pattern returned by this function.
1202 *
1203 * @param terms Array of search strings.
1204 * @return Compiled pattern that can be used to match a string to see if it contains any of the terms.
1205 *
1206 * @since ostermillerutils 1.02.25
1207 */
1208 public static Pattern getContainsAnyPattern(String[] terms) {
1209 StringBuffer sb = new StringBuffer();
1210 sb.append("(?s).*");
1211 buildFindAnyPattern(terms, sb);
1212 sb.append(".*");
1213
1214 return Pattern.compile(sb.toString());
1215 }
1216
1217 /***
1218 * Compile a pattern that can will match a string if the string
1219 * equals any of the given terms.
1220 * <p>
1221 * Usage:<br>
1222 * <code>boolean b = getEqualsAnyPattern(terms).matcher(s).matches();</code>
1223 * <p>
1224 * If multiple strings are matched against the same set of terms,
1225 * it is more efficient to reuse the pattern returned by this function.
1226 *
1227 * @param terms Array of search strings.
1228 * @return Compiled pattern that can be used to match a string to see if it equals any of the terms.
1229 *
1230 * @since ostermillerutils 1.02.25
1231 */
1232 public static Pattern getEqualsAnyPattern(String[] terms) {
1233 StringBuffer sb = new StringBuffer();
1234 sb.append("(?s)//A");
1235 buildFindAnyPattern(terms, sb);
1236 sb.append("//z");
1237
1238 return Pattern.compile(sb.toString());
1239 }
1240
1241 /***
1242 * Compile a pattern that can will match a string if the string
1243 * starts with any of the given terms.
1244 * <p>
1245 * Usage:<br>
1246 * <code>boolean b = getStartsWithAnyPattern(terms).matcher(s).matches();</code>
1247 * <p>
1248 * If multiple strings are matched against the same set of terms,
1249 * it is more efficient to reuse the pattern returned by this function.
1250 *
1251 * @param terms Array of search strings.
1252 * @return Compiled pattern that can be used to match a string to see if it starts with any of the terms.
1253 *
1254 * @since ostermillerutils 1.02.25
1255 */
1256 public static Pattern getStartsWithAnyPattern(String[] terms) {
1257 StringBuffer sb = new StringBuffer();
1258 sb.append("(?s)//A");
1259 buildFindAnyPattern(terms, sb);
1260 sb.append(".*");
1261
1262 return Pattern.compile(sb.toString());
1263 }
1264
1265 /***
1266 * Compile a pattern that can will match a string if the string
1267 * ends with any of the given terms.
1268 * <p>
1269 * Usage:<br>
1270 * <code>boolean b = getEndsWithAnyPattern(terms).matcher(s).matches();</code>
1271 * <p>
1272 * If multiple strings are matched against the same set of terms,
1273 * it is more efficient to reuse the pattern returned by this function.
1274 *
1275 * @param terms Array of search strings.
1276 * @return Compiled pattern that can be used to match a string to see if it ends with any of the terms.
1277 *
1278 * @since ostermillerutils 1.02.25
1279 */
1280 public static Pattern getEndsWithAnyPattern(String[] terms) {
1281 StringBuffer sb = new StringBuffer();
1282 sb.append("(?s).*");
1283 buildFindAnyPattern(terms, sb);
1284 sb.append("//z");
1285
1286 return Pattern.compile(sb.toString());
1287 }
1288
1289 /***
1290 * Compile a pattern that can will match a string if the string
1291 * contains any of the given terms.
1292 * <p>
1293 * Case is ignored when matching using Unicode case rules.
1294 * <p>
1295 * Usage:<br>
1296 * <code>boolean b = getContainsAnyPattern(terms).matcher(s).matches();</code>
1297 * <p>
1298 * If multiple strings are matched against the same set of terms,
1299 * it is more efficient to reuse the pattern returned by this function.
1300 *
1301 * @param terms Array of search strings.
1302 * @return Compiled pattern that can be used to match a string to see if it contains any of the terms.
1303 *
1304 * @since ostermillerutils 1.02.25
1305 */
1306 public static Pattern getContainsAnyIgnoreCasePattern(String[] terms) {
1307 StringBuffer sb = new StringBuffer();
1308 sb.append("(?i)(?u)(?s).*");
1309 buildFindAnyPattern(terms, sb);
1310 sb.append(".*");
1311
1312 return Pattern.compile(sb.toString());
1313 }
1314
1315 /***
1316 * Compile a pattern that can will match a string if the string
1317 * equals any of the given terms.
1318 * <p>
1319 * Case is ignored when matching using Unicode case rules.
1320 * <p>
1321 * Usage:<br>
1322 * <code>boolean b = getEqualsAnyPattern(terms).matcher(s).matches();</code>
1323 * <p>
1324 * If multiple strings are matched against the same set of terms,
1325 * it is more efficient to reuse the pattern returned by this function.
1326 *
1327 * @param terms Array of search strings.
1328 * @return Compiled pattern that can be used to match a string to see if it equals any of the terms.
1329 *
1330 * @since ostermillerutils 1.02.25
1331 */
1332 public static Pattern getEqualsAnyIgnoreCasePattern(String[] terms) {
1333 StringBuffer sb = new StringBuffer();
1334 sb.append("(?i)(?u)(?s)//A");
1335 buildFindAnyPattern(terms, sb);
1336 sb.append("//z");
1337
1338 return Pattern.compile(sb.toString());
1339 }
1340
1341 /***
1342 * Compile a pattern that can will match a string if the string
1343 * starts with any of the given terms.
1344 * <p>
1345 * Case is ignored when matching using Unicode case rules.
1346 * <p>
1347 * Usage:<br>
1348 * <code>boolean b = getStartsWithAnyPattern(terms).matcher(s).matches();</code>
1349 * <p>
1350 * If multiple strings are matched against the same set of terms,
1351 * it is more efficient to reuse the pattern returned by this function.
1352 *
1353 * @param terms Array of search strings.
1354 * @return Compiled pattern that can be used to match a string to see if it starts with any of the terms.
1355 *
1356 * @since ostermillerutils 1.02.25
1357 */
1358 public static Pattern getStartsWithAnyIgnoreCasePattern(String[] terms) {
1359 StringBuffer sb = new StringBuffer();
1360 sb.append("(?i)(?u)(?s)//A");
1361 buildFindAnyPattern(terms, sb);
1362 sb.append(".*");
1363
1364 return Pattern.compile(sb.toString());
1365 }
1366
1367 /***
1368 * Compile a pattern that can will match a string if the string
1369 * ends with any of the given terms.
1370 * <p>
1371 * Case is ignored when matching using Unicode case rules.
1372 * <p>
1373 * Usage:<br>
1374 * <code>boolean b = getEndsWithAnyPattern(terms).matcher(s).matches();</code>
1375 * <p>
1376 * If multiple strings are matched against the same set of terms,
1377 * it is more efficient to reuse the pattern returned by this function.
1378 *
1379 * @param terms Array of search strings.
1380 * @return Compiled pattern that can be used to match a string to see if it ends with any of the terms.
1381 *
1382 * @since ostermillerutils 1.02.25
1383 */
1384 public static Pattern getEndsWithAnyIgnoreCasePattern(String[] terms) {
1385 StringBuffer sb = new StringBuffer();
1386 sb.append("(?i)(?u)(?s).*");
1387 buildFindAnyPattern(terms, sb);
1388 sb.append("//z");
1389
1390 return Pattern.compile(sb.toString());
1391 }
1392
1393 /***
1394 * Tests to see if the given string contains any of the given terms.
1395 * <p>
1396 * This implementation is more efficient than the brute force approach
1397 * of testing the string against each of the terms. It instead compiles
1398 * a single regular expression that can test all the terms at once, and
1399 * uses that expression against the string.
1400 * <p>
1401 * This is a convenience method. If multiple strings are tested against
1402 * the same set of terms, it is more efficient not to compile the regular
1403 * expression multiple times.
1404 * @see #getContainsAnyPattern(String[])
1405 *
1406 * @param s String that may contain any of the given terms.
1407 * @param terms list of substrings that may be contained in the given string.
1408 * @return true iff one of the terms is a substring of the given string.
1409 *
1410 * @since ostermillerutils 1.02.25
1411 */
1412 public static boolean containsAny(String s, String[] terms) {
1413 return getContainsAnyPattern(terms).matcher(s).matches();
1414 }
1415
1416 /***
1417 * Tests to see if the given string equals any of the given terms.
1418 * <p>
1419 * This implementation is more efficient than the brute force approach
1420 * of testing the string against each of the terms. It instead compiles
1421 * a single regular expression that can test all the terms at once, and
1422 * uses that expression against the string.
1423 * <p>
1424 * This is a convenience method. If multiple strings are tested against
1425 * the same set of terms, it is more efficient not to compile the regular
1426 * expression multiple times.
1427 * @see #getEqualsAnyPattern(String[])
1428 *
1429 * @param s String that may equal any of the given terms.
1430 * @param terms list of strings that may equal the given string.
1431 * @return true iff one of the terms is equal to the given string.
1432 *
1433 * @since ostermillerutils 1.02.25
1434 */
1435 public static boolean equalsAny(String s, String[] terms) {
1436 return getEqualsAnyPattern(terms).matcher(s).matches();
1437 }
1438
1439 /***
1440 * Tests to see if the given string starts with any of the given terms.
1441 * <p>
1442 * This implementation is more efficient than the brute force approach
1443 * of testing the string against each of the terms. It instead compiles
1444 * a single regular expression that can test all the terms at once, and
1445 * uses that expression against the string.
1446 * <p>
1447 * This is a convenience method. If multiple strings are tested against
1448 * the same set of terms, it is more efficient not to compile the regular
1449 * expression multiple times.
1450 * @see #getStartsWithAnyPattern(String[])
1451 *
1452 * @param s String that may start with any of the given terms.
1453 * @param terms list of strings that may start with the given string.
1454 * @return true iff the given string starts with one of the given terms.
1455 *
1456 * @since ostermillerutils 1.02.25
1457 */
1458 public static boolean startsWithAny(String s, String[] terms) {
1459 return getStartsWithAnyPattern(terms).matcher(s).matches();
1460 }
1461
1462 /***
1463 * Tests to see if the given string ends with any of the given terms.
1464 * <p>
1465 * This implementation is more efficient than the brute force approach
1466 * of testing the string against each of the terms. It instead compiles
1467 * a single regular expression that can test all the terms at once, and
1468 * uses that expression against the string.
1469 * <p>
1470 * This is a convenience method. If multiple strings are tested against
1471 * the same set of terms, it is more efficient not to compile the regular
1472 * expression multiple times.
1473 * @see #getEndsWithAnyPattern(String[])
1474 *
1475 * @param s String that may end with any of the given terms.
1476 * @param terms list of strings that may end with the given string.
1477 * @return true iff the given string ends with one of the given terms.
1478 *
1479 * @since ostermillerutils 1.02.25
1480 */
1481 public static boolean endsWithAny(String s, String[] terms) {
1482 return getEndsWithAnyPattern(terms).matcher(s).matches();
1483 }
1484
1485 /***
1486 * Tests to see if the given string contains any of the given terms.
1487 * <p>
1488 * Case is ignored when matching using Unicode case rules.
1489 * <p>
1490 * This implementation is more efficient than the brute force approach
1491 * of testing the string against each of the terms. It instead compiles
1492 * a single regular expression that can test all the terms at once, and
1493 * uses that expression against the string.
1494 * <p>
1495 * This is a convenience method. If multiple strings are tested against
1496 * the same set of terms, it is more efficient not to compile the regular
1497 * expression multiple times.
1498 * @see #getContainsAnyIgnoreCasePattern(String[])
1499 *
1500 * @param s String that may contain any of the given terms.
1501 * @param terms list of substrings that may be contained in the given string.
1502 * @return true iff one of the terms is a substring of the given string.
1503 *
1504 * @since ostermillerutils 1.02.25
1505 */
1506 public static boolean containsAnyIgnoreCase(String s, String[] terms) {
1507 return getContainsAnyIgnoreCasePattern(terms).matcher(s).matches();
1508 }
1509
1510 /***
1511 * Tests to see if the given string equals any of the given terms.
1512 * <p>
1513 * Case is ignored when matching using Unicode case rules.
1514 * <p>
1515 * This implementation is more efficient than the brute force approach
1516 * of testing the string against each of the terms. It instead compiles
1517 * a single regular expression that can test all the terms at once, and
1518 * uses that expression against the string.
1519 * <p>
1520 * This is a convenience method. If multiple strings are tested against
1521 * the same set of terms, it is more efficient not to compile the regular
1522 * expression multiple times.
1523 * @see #getEqualsAnyIgnoreCasePattern(String[])
1524 *
1525 * @param s String that may equal any of the given terms.
1526 * @param terms list of strings that may equal the given string.
1527 * @return true iff one of the terms is equal to the given string.
1528 *
1529 * @since ostermillerutils 1.02.25
1530 */
1531 public static boolean equalsAnyIgnoreCase(String s, String[] terms) {
1532 return getEqualsAnyIgnoreCasePattern(terms).matcher(s).matches();
1533 }
1534
1535 /***
1536 * Tests to see if the given string starts with any of the given terms.
1537 * <p>
1538 * Case is ignored when matching using Unicode case rules.
1539 * <p>
1540 * This implementation is more efficient than the brute force approach
1541 * of testing the string against each of the terms. It instead compiles
1542 * a single regular expression that can test all the terms at once, and
1543 * uses that expression against the string.
1544 * <p>
1545 * This is a convenience method. If multiple strings are tested against
1546 * the same set of terms, it is more efficient not to compile the regular
1547 * expression multiple times.
1548 * @see #getStartsWithAnyIgnoreCasePattern(String[])
1549 *
1550 * @param s String that may start with any of the given terms.
1551 * @param terms list of strings that may start with the given string.
1552 * @return true iff the given string starts with one of the given terms.
1553 *
1554 * @since ostermillerutils 1.02.25
1555 */
1556 public static boolean startsWithAnyIgnoreCase(String s, String[] terms) {
1557 return getStartsWithAnyIgnoreCasePattern(terms).matcher(s).matches();
1558 }
1559
1560 /***
1561 * Tests to see if the given string ends with any of the given terms.
1562 * <p>
1563 * Case is ignored when matching using Unicode case rules.
1564 * <p>
1565 * This implementation is more efficient than the brute force approach
1566 * of testing the string against each of the terms. It instead compiles
1567 * a single regular expression that can test all the terms at once, and
1568 * uses that expression against the string.
1569 * <p>
1570 * This is a convenience method. If multiple strings are tested against
1571 * the same set of terms, it is more efficient not to compile the regular
1572 * expression multiple times.
1573 * @see #getEndsWithAnyIgnoreCasePattern(String[])
1574 *
1575 * @param s String that may end with any of the given terms.
1576 * @param terms list of strings that may end with the given string.
1577 * @return true iff the given string ends with one of the given terms.
1578 *
1579 * @since ostermillerutils 1.02.25
1580 */
1581 public static boolean endsWithAnyIgnoreCase(String s, String[] terms) {
1582 return getEndsWithAnyIgnoreCasePattern(terms).matcher(s).matches();
1583 }
1584 }