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  maxlen    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  maxlen    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 <code>null</code>
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 <code>null</code> 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 <code>null</code> if the specified
332path was null. This method takes a String as a parameter, as opposed to a
333<code>java.io.File</code> 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 <code>""</code>.
352<u>The path separator in the specified string should be <code>/</code></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<code>dirName(somepath) + fileName(somepath)</code> will always be equal to <code>somepath</code>.
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 <code>""</code>.
421<u>The path separator in the specified string is always assumed to be
422<code>/</code></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/** 
494Groups characters into 4 char groups and a space separator. Useful for printing out (for
495example) binary strings like <code>10010101</code> to <code>1001 0101</code>
496*/
497public static String group(String str) 
498  {
499  return group(str, 4, " ");
500  }
501
502/** 
503Groups characters into 4 char groups and the specified space separator. Useful for printing out (for
504example) binary strings like <code>10010101</code> to <code>1001 0101</code>
505*/
506public static String group(String str, String separator) 
507  {
508  return group(str, 4, separator);
509  }
510
511/** 
512Groups characters into the specified number of chars, separated by the separator. Useful
513for printing out (for example) binary strings like <code>10010101</code> to <code>1001
5140101</code>
515*/
516public static String group(String str, int groupchars, String separator) 
517  {
518  StringBuilder builder = new StringBuilder();
519  for (int n = str.length(), pos = 1; n > 0; n--, pos++) 
520    {
521    builder.append(str.charAt(n-1));
522    if ((pos % groupchars == 0) && n > 1) {
523      builder.append(separator);
524      }
525    }
526  return builder.reverse().toString();
527  }
528  
529
530/* TO DO: LATER
531Removes all whitespace in the specified string and returns all words 
532with only a single space between them. Uses a Perl regular expression 
533to do this.
534  public synchronized static void makeSingleSpaced(String target)
535  throws Exception
536  {
537  String regex1 = "s\\?([^\"]+)\\s*(target)?[^>]*>([^>]*)</a>"; 
538  MatchResult result;
539  Perl5Pattern pattern =  (Perl5Pattern)StringUtil.compiler.compile(
540                regex1,
541                Perl5Compiler.CASE_INSENSITIVE_MASK | 
542                Perl5Compiler.SINGLELINE_MASK); 
543  
544  }
545*/
546
547/**
548Converts the specified String to start with a capital letter. Only
549the first character is made uppercase, the rest of the specified
550string is not affected.
551**/
552public static String capitalWord(String str) 
553  {
554  int strlen = str.length();
555  StringBuffer buf = new StringBuffer(strlen);
556  buf.append( str.substring(0,1).toUpperCase() + 
557        str.substring(1, strlen) ); 
558  return buf.toString(); 
559  }
560
561/**
562Converts the specified String to be in sentence case, whereby
563the first letter of each word in the sentence is uppercased
564and all other letters are lowercased. The characters in the
565delimiter string are used to delimit words in the sentence.
566If the delimiter string is <code>null</code>, the original string
567is returned as-is.
568<br>
569A runtime exception will be thrown if the specified string
570was <code>null</code>.
571**/
572public static String sentenceCase(String str, String delimiters)
573  {
574  Argcheck.notnull(str, "specified string was null");
575  if (delimiters == null) 
576    return str;
577    
578  int strlen = str.length();
579  StringBuffer out = new StringBuffer(strlen);
580  StringBuffer temp = new StringBuffer(strlen);
581  for (int n = 0; n < strlen; n++)
582    {
583    //System.out.print("["+n+"] ");
584    char current_char = str.charAt(n);
585    if (delimiters.indexOf(current_char) >= 0) {
586      //System.out.println("->"+current_char);
587      if (temp.length() > 0 ) {
588        out.append( temp.substring(0, 1).toUpperCase() );
589        out.append( temp.substring(1, temp.length()).toLowerCase() );
590        }
591      out.append(current_char);
592      //System.out.println("temp="+temp);
593      temp = new StringBuffer(strlen);
594      continue;
595      }
596    temp.append(current_char);  
597    }
598  if (temp.length() > 0 ) {
599    out.append( temp.substring(0, 1).toUpperCase() );
600    out.append( temp.substring(1, temp.length()).toLowerCase() );
601    }
602  return out.toString();
603  }
604  
605static final String[] VIEW_ASCII = {
606/*0*/ "NUL", "[ascii(1)]", "[ascii(2)]", "[ascii(3)]", "[ascii(4)]",
607/*5*/ "[ascii(5)]", "[ascii(6)]", "\\a", "\\b", "\\t",
608/*10*/  "\\n", "\\v", "[ascii(12)]", "\\r", "[ascii(14)]",
609/*15*/  "[ascii(15)]", "[ascii(16)]", "[ascii(17)", "[ascii(18)]", "[ascii(19)]",
610/*20*/  "[ascii(20)]", "[ascii(21)]", "[ascii(22)]", "ascii(23)]", "[ascii(24)]",
611/*25*/  "[ascii(25)]", "[ascii(26)]", "\\e", "[ascii(28)]", "[ascii(29)]",
612/*30*/  "[ascii(30)]", "[ascii(31)]" 
613};  
614  
615/**
616Converts non printable ascii characters in the specified String
617to escaped or readable equivalents. For example, a newline is
618converted to the sequence <code>\n</code> and say, ascii character 29 is 
619converted to the sequence of chars: '<code>ascii(29)</code>'. 
620<p>
621If the specified String is <code>null</code>, this method returns 
622<code>null</code>.
623
624@param  str   the String to convert
625@return the converted String
626**/     
627public static String viewableAscii(String str) 
628  {
629  if (str == null)
630    return null;
631  
632  int strlen = str.length();
633  StringBuffer buf = new StringBuffer(strlen);
634  
635  //ignore all non ascii data, including UTF-16 surrogate bytes etc.
636  //by replacing such data with '?'   
637  for(int n = 0; n < strlen; n++) 
638    {
639    char c = str.charAt(n);
640    if ( c < 32) 
641      buf.append(VIEW_ASCII[c]);
642    else if ( c > 255) 
643      buf.append('?');
644    else
645      buf.append(c);
646    } 
647  return buf.toString();
648  } 
649
650/**
651A version of {@link viewableAscii(String)} that takes a
652single char as a parameter.
653
654@param  c the char to convert
655@return the ascii readable char
656**/
657public static String viewableAscii(char c) 
658  {
659  if ( c < 32) 
660    return VIEW_ASCII[c];
661  else if ( c > 255) 
662    return "?";
663  else
664    return new String(new char[] {c});
665  }
666
667/**
668Converts a character array into a viewable comma delimited
669string. Non-printable/readable characters are shown as
670readable equivalents.
671*/
672public static String arrayToString(char[] array) {
673  if (array == null) {
674    return "null";
675    }
676  int arraylen = array.length;
677  StringBuffer buf = new StringBuffer(arraylen * 2);
678  buf.append("[");
679  int n = 0;
680  while (n < arraylen) {
681    buf.append(viewableAscii(array[n]));
682    n++;
683    if (n != arraylen)
684      buf.append(", ");
685    }
686  buf.append("]");
687  return buf.toString();
688  }
689
690
691/**
692Converts a list into a string, each item being seperated by the specified delimiter.
693Each item in the list is converted by invokign <code>toString</code> on that item
694so the specified delimiter only applies to the outermost level. 
695<p>
696The converted string does not start or end with any characters. To specify the start/end, use {@link listToString(List, String, String, String)} 
697*/
698public static String listToString(List list, String delim) 
699  {
700  return listToString(list, delim, "", "");
701  }
702
703/**
704Converts a list into a string, each item being seperated by the specified delimiter.
705Each item in the list is converted by invokign <code>toString</code> on that item
706so the specified delimiter only applies to the outermost level. 
707<p>
708The converted string start and ends with the specified chars as well. 
709*/
710public static String listToString(List list, String delim, String start, String end) 
711  {
712  StringBuilder buf = new StringBuilder();
713  buf.append(start);  
714    
715  if (list != null) 
716    {
717    final int size = list.size();
718    for (int n = 0; n < size; n++) 
719      {
720      buf.append(list.get(n));
721      if (n + 1 < size) {
722        buf.append(delim);
723        }
724      }
725    }
726    
727  buf.append(end);
728  
729  return buf.toString();
730  }
731
732/**
733Escapes all single quotes in the specified a string with a backslash
734character. 
735*/
736public static String escapeSingleQuotes(final String str)
737  {
738  return escapeSingleQuotes(str, "\\");
739  }
740
741/**
742Escapes all single quotes in the specified a string with the specified
743escape character. So, if the specified escape character is <code>'</code>, 
744all occurrences of <code>o'tis the ele'phant</code> becomes 
745<code>o''tis the ele''phant</code>
746*/
747public static String escapeSingleQuotes(final String str, String escape)
748  {
749  if (str == null)
750    return null;
751  
752  final int len = str.length();
753  if (len == 0)
754    return str;
755    
756  final StringBuilder buf = new StringBuilder(len * 2);
757  for (int n = 0; n < len; n++) 
758    {
759    char c = str.charAt(n);
760    if (c == '\'') {
761      buf.append(escape);
762      buf.append('\'');
763      }
764    else{
765      buf.append(c);
766      }
767    }
768  return buf.toString();
769  }
770  
771/**
772Escapes all double quotes in the specified a string with a backslash
773character. 
774*/
775public static String escapeDoubleQuotes(final String str)
776  {
777  return escapeSingleQuotes(str, "\\");
778  }
779
780/**
781Escapes all double quotes in the specified a string with the specified
782escape character. So, if the specified escape character is <code>\</code>, 
783all occurrences of <code>o"tis the ele"phant</code> becomes 
784<code>o\"tis the ele\"phant</code>
785*/
786public static String escapeDoubleQuotes(final String str, String escape)
787  {
788  if (str == null)
789    return null;
790  
791  final int len = str.length();
792  if (len == 0)
793    return str;
794    
795  final StringBuilder buf = new StringBuilder(len * 2);
796  for (int n = 0; n < len; n++) 
797    {
798    char c = str.charAt(n);
799    if (c == '"') {
800      buf.append(escape);
801      buf.append('"');
802      }
803    else{
804      buf.append(c);
805      }
806    }
807  return buf.toString();
808  } 
809
810//unit test
811public static void main(String[] args)
812{
813String teststr = "hahaha, my name is ha";
814char[] remove = new char[] {'h','m'};
815System.out.println("testing StringUtil.remove(\"" + teststr + "\",'" + String.valueOf(remove) + "')");
816String newstr = StringUtil.remove(teststr,remove);
817System.out.println("result>>" + newstr + "<<");
818System.out.println("Original String length: " + teststr.length() +" ; New String length: " + newstr.length());
819System.out.println(":" + repeat(' ',20) + ":");
820
821System.out.println("removeLeadingWhiteSpace(\" \\n\"): [" + removeLeadingWhiteSpace(" \n") + "]");
822System.out.println("removeLeadingWhiteSpace(\"\"): [" + removeLeadingWhiteSpace("") + "]");
823System.out.println("removeLeadingWhiteSpace(\"\\n\"): [" + removeLeadingWhiteSpace("\n") + "]");
824System.out.println("removeLeadingWhiteSpace(\"\\n\\n\\ttest\"): [" + removeLeadingWhiteSpace("\n\n\ttest") + "]");
825System.out.println("removeLeadingWhiteSpace(\"\\n\\n\\ttest\\t \"): [" + removeLeadingWhiteSpace("\n\n\ttest\t ") + "]");
826
827System.out.println("sentenceCase(\"hello world\", \" \"): ["
828          + sentenceCase("hello world", " ") + "]");
829System.out.println("sentenceCase(\"helloworld\", \" \"): ["
830          + sentenceCase("helloworld", " ") + "]");
831System.out.println("sentenceCase(\"  hello world\", \" \"): ["
832          + sentenceCase("  hello world", " ") + "]");
833System.out.println("sentenceCase(\"hello world  \", \" \"): ["
834          + sentenceCase("hello world  ", " ") + "]");
835System.out.println("sentenceCase(\"hello_world  \", \"_\"): ["
836          + sentenceCase("hello_world  ", "_") + "]");
837System.out.println("sentenceCase(\"__hello_world_ foo  \", \"_ \"): ["
838          + sentenceCase("__hello_world_ foo  ", "_ ") + "]");
839System.out.println("sentenceCase(\"foXbAr\", \"X\"): ["
840          + sentenceCase("foXbAr", "X") + "]");
841      
842
843System.out.println("viewableAscii(abc[newline]foo[tab]\\u4234)="+viewableAscii("abc\nfoo\t\u4234"));
844for(char c = 0; c < 255; c++) {
845  System.out.print(viewableAscii(c));   
846  }
847System.out.println("");
848
849System.out.println("remove trailing slash on '' = " + removeTrailingSlash(""));
850System.out.println("remove trailing slash on '/' = " + removeTrailingSlash(""));
851System.out.println("remove trailing slash on 'foo/' = " + removeTrailingSlash("foo/"));
852System.out.println("remove beginning slash on '' = " + removeBeginningSlash(""));
853System.out.println("remove beginning slash on '/' = " + removeBeginningSlash("/"));
854System.out.println("remove beginning slash on '/foo' = " + removeBeginningSlash("/foo"));
855
856System.out.println("====fixed width tests");
857String fixedin = "hello";
858int width = 15;
859System.out.println("fixed width input string: " + fixedin);
860System.out.println("fixed width = 15");
861System.out.println("align default: [" + fixedWidth(fixedin, width) + "]");
862System.out.println("align left: [" + fixedWidth(fixedin, width, HAlign.LEFT) + "]");
863System.out.println("align right : [" + fixedWidth(fixedin, width, HAlign.RIGHT) + "]");
864System.out.println("align center: [" + fixedWidth(fixedin, width, HAlign.CENTER) + "]");
865
866System.out.println("repeatToWidth('hello', 0)="+repeatToWidth("hello", 0));
867System.out.println("repeatToWidth('hello', 1)="+repeatToWidth("hello", 1));
868System.out.println("repeatToWidth('hello', 5)="+repeatToWidth("hello", 5));
869System.out.println("repeatToWidth('hello', 9)="+repeatToWidth("hello", 9));
870System.out.println("repeatToWidth('hello', 10)="+repeatToWidth("hello", 10));
871System.out.println("repeatToWidth('hello', 11)="+repeatToWidth("hello", 11));
872
873System.out.println("repeatToWidth('X', 0)=["+repeatToWidth("X", 0) +"]");
874
875System.out.println("escapeSingleQuotes(\"'\")="+escapeSingleQuotes("'"));
876System.out.println("escapeSingleQuotes(\"\")="+escapeSingleQuotes(""));
877System.out.println("escapeSingleQuotes(\"'foo'bar'\")="+escapeSingleQuotes("'foo'bar'"));
878System.out.println("escapeSingleQuotes(\"'''\")="+escapeSingleQuotes("'''"));
879System.out.println("escapeSingleQuotes(\"'foo'bar'\", \"'\")="+escapeSingleQuotes("'foo'bar'", "'"));
880
881
882System.out.println("listToString(null):" + listToString(null, "x"));
883List list = new ArrayList();
884list.add(1);
885list.add(2);
886System.out.println("listToString([1,2] / [ ]): " +listToString(list,"/","[","]"));
887
888System.out.println("ellipsis('hello world', 8): " + ellipsis("hello world", 8));
889
890System.out.println("group default: " + group(Integer.toUnsignedString(-5)));
891System.out.println("group (4,'|'): " + group(Integer.toUnsignedString(-5),4,"|"));
892System.out.println("group (3,' '): " + group(Integer.toUnsignedString(-5),3," "));
893
894
895}
896
897}     //~class StringUtil