View Javadoc

1   /*
2    * Copyright (c) 2004, RV Test Team
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    *
8    * Redistributions of source code must retain the above copyright notice, this
9    * list of conditions and the following disclaimer.
10   *
11   * Redistributions in binary form must reproduce the above copyright notice,
12   * this list of conditions and the following disclaimer in the documentation
13   * and/or other materials provided with the distribution.
14   *
15   * Neither the name of the "RV Test Team" nor the names of its contributors may
16   * be used to endorse or promote products derived from this software without
17   * specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29   * THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   */
32  //Created on Oct 6, 2004
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         // the next statement has the side effect of throwing a null pointer
517         // exception if s is null.
518         int stringLength = s.length();
519 
520         if ((delimiter == null) ||
521                 ((delimiterLength = delimiter.length()) == 0)) {
522             // it is not inherently clear what to do if there is no delimiter
523             // On one hand it would make sense to return each character because
524             // the null String can be found between each pair of characters in
525             // a String.  However, it can be found many times there and we don'
526             // want to be returning multiple null tokens.
527             // returning the whole String will be defined as the correct behavior
528             // in this instance.
529             return new String[] { s };
530         }
531 
532         // a two pass solution is used because a one pass solution would
533         // require the possible resizing and copying of memory structures
534         // In the worst case it would have to be resized n times with each
535         // resize having a O(n) copy leading to an O(n^2) algorithm.
536         int count;
537         int start;
538         int end;
539 
540         // Scan s and count the tokens.
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         // allocate an array to return the tokens,
552         // we now know how big it should be
553         String[] result = new String[count];
554 
555         // Scan s again, but this time pick out the tokens
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         // the next statement has the side effect of throwing a null pointer
597         // exception if s is null.
598         int stringLength = s.length();
599 
600         if ((find == null) || ((findLength = find.length()) == 0)) {
601             // If there is nothing to find, we won't try and find it.
602             return s;
603         }
604 
605         if (replace == null) {
606             // a null string and an empty string are the same
607             // for replacement purposes.
608             replace = "";
609         }
610 
611         int replaceLength = replace.length();
612 
613         // We need to figure out how long our resulting string will be.
614         // This is required because without it, the possible resizing
615         // and copying of memory structures could lead to an unacceptable runtime.
616         // In the worst case it would have to be resized n times with each
617         // resize having a O(n) copy leading to an O(n^2) algorithm.
618         int length;
619 
620         if (findLength == replaceLength) {
621             // special case in which we don't need to count the replacements
622             // because the count falls out of the length formula.
623             length = stringLength;
624         } else {
625             int count;
626             int start;
627             int end;
628 
629             // Scan s and count the number of times we find our target.
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                 // special case in which on first pass, we find there is nothing
640                 // to be replaced.  No need to do a second pass or create a string buffer.
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             // nothing was found in the string to replace.
652             // we can get this if the find and replace strings
653             // are the same length because we didn't check before.
654             // in this case, we will return the original string
655             return s;
656         }
657 
658         // it looks like we actually have something to replace
659         // *sigh* allocate memory for it.
660         StringBuffer sb = new StringBuffer(length);
661 
662         // Scan s and do the replacements
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: &lt;b&gt;Joe&lt;b&gt;
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 &gt; with their
694      * HTML entity reference (&amp;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>&lt;html&gt;&lt;body&gt;<i>This in not a &amp;lt;tag&amp;gt;
700      * in HTML</i>&lt;/body&gt;&lt;/html&gt;</code><br>
701      * and<br>
702      * <code>&lt;form&gt;&lt;input type="hidden" name="date" value="<i>This data could
703      * be &amp;quot;malicious&amp;quot;</i>"&gt;&lt;/form&gt;</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         // first check for characters that might
720         // be dangerous and calculate a length
721         // of the string that has escapes.
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             // nothing to escape in the string
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                     // Remove this character
791                 }
792                 }
793             } else {
794                 switch (c) {
795                 case '\"':sb.append("&quot;");
796 
797                 break;
798 
799                 case '\'':sb.append("&#39;");
800 
801                 break;
802 
803                 case '&':sb.append("&amp;");
804 
805                 break;
806 
807                 case '<':sb.append("&lt;");
808 
809                 break;
810 
811                 case '>':sb.append("&gt;");
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         // first check for characters that might
854         // be dangerous and calculate a length
855         // of the string that has escapes.
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             // nothing to escape in the string
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         // first check for characters that might
920         // be dangerous and calculate a length
921         // of the string that has escapes.
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             // nothing to escape in the string
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; // trim-able character found.
1006         int i;
1007 
1008         // Start from the beginning and find the
1009         // first non-trim-able character.
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         // if all characters are trim-able.
1024         if (!found) {
1025             return "";
1026         }
1027 
1028         start = i - 1;
1029 
1030         // Start from the end and find the
1031         // last non-trim-able character.
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         // According to the documentation in the Pattern class:
1114         //
1115         // The backslash character ('\') serves to introduce escaped constructs,
1116         // as defined in the table above, as well as to quote characters that
1117         // otherwise would be interpreted as unescaped constructs. Thus the
1118         // expression // matches a single backslash and \{ matches a left brace.
1119         //
1120         // It is an error to use a backslash prior to any alphabetic character
1121         // that does not denote an escaped construct; these are reserved for future
1122         // extensions to the regular-expression language. A backslash may be used
1123         // prior to a non-alphabetic character regardless of whether that character
1124         // is part of an unescaped construct.
1125         //
1126         // As a result, escape everything except [0-9a-zA-Z]
1127         int length = s.length();
1128         int newLength = length;
1129 
1130         // first check for characters that might
1131         // be dangerous and calculate a length
1132         // of the string that has escapes.
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             // nothing to escape in the string
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 }