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