93d4c6b24332ba1311295e2c15af114aa72fb2d5
[mir.git] / source / mir / misc / StringUtil.java
1 /*
2  * Copyright (C) 2001, 2002  The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with the com.oreilly.servlet library, any library
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of
24  * the above that use the same license as the above), and distribute linked
25  * combinations including the two.  You must obey the GNU General Public
26  * License in all respects for all of the code used other than the above
27  * mentioned libraries.  If you modify this file, you may extend this exception
28  * to your version of the file, but you are not obligated to do so.  If you do
29  * not wish to do so, delete this exception statement from your version.
30  */
31
32 package  mir.misc;
33
34 import  java.io.*;
35 import  java.lang.*;
36 import  java.util.*;
37 import  java.text.NumberFormat;
38 import  gnu.regexp.*;
39
40 /**
41  * Statische Hilfsmethoden zur Stringbehandlung
42  *
43  * @version $Revision: 1.23.2.1 $ $Date: 2002/09/01 21:31:40 $
44  * @author $Author: mh $
45  *
46  * $Log: StringUtil.java,v $
47  * Revision 1.23.2.1  2002/09/01 21:31:40  mh
48  * Mir goes GPL
49  *
50  * Revision 1.23  2002/06/28 20:39:37  mh
51  * added numberformat helper. make webdbDate2readableDate use webdb_create instead. make the order and appearance of it more consistent. cvs macros. and finally code tidying
52  *
53  *
54  */
55 public final class StringUtil {
56
57         private static RE   re_newline2br, re_brbr2p, re_mail, re_url, re_tags;
58
59         private StringUtil() { }  // this avoids contruction
60
61         static {
62                 try {
63                         //precompile regex
64                         re_newline2br = new RE("(\r?\n){1}");
65                         re_brbr2p     = new RE("(<br>\r?\n<br>){1,}");
66                         re_mail       = new RE("([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_-]+).([a-zA-Z0-9_.-]+)");
67                         re_url        = new RE("((https://)|(http://)|(ftp://)){1}([a-zA-Z0-9_-]+).([a-zA-Z0-9_.:-]+)/?([^ \t\r\n<>\\)\\]]+[^ \t\r\n.,<>\\)\\]])");
68                         re_tags       = new RE("<[^>]*>",RE.REG_ICASE);
69                 }
70                 catch (REException e){
71                         System.err.println("FATAL: StringUtil: could not precompile REGEX: "+e.toString());
72                 }
73         }
74
75   /**
76    * Formats a number with the specified minimum and maximum number of digits.
77    **/
78   public static synchronized String zeroPaddingNumber(long value, int minDigits,
79                                                       int maxDigits)
80   {
81     NumberFormat numberFormat = NumberFormat.getInstance();
82     numberFormat.setMinimumIntegerDigits(minDigits);
83     numberFormat.setMaximumIntegerDigits(maxDigits);
84     return numberFormat.format(value);
85   }
86
87         /**
88          * Wandelt Datum in einen 8-ziffrigen String um (yyyymmdd)
89          * @param theDate
90          * @return 8-ziffriger String (yyyymmdd)
91          */
92
93         public static final String date2webdbDate (GregorianCalendar theDate) {
94                 StringBuffer webdbDate = new StringBuffer();
95                 webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
96                 webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
97                 webdbDate.append(pad2(theDate.get(Calendar.DATE)));
98                 return  webdbDate.toString();
99         }
100
101         /**
102          * Wandelt Calendar in einen 12-ziffrigen String um (yyyymmddhhmm)
103          * @param theDate
104          * @return 12-ziffriger String (yyyymmdd)
105          */
106
107         public static final String date2webdbDateTime (GregorianCalendar theDate) {
108                 StringBuffer webdbDate = new StringBuffer();
109                 webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
110                 webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
111                 webdbDate.append(pad2(theDate.get(Calendar.DATE)));
112                 webdbDate.append(pad2(theDate.get(Calendar.HOUR)));
113                 webdbDate.append(pad2(theDate.get(Calendar.MINUTE)));
114                 return  webdbDate.toString();
115         }
116
117         /**
118          * Return a http://www.w3.org/TR/NOTE-datetime formatted date (yyyy-mm-ddThh:mm:ssTZ)
119          * @param theDate
120          * @return w3approved datetime
121          */
122
123         public static final String date2w3DateTime (GregorianCalendar theDate) {
124                 StringBuffer webdbDate = new StringBuffer();
125                 webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
126                 webdbDate.append("-");
127                 webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
128                 webdbDate.append("-");
129                 webdbDate.append(pad2(theDate.get(Calendar.DATE)));
130                 webdbDate.append("T");
131                 webdbDate.append(pad2(theDate.get(Calendar.HOUR)));
132                 webdbDate.append(":");
133                 webdbDate.append(pad2(theDate.get(Calendar.MINUTE)));
134                 webdbDate.append(":");
135                 webdbDate.append(pad2(theDate.get(Calendar.SECOND)));
136                 //assumes you are an hour-multiple away from UTC....
137                 int offset=(theDate.get(Calendar.ZONE_OFFSET)/(60*60*1000));
138                 if (offset < 0){
139                 webdbDate.append("-");
140                 }
141                 else{
142                 webdbDate.append("+");
143                 }
144                 webdbDate.append(pad2(Math.abs(offset)));
145                 webdbDate.append(":00");
146                 return  webdbDate.toString();
147         }
148
149         /**
150          * wandelt Calendar in dd.mm.yyyy / hh.mm um
151          * @param theDate
152          * @return String mit (dd.mm.yyyy / hh.mm um)
153          */
154         public static String date2readableDateTime (GregorianCalendar theDate) {
155                 String readable = "";
156                 int hour;
157                 readable += pad2(theDate.get(Calendar.DATE));
158                 readable += "." + pad2(theDate.get(Calendar.MONTH) + 1);
159                 readable += "." + String.valueOf(theDate.get(Calendar.YEAR));
160                 hour = theDate.get(Calendar.HOUR);
161                 if (theDate.get(Calendar.AM_PM) == Calendar.PM)
162                         hour += 12;
163                 readable += " / " + pad2(hour);
164                 readable += ":" + pad2(theDate.get(Calendar.MINUTE));
165                 return  readable;
166         }
167
168         /**
169          * wandelt eine Datum in einen 8-buchstabigen String, der durch <code>/</code>
170          * getrennt ist.
171          *
172          * @param webdbDate
173          * @return String mit <code>/yyyy/mm/dd</code>
174          */
175         public static final String webdbDate2path (String webdbDate) {
176                 StringBuffer path = new StringBuffer();
177                 path.append("/").append(webdbDate.substring(0, 4));
178                 path.append("/").append(webdbDate.substring(4, 6));
179                 path.append("/");
180                 //who did this?
181                 //path.append("/").append(webdbDate.substring(6, 8));
182                 return  path.toString();
183         }
184
185         /**
186          * wandelt Calendar in dd.mm.yyyy um
187          *
188          * @param theDate
189          * @return String mit  <code>yyyy.mm.dd</code>
190          */
191         public static final String webdbDate2readableDate (String webdbDate) {
192                 String date = "";
193                 date += webdbDate.substring(0, 4);
194                 date += "-" + webdbDate.substring(5, 7);
195                 date += "-"+webdbDate.substring(8, 10);
196                 return  date;
197         }
198
199
200         /**
201          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
202          * to dd.mm.yyyy hh:mm
203          */
204         public static String dateToReadableDate(String date) {
205                 StringBuffer returnDate = new StringBuffer();
206                 if (date!=null) {
207
208                         returnDate.append(date.substring(8,10)).append('.');
209                         returnDate.append(date.substring(5,7)).append('.');
210                         returnDate.append(date.substring(0,4)).append(' ');
211                         returnDate.append(date.substring(11,16));
212                 }
213                 return returnDate.toString();
214         }
215         
216   /**
217          * converts string from format: yyyy-mm-dd__hh:mm:ss.dddddd+TZ
218          * to yyyy-mm-ddThh:mm:ss+TZ:00 (w3 format for Dublin Core)
219          */
220         public static String webdbdateToDCDate(String date) {
221                 StringBuffer returnDate = new StringBuffer();
222                 if (date!=null) {
223       returnDate.append(date.substring(0,10));
224       returnDate.append("T");
225       returnDate.append(date.substring(11,19));
226       //String tzInfo=date.substring(26,29);
227       //if (tzInfo.equals("+00")){
228       //UTC gets a special code in w3 dates
229       //    returnDate.append("Z");
230       //}
231       //else{
232       //need to see what a newfoundland postgres
233       //timestamp looks like before making this robust
234       //    returnDate.append(tzInfo);
235       //    returnDate.append(":00");
236       //}
237
238                 }
239                 return returnDate.toString();
240         }
241
242
243         /**
244          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
245          * to yyyy
246          */
247         public static String dateToYear (String date) {
248                 StringBuffer returnDate = new StringBuffer();
249                 if (date!=null) {
250
251                         returnDate.append(date.substring(0,4));
252                 }
253                 return returnDate.toString();
254         }
255
256         /**
257          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
258          * to [m]m
259          */
260         public static String dateToMonth (String date) {
261                 StringBuffer returnDate = new StringBuffer();
262                 if (date!=null) {
263                         if (!date.substring(5,6).equalsIgnoreCase("0")) returnDate.append(date.substring(5,7));
264                         else returnDate.append(date.substring(6,7));
265                 }
266                 return returnDate.toString();
267         }
268
269         /**
270          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
271          * to [d]d
272          */
273         public static String dateToDayOfMonth (String date) {
274                 StringBuffer returnDate = new StringBuffer();
275                 if (date!=null) {
276                         if (!date.substring(8,9).equalsIgnoreCase("0")) returnDate.append(date.substring(8,10));
277                         else returnDate.append(date.substring(9,10));
278                 }
279                 return returnDate.toString();
280         }
281
282         /**
283          * converts string from format: yyyy-mm-dd__hh:mm:ss.d
284          * to hh:mm
285          */
286         public static String dateToTime (String date) {
287                 StringBuffer returnDate = new StringBuffer();
288                 if (date!=null) {
289                         returnDate.append(date.substring(11,16));
290                 }
291                 return returnDate.toString();
292         }
293
294     /**
295      * Splits the provided CSV text into a list. stolen wholesale from
296      * from Jakarta Turbine StrinUtils.java -mh
297      *
298      * @param text      The CSV list of values to split apart.
299      * @param separator The separator character.
300      * @return          The list of values.
301      */
302     public static String[] split(String text, String separator)
303     {
304         StringTokenizer st = new StringTokenizer(text, separator);
305         String[] values = new String[st.countTokens()];
306         int pos = 0;
307         while (st.hasMoreTokens())
308         {
309             values[pos++] = st.nextToken();
310         }
311         return values;
312     }
313
314     /**
315      * Joins the elements of the provided array into a single string
316      * containing a list of CSV elements. Stolen wholesale from Jakarta
317      * Turbine StringUtils.java. -mh
318      *
319      * @param list      The list of values to join together.
320      * @param separator The separator character.
321      * @return          The CSV text.
322      */
323     public static String join(String[] list, String separator)
324     {
325         StringBuffer csv = new StringBuffer();
326         for (int i = 0; i < list.length; i++)
327         {
328             if (i > 0)
329             {
330                 csv.append(separator);
331             }
332             csv.append(list[i]);
333         }
334         return csv.toString();
335     }
336
337
338         /**
339          * schließt einen String in Anführungsszeichen ein, falls er Leerzeichen o.ä. enthält
340          *
341          * @return gequoteter String
342          */
343          public static String quoteIfNecessary(String s) {
344                 for (int i = 0; i < s.length(); i++)
345                         if (!(Character.isLetterOrDigit(s.charAt(i)) || s.charAt(i) == '.'))
346                                 return quote(s, '"');
347                 return s;
348         }
349
350          /**
351          * schließt <code>s</code> in <code>'</code> ein und setzt Backslashes vor
352          * "gefährliche" Zeichen innerhalb des Strings
353          * Quotes special SQL-characters in <code>s</code>
354          *
355          * @return geqoteter String
356          */
357         public static String quote(String s)
358         {
359                 //String s2 = quote(s, '\'');
360                 //Quickhack     ÃŠÃŠ ÃŠ ÃŠ ÃŠ ÃŠ ÃŠ ÃŠ
361                 //Because of '?-Bug in Postgresql-JDBC-Driver
362                 StringBuffer temp = new StringBuffer();
363                 for(int i=0;i<s.length();i++){
364                         if(s.charAt(i)=='\''){
365                                 temp.append("&#39;");
366                         } else {
367                                 temp.append(s.charAt(i));
368                         }
369                 }
370                 String s2 = temp.toString();
371                 //end Quickhack
372                 
373                 s2 = quote(s2, '\"');
374                 return s2;
375         }
376
377         /**
378          * schließt <code>s</code> in <code>'</code> ein und setzt Backslashes vor
379          * "gefährliche" Zeichen innerhalb des Strings
380          *
381          * @param s String, der gequoted werden soll
382          * @param quoteChar zu quotendes Zeichen
383          * @return gequoteter String
384          */
385         public static String quote(String s, char quoteChar)
386         {
387                 StringBuffer buf = new StringBuffer(s.length());
388                 int pos = 0;
389                 while (pos < s.length()) {
390                         int i = s.indexOf(quoteChar, pos);
391                         if (i < 0) i = s.length();
392                         buf.append(s.substring(pos, i));
393                         pos = i;
394                         if (pos < s.length()) {
395                                 buf.append('\\');
396                                 buf.append(quoteChar);
397                                 pos++;
398                         }
399                 }
400                 return buf.toString();
401         }
402
403         /**
404          * replaces dangerous characters in <code>s</code>
405          *
406          */
407
408         public static String unquote(String s)
409         {
410                 char quoteChar='\'';
411                 StringBuffer buf = new StringBuffer(s.length());
412                 int pos = 0;
413                 String searchString = "\\"+quoteChar;
414                 while (pos < s.length()) {
415                         int i = s.indexOf(searchString, pos);
416                         if (i < 0) i = s.length();
417                         buf.append(s.substring(pos, i));
418                         pos = i+1;
419                 }
420                 return buf.toString();
421         }
422
423         /**
424          * Wandelet String in byte[] um.
425          * @param s
426          * @return byte[] des String
427          */
428
429         public static byte[] stringToBytes(String s) {
430                 String crlf = System.getProperty("line.separator");
431                 if (!crlf.equals("\n"))
432                         s = replace(s, "\n", crlf);
433                 // byte[] buf = new byte[s.length()];
434                 byte[] buf = s.getBytes();
435                 return buf;
436         }
437
438                 /**
439          * Ersetzt in String <code>s</code> das <code>pattern</code> durch <code>substitute</code>
440          * @param s
441          * @param pattern
442          * @param substitute
443          * @return String mit den Ersetzungen
444          */
445         public static String replace(String s, String pattern, String substitute) {
446                 int i = 0, pLen = pattern.length(), sLen = substitute.length();
447                 StringBuffer buf = new StringBuffer(s.length());
448                 while (true) {
449                         int j = s.indexOf(pattern, i);
450                         if (j < 0) {
451                                 buf.append(s.substring(i));
452                                 break;
453                         } else {
454                                 buf.append(s.substring(i, j));
455                                 buf.append(substitute);
456                                 i = j+pLen;
457                         }
458                 }
459                 return buf.toString();
460         }
461
462         /**
463          * Ersetzt in String <code>s</code> das Regexp <code>pattern</code> durch <code>substitute</code>
464          * @param s
465          * @param pattern
466          * @param substitute
467          * @return String mit den Ersetzungen
468          */
469         public static String regexpReplace(String haystack, String pattern, String substitute) {
470                 try {
471                         RE regex = new RE(pattern);
472                         return regex.substituteAll(haystack,substitute);
473                 } catch(REException ex){
474                         return null;
475                 }
476         }
477
478
479
480
481         /**
482          * Fügt einen Separator an den Pfad an
483          * @param path
484          * @return Pfad mit Separator am Ende
485          */
486         public static final String addSeparator (String path) {
487                 return  path.length() == 0 || path.endsWith(File.separator) ? path : path
488                                 + File.separatorChar;
489         }
490
491         /**
492          * Fügt ein <code>/</code> ans ende des Strings and
493          * @param path
494          * @return Pfad mit <code>/</code> am Ende
495          */
496         public static final String addSlash (String path) {
497                 return  path.length() == 0 || path.endsWith("/") ? path : path + '/';
498         }
499
500         /**
501          * Löscht <code>/</code> am Ende des Strings, falls vorhanden
502          * @param path
503          * @return String ohne <code>/</code> am Ende
504          */
505         public static final String removeSlash (String path) {
506                 return  path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length()
507                                 - 1) : path;
508         }
509
510         /**
511          * Checks to see if the path is absolute by looking for a leading file
512          * separater
513          * @param path
514          * @return
515          */
516         public static boolean isAbsolutePath (String path) {
517                 return  path.startsWith(File.separator);
518         }
519
520         /**
521          * Löscht Slash am Anfang des Strings
522          * @param path
523          * @return
524          */
525         public static String removeFirstSlash (String path) {
526                 return  path.startsWith("/") ? path.substring(1) : path;
527         }
528
529         /**
530          * formatiert eine Zahl (0-99) zweistellig (z.B. 5 -> 05)
531          * @return zwistellige Zahl
532          */
533         public static String pad2 (int number) {
534                 return  number < 10 ? "0" + number : String.valueOf(number);
535         }
536
537         /**
538          * formatiert eine Zahl (0-999) dreistellig (z.B. 7 -> 007)
539          *
540          * @return 3-stellige Zahl
541          */
542         public static String pad3 (int number) {
543                 return  number < 10 ? "00" + number : number < 100 ? "0" + number : String.valueOf(number);
544         }
545
546         /**
547          * Konvertiert Unix-Linefeeds in Win-Linefeeds
548          * @param s
549          * @return Konvertierter String
550          */
551         public static String unixLineFeedsToWin(String s) {
552                 int i = -1;
553                 while (true) {
554                         i = s.indexOf('\n', i+1);
555                         if (i < 0) break;
556                         if ((i == 0 || s.charAt(i-1) != '\r') &&
557                                 (i == s.length()-1 || s.charAt(i+1) != '\r')) {
558                                 s = s.substring(0, i)+'\r'+s.substring(i);
559                                 i++;
560                         }
561                 }
562                 return s;
563         }
564
565
566         /**
567          * verwandelt einen String in eine gültige Url, konvertiert Sonderzeichen
568          * und Spaces werden zu Underscores
569          *
570          * @return gültige Url
571          */
572         public static String convert2url(String s) {
573                 s = toLowerCase(s);
574                 StringBuffer buf = new StringBuffer();
575                 for(int i = 0; i < s.length(); i++ ) {
576                                 switch( s.charAt( i ) ) {
577                                 case 'ö':
578                         buf.append( "oe" ); break;
579                                 case 'ä':
580                         buf.append( "ae" ); break;
581                                 case 'ü':
582                         buf.append( "ue" ); break;
583                                 case 'ã':
584                         buf.append( "a" ); break;
585                                 case '´':
586                                 case '.':
587                         buf.append( "_" ); break;
588                                 case ' ':
589                         if( buf.charAt( buf.length() - 1 ) != '_' ) {
590                                         buf.append( "_" );
591                         }
592                         break;
593                                 default:
594                         buf.append( s.charAt( i ) );
595                                 }
596                 }
597                 return buf.toString();
598         }
599
600
601         public static String decodeHTMLinTags(String s){
602                 StringBuffer buffer = new StringBuffer();
603                 boolean start = false;
604                 boolean stop = false;
605                 int startIndex = 0;
606                 int stopIndex = 0;
607                 int temp = 0;
608
609                 for(int i=0;i<s.length();i++){
610                         if(s.charAt(i)=='<'){
611                                 start = true;
612                                 startIndex = i;
613                         } else if(s.charAt(i)=='>'){
614                                 stop = true;
615                                 stopIndex = i;
616
617                                 if(start && stop){
618                                         buffer.append(s.substring(temp,startIndex));
619                                         buffer.append(replaceQuot(s.substring(startIndex,stopIndex+1)));
620                                         i= temp= stopIndex+1;
621                                         start= stop= false;
622                                 }
623                         }
624                 }
625                 if(stopIndex>0){
626                         buffer.append(s.substring(stopIndex+1));
627                         return buffer.toString();
628                 } else {
629                         return s;
630                 }
631         }
632
633         public static String replaceQuot(String s) {
634                 StringBuffer buffer = new StringBuffer();
635                 for(int j = 0; j < s.length();j++){
636                         if(s.charAt(j)=='&'){
637                                 if(s.indexOf( "&quot;",j) == j) {
638                                         buffer.append( "\"" );
639                                         j += 5;
640                                 }//if
641                         } else {
642                                 buffer.append(s.charAt(j));
643                         }//else
644                 }//for
645                 return buffer.toString();
646         }
647
648         /** wandelt Quotes in Sonderzeichen um
649          */
650         /**
651         public static String decodeHtml(String s) {
652                 StringBuffer buf = new StringBuffer();
653                 for(int i=0;i < s.length(); i++ ) {
654                         if( s.indexOf( "&ouml;", i ) == i ) {
655                                 buf.append( "ö" ); i += 5;
656                                 continue;
657                         }
658                         if( s.indexOf( "&auml;", i ) == i ) {
659                                 buf.append( "ä" ); i += 5;
660                                 continue;
661                         }
662                         if( s.indexOf( "&uuml;", i ) == i ) {
663                                 buf.append( "ü" ); i += 5;
664                                 continue;
665                         }
666                         if( s.indexOf( "&Ouml;", i ) == i ) {
667                                 buf.append( "Ö" ); i += 5;
668                                 continue;
669                         }
670                         if( s.indexOf( "&Auml;", i ) == i ) {
671                                 buf.append( "Ä" ); i += 5;
672                                 continue;
673                         }
674                         if( s.indexOf( "&Uuml;", i ) == i ) {
675                                 buf.append( "Ãœ" ); i += 5;
676                                 continue;
677                         }
678                         if( s.indexOf( "&szlig;", i ) == i ) {
679                                 buf.append( "ß" ); i += 6;
680                                 continue;
681                         }
682                         if( s.indexOf( "&quot;", i ) == i ) {
683                                 buf.append( "\"" ); i += 5;
684                                 continue;
685                         }
686                         buf.append( s.charAt(i) );
687                 }
688                 return buf.toString();
689         }
690          */
691
692         /**
693          * schnellere Variante der String.toLowerCase()-Routine
694          *
695          * @return String in Kleinbuchsten
696          */
697         public static String toLowerCase(String s) {
698                 int l = s.length();
699                 char[] a = new char[l];
700                 for (int i = 0; i < l; i++)
701                         a[i] = Character.toLowerCase(s.charAt(i));
702                 return new String(a);
703         }
704
705                 /**
706          * Findet <code>element</code> im String-Array <code>array</code>
707          * @param array
708          * @param element
709          * @return Fundstelle als int oder -1
710          */
711         public static int indexOf(String[] array, String element) {
712                 if (array != null)
713                         for (int i = 0; i < array.length; i++)
714                                 if (array[i].equals(element))
715                                         return i;
716                 return -1;
717         }
718
719         /**
720          * Testet auf Vorkommen von <code>element</code> in <code>array</code>
721          * @param array String-Array
722          * @param element
723          * @return true wenn <code>element</code> vorkommt, sonst false
724          */
725         public static boolean contains(String[] array, String element) {
726                 return indexOf(array, element) >= 0;
727         }
728
729                 /**
730          * Ermittelt CRC-Prüfsumme von String <code>s</code>
731          * @param s
732          * @return CRC-Prüfsumme
733          */
734         public static int getCRC(String s) {
735                 int h = 0;
736                 char val[] = s.toCharArray();
737                 int len = val.length;
738
739                 for (int i = 0 ; i < len; i++) {
740                         h &= 0x7fffffff;
741                         h = (((h >> 30) | (h << 1)) ^ (val[i]+i));
742                 }
743
744                 return (h << 8) | (len & 0xff);
745         }
746
747                 /**
748          * Liefert Default-Wert def zurück, wenn String <code>s</code>
749          * kein Integer ist.
750          *
751          * @param s
752          * @param def
753          * @return geparster int aus s oder def
754          */
755         public static int parseInt(String s, int def) {
756                 if (s == null) return def;
757                 try {
758                         return Integer.parseInt(s);
759                 } catch (NumberFormatException e) {
760                         return def;
761                 }
762         }
763
764         /**
765          * Liefert Defaultwert def zurück, wenn s nicht zu einem float geparsed werden kann.
766          * @param s
767          * @param def
768          * @return geparster float oder def
769          */
770         public static float parseFloat(String s, float def) {
771                 if (s == null) return def;
772                 try {
773                         return new Float(s).floatValue();
774                 } catch (NumberFormatException e) {
775                         return def;
776                 }
777         }
778
779                 /**
780          * Findet Ende eines Satzes in String <code>text</code>
781          * @param text
782          * @param startIndex
783          * @return index des Satzendes, oder -1
784          */
785         public static int findEndOfSentence(String text, int startIndex) {
786                  while (true) {
787                          int i = text.indexOf('.', startIndex);
788                          if (i < 0) return -1;
789                          if (i > 0 && !Character.isDigit(text.charAt(i-1)) &&
790                                         (i+1 >= text.length()
791                                         || text.charAt(i+1) == ' '
792                                         || text.charAt(i+1) == '\n'
793                                         || text.charAt(i+1) == '\t'))
794                                         return i+1;
795                          startIndex = i+1;
796                  }
797         }
798
799                 /**
800          * Findet Wortende in String <code>text</code> ab <code>startIndex</code>
801          * @param text
802          * @param startIndex
803          * @return Index des Wortendes, oder -1
804          */
805         public static int findEndOfWord(String text, int startIndex) {
806                 int i = text.indexOf(' ', startIndex),
807                         j = text.indexOf('\n', startIndex);
808                 if (i < 0) i = text.length();
809                 if (j < 0) j = text.length();
810                 return Math.min(i, j);
811         }
812
813
814         /**
815          *  convertNewline2P ist eine regex-routine zum umwandeln von 2 oder mehr newlines (\n)
816          *  in den html-tag <p>
817          *  nur sinnvoll, wenn text nicht im html-format eingegeben
818          */
819         public static String convertNewline2P(String haystack) {
820                         return re_brbr2p.substituteAll(haystack,"\n</p><p>");
821         }
822
823         /**
824          *  convertNewline2Break ist eine regex-routine zum umwandeln von 1 newline (\n)
825          *  in den html-tag <br>
826          *  nur sinnvoll, wenn text nicht im html-format eingegeben
827          */
828         public static String convertNewline2Break(String haystack) {
829                 return re_newline2br.substituteAll(haystack,"$0<br />");
830         }
831
832         /**
833          *  createMailLinks wandelt text im email-adressenformat
834          *  in einen klickbaren link um
835          *  nur sinnvoll, wenn text nicht im html-format eingegeben
836          */
837         public static String createMailLinks(String haystack) {
838                         return re_mail.substituteAll(haystack,"<a href=\"mailto:$0\">$0</a>");
839         }
840
841
842         /**
843          *  createMailLinks wandelt text im email-adressenformat
844          *  in einen klickbaren link um
845          *  nur sinnvoll, wenn text nicht im html-format eingegeben
846          */
847         public static String createMailLinks(String haystack, String imageRoot, String mailImage) {
848                 return re_mail.substituteAll(haystack,"<img src=\""+imageRoot+"/"+mailImage+"\" border=\"0\"/>&#160;<a href=\"mailto:$0\">$0</a>");
849         }
850
851
852         /**
853          *  createURLLinks wandelt text im url-format
854          *  in einen klickbaren link um
855          *  nur sinnvoll, wenn text nicht im html-format eingegeben
856          */
857         public static String createURLLinks(String haystack) {
858                 return re_url.substituteAll(haystack,"<a href=\"$0\">$0</a>");
859         }
860
861         /**
862          * this routine takes text in url format and makes
863          * a clickaeble "<href>" link removing any "illegal" html tags
864          * @param haystack, the url
865          * @param title, the href link text
866          * @param imagRoot, the place to find icons
867          * @param extImage, the url of the icon to show next to the link
868          * @return a String containing the url
869          */
870         public static String createURLLinks(String haystack, String title, String imageRoot,String extImage) {
871                 if (title == null) {
872                         return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">$0</a>");
873                 } else {
874                         title = removeHTMLTags(title);
875                         return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">"+title+"</a>");
876                 }
877         }
878
879         /**
880          * this routine takes text in url format and makes
881          * a clickaeble "<href>" link removing any "illegal" html tags
882          * @param haystack, the url
883          * @param imageRoot, the place to find icons
884          * @param extImage, the url of the icon to show next to the link
885          * @param intImage, unused
886          * @return a String containing the url
887          */
888         public static String createURLLinks(String haystack, String title, String imageRoot,String extImage,String intImage) {
889                 return createURLLinks(haystack, title, imageRoot, extImage);
890         }
891
892          /**
893          *  deleteForbiddenTags
894          *  this method deletes all <script>, <body> and <head>-tags
895          */
896         public static final String deleteForbiddenTags(String haystack) {
897                 try {
898                         RE regex = new RE("<[ \t\r\n](.*?)script(.*?)/script(.*?)>",RE.REG_ICASE);
899                         haystack = regex.substituteAll(haystack,"");
900                         regex = new RE("<head>(.*?)</head>");
901                         haystack = regex.substituteAll(haystack,"");
902                         regex = new RE("<[ \t\r\n/]*body(.*?)>");
903                         haystack = regex.substituteAll(haystack,"");
904                         return haystack;
905                 } catch(REException ex){
906                         return null;
907                 }
908         }
909
910         /**
911          * this method deletes all html tags
912          */
913         public static final String removeHTMLTags(String haystack){
914                         return re_tags.substituteAll(haystack,"");
915         }
916
917
918         /**
919          * this method deletes all but the approved tags html tags
920          * it also deletes approved tags which contain malicious-looking attributes and doesn't work at all
921          */
922         public static String approveHTMLTags(String haystack){
923                 try {
924                         String approvedTags="a|img|h1|h2|h3|h4|h5|h6|br|b|i|strong|p";
925                         String badAttributes="onAbort|onBlur|onChange|onClick|onDblClick|onDragDrop|onError|onFocus|onKeyDown|onKeyPress|onKeyUp|onLoad|onMouseDown|onMouseMove|onMouseOut|onMouseOver|onMouseUp|onMove|onReset|onResize|onSelect|onSubmit|onUnload";
926                         String approvedProtocols="rtsp|http|ftp|https|freenet|mailto";
927
928                         // kill all the bad tags that have attributes
929                         String s = "<\\s*/?\\s*(?!(("+approvedTags+")\\s))\\w+\\s[^>]*>";
930                         RE regex = new RE(s,RE.REG_ICASE);
931                         haystack = regex.substituteAll(haystack,"");
932
933                         // kill all the bad tags that are attributeless
934                         regex = new RE("<\\s*/?\\s*(?!(("+approvedTags+")\\s*>))\\w+\\s*>",RE.REG_ICASE);
935                         haystack = regex.substituteAll(haystack,"");
936
937                         // kill all the tags which have a javascript attribute like onLoad
938                         regex = new RE("<[^>]*("+badAttributes+")[^>]*>",RE.REG_ICASE);
939                         haystack = regex.substituteAll(haystack,"");
940
941                         // kill all the tags which include a url to an unacceptable protocol
942                         regex = new RE("<\\s*a\\s+[^>]*href=(?!(\'|\")?("+approvedProtocols+"))[^>]*>",RE.REG_ICASE);
943                         haystack = regex.substituteAll(haystack,"");
944
945                         return haystack;
946                 } catch(REException ex){
947                         ex.printStackTrace();
948                         return null;
949                 }
950         }
951
952
953         /**
954          *  createHTML ruft alle regex-methoden zum unwandeln eines nicht
955          *  htmlcodierten string auf und returnt einen htmlcodierten String
956          */
957         public static String createHTML(String content){
958                 content=convertNewline2Break(content);
959                 content=convertNewline2P(content);
960                 content=createMailLinks(content);
961                 content=createURLLinks(content);
962                 return content;
963         }
964
965
966         /**
967          *  createHTML ruft alle regex-methoden zum unwandeln eines nicht
968          *  htmlcodierten string auf und returnt einen htmlcodierten String
969          */
970         public static String createHTML(String content,String producerDocRoot,String mailImage,String extImage,String intImage){
971                 content=convertNewline2Break(content);
972                 content=convertNewline2P(content);
973                 content=createMailLinks(content,producerDocRoot,mailImage);
974                 content=createURLLinks(content,null,producerDocRoot,extImage,intImage);
975                 return content;
976         }
977
978 }
979