001    // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002    // The Molly framework is freely distributable under the terms of an
003    // MIT-style license. For details, see the molly pages web site at:
004    // http://www.mollypages.org/. Use, modify, have fun !
005    
006    package fc.util;
007    
008    import java.util.*;
009    
010    /** 
011    Utility functions related to java.lang.String, i.e 
012    functions that are useful but not provided by that class.
013    
014    @author hursh jain
015    */
016    public final class StringUtil
017    {
018    /** 
019    Returns an empty string if the specified argument was null,
020    otherwise returns the argument itself. 
021    **/
022    public static String nullToEmpty(String val) 
023      {
024      if (val == null) {
025        return "";
026        }
027      return val;
028      }
029    
030    /** 
031    Returns an empty string if the specified argument was null,
032    otherwise returns the value of the toString() method invoked
033    on the specified object. 
034    **/
035    public static String nullToEmpty(Object val) 
036      {
037      if (val == null) {
038        return "";
039        }
040      return val.toString();
041      }
042    
043    
044    /** 
045    Returns true if the specified String is either null or empty. 
046    **/
047    public static boolean nullOrEmpty(String str) 
048      {
049      return str != null && str.isEmpty();
050      }
051    
052    
053    /** 
054    Returns a String containing a string of the specified character concatenated
055    the specified number of times. Returns an empty string if length
056    is less than/equal to zero
057    
058    @param c    the character to be repeated
059    @param length the repeat length
060    */
061    public static String repeat(char c, int length)
062      {
063      StringBuffer b = new StringBuffer();
064      for (int n = 0; n < length; n++) {
065        b.append(c);
066        }
067      return b.toString();
068      }
069    
070    /** 
071    Returns a String containing the specified string concatenated
072    the specified number of times.
073    
074    @param str    the string to be repeated
075    @param length the repeat length
076    */
077    public static String repeat(String str, int length)
078      {
079      int len = str.length();
080      StringBuffer b = new StringBuffer(len*length);
081      for (int n = 0; n < length; n++) {
082        b.append(str);
083        }
084      return b.toString();
085      }
086    
087    /** 
088    Contatenates the given string so that the maximum length reached
089    is the specified length. If the specified string does not fit in
090    the length, then the string is truncated appropriately.
091    
092    @param  str   the string to repeat 
093    @param  length  the length of the returned string
094    **/
095    public static String repeatToWidth(String str, int length)
096      {
097      Argcheck.notnull(str, "specified string was null");
098        
099      int strlen = str.length();  
100      
101      //strlen.range:     [0,inf)
102      //repeat length range:  (-inf, inf)
103      
104      if (strlen == length)   
105        return str;
106    
107      if (strlen > length)
108        return str.substring(0, length);
109    
110    
111      //strlen.range now    [1, inf)  
112    
113      int multiple   = length / strlen; 
114      int fractional = length % strlen;
115    
116      String result = repeat(str, multiple);
117    
118      if (fractional != 0) { 
119        result = result.concat(str.substring(0, fractional));
120        }
121        
122      return result;
123      }
124    
125    
126    /** 
127    Converts the specified String into a fixed width string,
128    left padding (with a blank space) or truncating on the right as necessary. 
129    (i.e., the specified string is aligned left w.r.t to the specified width).
130    
131    @param  str   the target string
132    @param  width the fixed width
133    
134    @return the transformed string
135    **/
136    public static String fixedWidth(String str, int width) 
137      {   
138      return fixedWidth(str, width, HAlign.LEFT, ' ');
139      }
140      
141    /** 
142    Calls {@link fixedWidth(String, int, HAlign, char)} specifying
143    the padding character as a blank space.
144    **/
145    public static String fixedWidth(String str, int width, HAlign align) 
146      {
147      return fixedWidth(str, width, align, ' ');
148      }
149      
150    
151    /** 
152    Converts the specified String into a fixed width string. Strings
153    lesser in size than the fixed width are padded or truncated as
154    required by the specified alignment.
155    
156    @param  str     the target string
157    @param  width   the fixed width
158    @param  align     the alignment of the target string within the width
159    @param  paddingChar the character to pad the string (if necessary);
160    
161    @return the transformed string
162    **/
163    public static String fixedWidth(
164     String str, int width, HAlign align, char paddingChar) 
165      {
166      if (str == null)
167        str = "";
168        
169      int len = str.length();
170    
171      if (len < width) 
172        {
173        if (align == HAlign.LEFT) {
174          str = str + repeat(paddingChar, width-len);
175          }
176        else if (align == HAlign.RIGHT) {
177          str = repeat(paddingChar, width-len) + str;
178          }
179        else if (align == HAlign.CENTER) {
180          //arbitrary tie-break, if the diff is odd then the
181          //1 extra space is padded on the right side
182      
183          int diff = (width-len);   
184          String temp = repeat(paddingChar, diff/2);
185          str = temp + str + temp + repeat(paddingChar, diff%2);
186          }
187        else throw new IllegalArgumentException("Do not understand the specified alignment: " + align);
188        }
189    
190    
191      else if (len > width) {
192        str = str.substring(0, width);
193        }
194        
195      return str; 
196      }
197    
198    /**
199    Converts the specified String into a string with maxlen characters, using the specified
200    ellipsis as the suffix to denote the missing characters.
201    
202    @param  str     the target string
203    @param  ellipsis  the ellipsis suffix
204    @param  width   the max length, <b>including</b> the ellipsis
205    
206    @return the transformed string
207    */
208    public static String ellipsis(String str, String ellipsis, int maxlen)
209      {
210      if (str.length() > maxlen)
211        {
212          str = str.substring(0, maxlen - ellipsis.length()) + ellipsis;
213        }
214      
215      return str;
216      }
217    
218    /**
219    Converts the specified String into a string with maxlen characters, using <code>...<code>
220    as the suffix to denote the missing characters.
221    
222    @param  str     the target string
223    @param  width   the max length, <b>including</b> the ellipsis ("...")
224    
225    @return the transformed string
226    */
227    public static String ellipsis(String str, int maxlen)
228      {
229      return ellipsis(str, "...", maxlen);
230      }
231    
232    
233    /** 
234    Removes all occurences of specified characters from the specified 
235    string and returns the new resulting string.
236    @param  target  the string to remove characters from
237    @param  chars an array of characters, each of which is to be removed
238    */
239    public static String remove(String target, char[] chars)
240      {
241      if (target == null || chars == null) return target;
242      int strlen = target.length();
243      char[] newstr = new char[strlen];
244      char[] oldstr = new char[strlen];
245      target.getChars(0,strlen,oldstr,0);
246      int replacelen = chars.length;
247      
248      int oldindex = -1;
249      int newindex = -1;
250      char c = 0;
251      boolean found = false;
252    
253      while (++oldindex < strlen) 
254        {
255        c = oldstr[oldindex];
256        found = false;
257        for (int j = 0; j < replacelen; j++) 
258          {
259          if (c == chars[j]) {
260            found = true;
261            break;
262            }
263          } //~for
264        if (!found) 
265          {
266          newstr[++newindex] = c;
267          }
268        }   //~while
269      return new String(newstr, 0, newindex+1);
270      }     //~remove()
271    
272    
273    /**
274    Removes the last forward or backward slash from the specified
275    string (if any) and returns the resulting String. Returns <tt>null</tt>
276    if a null argument is specified. The trailing slash is a slash that
277    is the last character of the specified string.
278    **/
279    public static String removeTrailingSlash(String str)
280      {
281      String res = str;
282      if (str == null) return null; 
283      int len = str.length();
284      if (len == 0)
285        return str;  //str was ""
286      char c = str.charAt(len-1);
287      if (c == '/' || c == '\\') {
288        res = str.substring(0, len-1);  //len-1 will be >= 0
289        }
290      return res;     
291      }
292    
293    /**
294    Removes the starting (at the very beginning of the string) forward or 
295    backward slash from the specified string (if any) and returns the 
296    resulting String. Returns <tt>null</tt> if  null argument is specified.
297    **/
298    public static String removeBeginningSlash(String str)
299      {
300      if (str == null) return null; 
301      int len = str.length();
302      if (len == 0) 
303        return str;  //str was ""
304      char c = str.charAt(0);
305      if (c == '/' || c == '\\') 
306        {
307        if (len > 1) { 
308          return str.substring(1);
309          }
310        else { //str was "/"
311          return "";  
312          }
313        }
314      return str;
315      }
316    
317    /**
318    Removes the any file extension (.foo for example) from the specified name
319    and returns the resulting String. Returns <tt>null</tt> if the specified
320    path was null. This method takes a String as a parameter, as opposed to a
321    <tt>java.io.File</tt> because the caller knows best what portion of the
322    filename should be modified and returned by this method (full path name,
323    name without path information etc).
324    
325    @param  name the String denoting the file name to remove the extension from
326    **/
327    public static String removeSuffix(String name)
328      {
329      String result = null;
330      if (name == null)
331        return result;
332      result = name.replaceFirst("(.+)(\\..+)","$1");
333      //System.out.println("File " + name + " after removing extension =" + name);  
334      return result;
335      }
336    
337    /** 
338    Returns the path component of the specified filename. If no path exists
339    or the specified string is null, returns the empty string <tt>""</tt>.
340    <u>The path separator in the specified string should be <tt>/</tt></u>.
341    If on a platform where this is not the case, the specified string should
342    be modified to contain "/" before invoking this method. The returned
343    pathName <b>does</b>
344    contain the trailing "/". This ensures that 
345    <tt>dirName(somepath) + fileName(somepath)</tt> will always be equal to <tt>somepath</tt>.
346    <p>
347    <blockquote>
348    <pre>
349    The functionality of this method is different than java.io.File.getName()
350    and getParent(). Also unix dirname, basename are also compared below.
351    
352    //Using java.io.File (getPath() returns the entire name, identical to
353    //the input, so is not shown. Sample run on windows:
354    Name=''         ; getName()='';       getParent()='null'
355    Name='/'        ; getName()='';       getParent()='null'
356    Name='/a'       ; getName()='a';      getParent()='\'
357    Name='a/b'      ; getName()='b';      getParent()='a'
358    Name='a/b.txt'  ; getName()='b.txt';  getParent()='a'
359    Name='b.txt'    ; getName()='b.txt';  getParent()='null'
360    
361    Name='/a/'      ; getName()='a';      getParent()='\'
362    Name='/a/b/'    ; getName()='b';      getParent()='\a'
363    Name='a/b/'     ; getName()='b';      getParent()='a'
364    ----------------------------
365    //Using these methods:
366    Name=''         ; fileName()='';      dirName()=''
367    Name='/'        ; fileName()='';      dirName()='/' 
368    Name='/a'       ; fileName()='a';     dirName()='/' 
369    Name='a/b'      ; fileName()='b';     dirName()='a/' 
370    Name='a/b.txt'  ; fileName()='b.txt'; dirName()='a/' 
371    Name='b.txt'    ; fileName()='b.txt'; dirName()='' 
372    
373    Name='/a/'      ; fileName()='';      dirName()='/a/'
374    Name='/a/b/'    ; fileName()='';      dirName()='/a/b/'
375    Name='a/b/'     ; fileName()='';      dirName()='a/b/'
376    -----------------------------
377    //unix basename, dirname
378    Name=''         ; basename()='';    dirname()=''
379    Name='/'        ; basename()='/';   dirname()='/' 
380    Name='/a'       ; basename()='a';     dirname()='/' 
381    Name='a/b'      ; basename()='b';     dirname()='a/' 
382    Name='a/b.txt'  ; basename()='b.txt'; dirname()='a/' 
383    Name='b.txt'    ; basename()='b.txt'; dirname()='.' 
384    
385    Name='/a/'      ; basename()='a';     dirname()='/'
386    Name='a/b/'     ; basename()='b';     dirname()='a'
387    Name='/a/b/'  ; fileName()='b';     dirName()='a'
388    
389    -----------------------------
390    </pre>
391    Note, the main differences among the 3 approaches above are in the last 
392    2 statements in each section.
393    </blockquote>
394    **/
395    public static String dirName(String str) 
396      {
397      String res = "";
398      if (str == null)
399        return res;
400      int pos = str.lastIndexOf("/");
401      if (pos == -1)
402        return "";
403      return str.substring(0, (pos+1));
404      }
405    
406    /** 
407    Returns the file component of specified filename. If no filename exists
408    or the specified string is null, returns the empty string <tt>""</tt>.
409    <u>The path separator in the specified string is always assumed to be
410    <tt>/</tt></u>. If on a platform where this is not the case, the
411    specified string should be modified to contain "/" before invoking this
412    method. The returned file name does <b>not</b> contain the preceding "/".
413    **/
414    public static String fileName(String str) 
415      {
416      String res = "";
417      if (str == null)
418        return res;
419      int pos = str.lastIndexOf("/");
420      if (pos == -1)
421        return str;
422      
423      int strlen = str.length();
424      if (strlen == 1)
425        return res; //we return "" since the string has to be "/" 
426      else
427        pos++;    //skip "/" in other strings
428        
429      return str.substring(pos, strlen); //will return "" if str = "/"
430      }
431    
432    
433    /** 
434    Splits the string using the specified delimiters and
435    returns the splits parts in a List. Use {@link
436    java.lang.String#split} instead for greater options.
437    
438    @param  str   the string to be tokenized
439    @param  delim delimiter string, each character in the string will be used 
440            as a delimiter to use while tokenizing
441    */
442    public static List split(String str, String delim)
443      {   
444      int pos = 0;    //current position pointer in the string (str)
445      List result = new ArrayList();  
446      StringTokenizer st = new StringTokenizer(str,delim);
447        while (st.hasMoreTokens()) {
448                //tokens are stored as lowercase
449            result.add(st.nextToken().toLowerCase());  
450            }
451      return result;  
452      }
453    
454    /** 
455    Joins the elements of the specified list, delimited by
456    the specified delimiter.
457    
458    @param  list  containing the elements to be joined.
459    @param  delim delimits each element from the next
460    */
461    public static String join(List list, String delim)
462      { 
463      Argcheck.notnull(list, "specified list param was null");
464      Argcheck.notnull(delim, "specified delim param was null");
465    
466      int size = list.size();
467      int size_minus_one = size -1 ;
468      StringBuffer buf = new StringBuffer(size * 16);
469      
470      for (int n = 0; n < size; n++) {
471        buf.append(list.get(n).toString());
472        if ( n < (size_minus_one)) {
473          buf.append(delim);
474          }
475        }
476        
477      return buf.toString();  
478      } 
479    
480    
481    /* TO DO: LATER
482    Removes all whitespace in the specified string and returns all words 
483    with only a single space between them. Uses a Perl regular expression 
484    to do this.
485      public synchronized static void makeSingleSpaced(String target)
486      throws Exception
487      {
488      String regex1 = "s\\?([^\"]+)\\s*(target)?[^>]*>([^>]*)</a>";  
489      MatchResult result;
490      Perl5Pattern pattern =  (Perl5Pattern)StringUtil.compiler.compile(
491                    regex1,
492                    Perl5Compiler.CASE_INSENSITIVE_MASK | 
493                    Perl5Compiler.SINGLELINE_MASK); 
494      
495      }
496    */
497    
498    /**
499    Converts the specified String to start with a capital letter. Only
500    the first character is made uppercase, the rest of the specified
501    string is not affected.
502    **/
503    public static String capitalWord(String str) 
504      {
505      int strlen = str.length();
506      StringBuffer buf = new StringBuffer(strlen);
507      buf.append( str.substring(0,1).toUpperCase() + 
508            str.substring(1, strlen) ); 
509      return buf.toString(); 
510      }
511    
512    /**
513    Converts the specified String to be in sentence case, whereby
514    the first letter of each word in the sentence is uppercased
515    and all other letters are lowercased. The characters in the
516    delimiter string are used to delimit words in the sentence.
517    If the delimiter string is <tt>null</tt>, the original string
518    is returned as-is.
519    <br>
520    A runtime exception will be thrown if the specified string
521    was <tt>null</tt>.
522    **/
523    public static String sentenceCase(String str, String delimiters)
524      {
525      Argcheck.notnull(str, "specified string was null");
526      if (delimiters == null) 
527        return str;
528        
529      int strlen = str.length();
530      StringBuffer out = new StringBuffer(strlen);
531      StringBuffer temp = new StringBuffer(strlen);
532      for (int n = 0; n < strlen; n++)
533        {
534        //System.out.print("["+n+"] ");
535        char current_char = str.charAt(n);
536        if (delimiters.indexOf(current_char) >= 0) {
537          //System.out.println("->"+current_char);
538          if (temp.length() > 0 ) {
539            out.append( temp.substring(0, 1).toUpperCase() );
540            out.append( temp.substring(1, temp.length()).toLowerCase() );
541            }
542          out.append(current_char);
543          //System.out.println("temp="+temp);
544          temp = new StringBuffer(strlen);
545          continue;
546          }
547        temp.append(current_char);  
548        }
549      if (temp.length() > 0 ) {
550        out.append( temp.substring(0, 1).toUpperCase() );
551        out.append( temp.substring(1, temp.length()).toLowerCase() );
552        }
553      return out.toString();
554      }
555      
556    static final String[] VIEW_ASCII = {
557    /*0*/ "NUL", "[ascii(1)]", "[ascii(2)]", "[ascii(3)]", "[ascii(4)]",
558    /*5*/ "[ascii(5)]", "[ascii(6)]", "\\a", "\\b", "\\t",
559    /*10*/  "\\n", "\\v", "[ascii(12)]", "\\r", "[ascii(14)]",
560    /*15*/  "[ascii(15)]", "[ascii(16)]", "[ascii(17)", "[ascii(18)]", "[ascii(19)]",
561    /*20*/  "[ascii(20)]", "[ascii(21)]", "[ascii(22)]", "ascii(23)]", "[ascii(24)]",
562    /*25*/  "[ascii(25)]", "[ascii(26)]", "\\e", "[ascii(28)]", "[ascii(29)]",
563    /*30*/  "[ascii(30)]", "[ascii(31)]" 
564    };  
565      
566    /**
567    Converts non printable ascii characters in the specified String
568    to escaped or readable equivalents. For example, a newline is
569    converted to the sequence <tt>\n</tt> and say, ascii character 29 is 
570    converted to the sequence of chars: '<tt>ascii(29)</tt>'. 
571    <p>
572    If the specified String is <tt>null</tt>, this method returns 
573    <tt>null</tt>.
574    
575    @param  str   the String to convert
576    @return the converted String
577    **/     
578    public static String viewableAscii(String str) 
579      {
580      if (str == null)
581        return null;
582      
583      int strlen = str.length();
584      StringBuffer buf = new StringBuffer(strlen);
585      
586      //ignore all non ascii data, including UTF-16 surrogate bytes etc.
587      //by replacing such data with '?'   
588      for(int n = 0; n < strlen; n++) 
589        {
590        char c = str.charAt(n);
591        if ( c < 32) 
592          buf.append(VIEW_ASCII[c]);
593        else if ( c > 255) 
594          buf.append('?');
595        else
596          buf.append(c);
597        } 
598      return buf.toString();
599      } 
600    
601    /**
602    A version of {@link viewableAscii(String)} that takes a
603    single char as a parameter.
604    
605    @param  char the char to convert
606    @return the ascii readable char
607    **/
608    public static String viewableAscii(char c) 
609      {
610      if ( c < 32) 
611        return VIEW_ASCII[c];
612      else if ( c > 255) 
613        return "?";
614      else
615        return new String(new char[] {c});
616      }
617    
618    /**
619    Converts a character array into a viewable comma delimited
620    string. Non-printable/readable characters are shown as
621    readable equivalents.
622    */
623    public static String arrayToString(char[] array) {
624      if (array == null) {
625        return "null";
626        }
627      int arraylen = array.length;
628      StringBuffer buf = new StringBuffer(arraylen * 2);
629      buf.append("[");
630      int n = 0;
631      while (n < arraylen) {
632        buf.append(viewableAscii(array[n]));
633        n++;
634        if (n != arraylen)
635          buf.append(", ");
636        }
637      buf.append("]");
638      return buf.toString();
639      }
640    
641    
642    /**
643    Converts a list into a string, each item being seperated by the specified delimiter.
644    Each item in the list is converted by invokign <code>toString</code> on that item
645    so the specified delimiter only applies to the outermost level. 
646    <p>
647    The converted string does not start or end with any characters. To specify the start/end, use {@link listToString(List, String, String, String)} 
648    */
649    public static String listToString(List list, String delim) 
650      {
651      return listToString(list, delim, "", "");
652      }
653    
654    /**
655    Converts a list into a string, each item being seperated by the specified delimiter.
656    Each item in the list is converted by invokign <code>toString</code> on that item
657    so the specified delimiter only applies to the outermost level. 
658    <p>
659    The converted string start and ends with the specified chars as well. 
660    */
661    public static String listToString(List list, String delim, String start, String end) 
662      {
663      StringBuilder buf = new StringBuilder();
664      buf.append(start);  
665        
666      if (list != null) 
667        {
668        final int size = list.size();
669        for (int n = 0; n < size; n++) 
670          {
671          buf.append(list.get(n));
672          if (n + 1 < size) {
673            buf.append(delim);
674            }
675          }
676        }
677        
678      buf.append(end);
679      
680      return buf.toString();
681      }
682    
683    /**
684    Escapes all single quotes in the specified a string with a backslash
685    character. 
686    */
687    public static String escapeSingleQuotes(final String str)
688      {
689      return escapeSingleQuotes(str, "\\");
690      }
691    
692    /**
693    Escapes all single quotes in the specified a string with the specified
694    escape character. So, if the specified escape character is <tt>'</tt>, 
695    all occurrences of <tt>o'tis the ele'phant</tt> becomes 
696    <tt>o''tis the ele''phant</tt>
697    */
698    public static String escapeSingleQuotes(final String str, String escape)
699      {
700      if (str == null)
701        return null;
702      
703      final int len = str.length();
704      if (len == 0)
705        return str;
706        
707      final StringBuilder buf = new StringBuilder(len * 2);
708      for (int n = 0; n < len; n++) 
709        {
710        char c = str.charAt(n);
711        if (c == '\'') {
712          buf.append(escape);
713          buf.append('\'');
714          }
715        else{
716          buf.append(c);
717          }
718        }
719      return buf.toString();
720      }
721      
722    /**
723    Escapes all double quotes in the specified a string with a backslash
724    character. 
725    */
726    public static String escapeDoubleQuotes(final String str)
727      {
728      return escapeSingleQuotes(str, "\\");
729      }
730    
731    /**
732    Escapes all double quotes in the specified a string with the specified
733    escape character. So, if the specified escape character is <tt>\</tt>, 
734    all occurrences of <tt>o"tis the ele"phant</tt> becomes 
735    <tt>o\"tis the ele\"phant</tt>
736    */
737    public static String escapeDoubleQuotes(final String str, String escape)
738      {
739      if (str == null)
740        return null;
741      
742      final int len = str.length();
743      if (len == 0)
744        return str;
745        
746      final StringBuilder buf = new StringBuilder(len * 2);
747      for (int n = 0; n < len; n++) 
748        {
749        char c = str.charAt(n);
750        if (c == '"') {
751          buf.append(escape);
752          buf.append('"');
753          }
754        else{
755          buf.append(c);
756          }
757        }
758      return buf.toString();
759      } 
760    
761    //unit test
762    public static void main(String[] args)
763    {
764    String teststr = "hahaha, my name is ha";
765    char[] remove = new char[] {'h','m'};
766    System.out.println("testing StringUtil.remove(\"" + teststr + "\",'" + String.valueOf(remove) + "')");
767    String newstr = StringUtil.remove(teststr,remove);
768    System.out.println("result>>" + newstr + "<<");
769    System.out.println("Original String length: " + teststr.length() +" ; New String length: " + newstr.length());
770    System.out.println(":" + repeat(' ',20) + ":");
771    
772    System.out.println("sentenceCase(\"hello world\", \" \"): ["
773              + sentenceCase("hello world", " ") + "]");
774    System.out.println("sentenceCase(\"helloworld\", \" \"): ["
775              + sentenceCase("helloworld", " ") + "]");
776    System.out.println("sentenceCase(\"  hello world\", \" \"): ["
777              + sentenceCase("  hello world", " ") + "]");
778    System.out.println("sentenceCase(\"hello world  \", \" \"): ["
779              + sentenceCase("hello world  ", " ") + "]");
780    System.out.println("sentenceCase(\"hello_world  \", \"_\"): ["
781              + sentenceCase("hello_world  ", "_") + "]");
782    System.out.println("sentenceCase(\"__hello_world_ foo  \", \"_ \"): ["
783              + sentenceCase("__hello_world_ foo  ", "_ ") + "]");
784    System.out.println("sentenceCase(\"foXbAr\", \"X\"): ["
785              + sentenceCase("foXbAr", "X") + "]");
786          
787    
788    System.out.println("viewableAscii(abc[newline]foo[tab]\\u4234)="+viewableAscii("abc\nfoo\t\u4234"));
789    for(char c = 0; c < 255; c++) {
790      System.out.print(viewableAscii(c));   
791      }
792    System.out.println("");
793    
794    System.out.println("remove trailing slash on '' = " + removeTrailingSlash(""));
795    System.out.println("remove trailing slash on '/' = " + removeTrailingSlash(""));
796    System.out.println("remove trailing slash on 'foo/' = " + removeTrailingSlash("foo/"));
797    System.out.println("remove beginning slash on '' = " + removeBeginningSlash(""));
798    System.out.println("remove beginning slash on '/' = " + removeBeginningSlash("/"));
799    System.out.println("remove beginning slash on '/foo' = " + removeBeginningSlash("/foo"));
800    
801    System.out.println("====fixed width tests");
802    String fixedin = "hello";
803    int width = 15;
804    System.out.println("fixed width input string: " + fixedin);
805    System.out.println("fixed width = 15");
806    System.out.println("align default: [" + fixedWidth(fixedin, width) + "]");
807    System.out.println("align left: [" + fixedWidth(fixedin, width, HAlign.LEFT) + "]");
808    System.out.println("align right : [" + fixedWidth(fixedin, width, HAlign.RIGHT) + "]");
809    System.out.println("align center: [" + fixedWidth(fixedin, width, HAlign.CENTER) + "]");
810    
811    System.out.println("repeatToWidth('hello', 0)="+repeatToWidth("hello", 0));
812    System.out.println("repeatToWidth('hello', 1)="+repeatToWidth("hello", 1));
813    System.out.println("repeatToWidth('hello', 5)="+repeatToWidth("hello", 5));
814    System.out.println("repeatToWidth('hello', 9)="+repeatToWidth("hello", 9));
815    System.out.println("repeatToWidth('hello', 10)="+repeatToWidth("hello", 10));
816    System.out.println("repeatToWidth('hello', 11)="+repeatToWidth("hello", 11));
817    
818    System.out.println("repeatToWidth('X', 0)=["+repeatToWidth("X", 0) +"]");
819    
820    System.out.println("escapeSingleQuotes(\"'\")="+escapeSingleQuotes("'"));
821    System.out.println("escapeSingleQuotes(\"\")="+escapeSingleQuotes(""));
822    System.out.println("escapeSingleQuotes(\"'foo'bar'\")="+escapeSingleQuotes("'foo'bar'"));
823    System.out.println("escapeSingleQuotes(\"'''\")="+escapeSingleQuotes("'''"));
824    System.out.println("escapeSingleQuotes(\"'foo'bar'\", \"'\")="+escapeSingleQuotes("'foo'bar'", "'"));
825    
826    
827    System.out.println("listToString(null):" + listToString(null, "x"));
828    List list = new ArrayList();
829    list.add(1);
830    list.add(2);
831    System.out.println("listToString([1,2] / [ ]): " +listToString(list,"/","[","]"));
832    
833    System.out.println("ellipsis('hello world', 8): " + ellipsis("hello world", 8));
834    }
835    
836    }     //~class StringUtil