Strings.java
001 /*
002  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
003  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
004  *
005  *  This file is part of GATE (see http://gate.ac.uk/), and is free
006  *  software, licenced under the GNU Library General Public License,
007  *  Version 2, June 1991 (in the distribution as file licence.html,
008  *  and also available at http://gate.ac.uk/gate/licence.html).
009  *
010  *  Hamish Cunningham, 22/02/2000
011  *
012  *  $Id: Strings.java 12872 2010-07-08 11:29:23Z thomas_heitz $
013  */
014 
015 package gate.util;
016 
017 import java.io.*;
018 import java.util.ArrayList;
019 import java.util.Arrays;
020 import java.util.Collection;
021 import java.util.HashMap;
022 import java.util.List;
023 import java.util.Map;
024 
025 /** Some utilities for use with Strings. */
026 public class Strings {
027 
028   /** Debug flag */
029   private static final boolean DEBUG = false;
030 
031   /** What character to pad with. */
032   private static char padChar = ' ';
033 
034   /** Local fashion for newlines this year. */
035   private static String newline = System.getProperty("line.separator");
036 
037   /** Get local fashion for newlines. */
038   public static String getNl() { return newline; }
039 
040   /** Local fashion for path separators. */
041   private static String pathSep = System.getProperty("path.separator");
042 
043   /** Get local fashion for path separators (e.g. ":"). */
044   public static String getPathSep() { return pathSep; }
045 
046   /** Local fashion for file separators. */
047   private static String fileSep = System.getProperty("file.separator");
048 
049   /** Get local fashion for file separators (e.g. "/"). */
050   public static String getFileSep() { return fileSep; }
051 
052   /** Add n pad characters to pad. */
053   public static String addPadding(String pad, int n) {
054     StringBuffer s = new StringBuffer(pad);
055     for(int i = 0; i < n; i++)
056       s.append(padChar);
057 
058     return s.toString();
059   // padding
060 
061   /** Helper method to add line numbers to a string */
062   public static String addLineNumbers(String text) {
063     return addLineNumbers(text, 1);
064   }
065   
066   public static String addLineNumbers(String text, int startLine) {
067     // construct a line reader for the text
068     BufferedReader reader = new BufferedReader(new StringReader(text));
069     String line = null;
070     StringBuffer result = new StringBuffer();
071 
072     try {
073       for(int lineNum = startLine; line = reader.readLine() ) != null; lineNum++) {
074         String pad;
075         if(lineNum < 10pad = " ";
076         else pad = "";
077         result.append(pad + lineNum + "  " + line + Strings.getNl());
078       }
079     catch(IOException ie) { }
080 
081     return result.toString();
082   // addLineNumbers
083 
084   /**
085    * A method to unescape Java strings, returning a string containing escape
086    * sequences into the respective character. i.e. "\" followed by "t" is turned
087    * into the tab character.
088    *
089    @param str the string to unescape
090    @return a new unescaped string of the one passed in
091    */
092   public static String unescape(String str) {
093     if (str == nullreturn str;
094 
095     StringBuilder sb = new StringBuilder()// string to build
096 
097     StringBuilder unicodeStr = new StringBuilder(4)// store unicode sequences
098 
099     boolean inUnicode = false;
100     boolean hadSlash = false;
101 
102     for (char ch: str.toCharArray()) {
103       if (inUnicode) {
104         unicodeStr.append(ch);
105         if (unicodeStr.length() == 4) {
106           try {
107             int unicodeValue = Integer.parseInt(unicodeStr.toString()16);
108             sb.append((charunicodeValue);
109             unicodeStr.setLength(0);
110             inUnicode = false;
111             hadSlash = false;
112           catch (NumberFormatException e) {
113             throw new RuntimeException("Couldn't parse unicode value: " + unicodeStr, e);
114           }
115         }
116         continue;
117       }
118       if (hadSlash) {
119         hadSlash = false;
120         switch (ch) {
121           case '\\':
122             sb.append('\\');
123             break;
124           case '\'':
125             sb.append('\'');
126             break;
127           case '\"':
128             sb.append('"');
129             break;
130           case 'r':
131             sb.append('\r');
132             break;
133           case 'f':
134             sb.append('\f');
135               break;
136           case 't':
137             sb.append('\t');
138             break;
139           case 'n':
140             sb.append('\n');
141             break;
142           case 'b':
143             sb.append('\b');
144             break;
145           case 'u':
146             inUnicode = true;
147             break;
148           default :
149             sb.append(ch);
150             break;
151         }
152         continue;
153       else if (ch == '\\') {
154         hadSlash = true;
155         continue;
156       }
157       sb.append(ch);
158     }
159     if (hadSlash) {
160       sb.append('\\');
161     }
162     return sb.toString();
163   }
164 
165   /**
166    * Convert about any object to a human readable string.<br>
167    * Use {@link Arrays#deepToString(Object[])} to convert an array or
168    * a collection.
169    @param object object to be converted to a string
170    @return a string representation of the object, the empty string if null.
171    */
172   public static String toString(Object object) {
173     if (object == null) {
174       return "";
175     else if (object instanceof Object[]) {
176       return Arrays.deepToString((Object[])object);
177     else if (object instanceof Collection) {
178       return Arrays.deepToString(((Collection)object).toArray());
179     else {
180       return object.toString();
181     }
182   }
183 
184   /**
185    * Create a String representation of a List of String with the format
186    * [value, value].
187    * Escape with a backslash the separator character.
188    @param list list to convert to one String
189    @return a String that represent the list
190    @see #toList(String, String)
191    */
192   public static String toString(List<String> list) {
193     StringBuilder builder = new StringBuilder();
194     builder.append('[');
195     for (String element : list) {
196       // escape list separator
197       String escapedElement = element.replaceAll(",""\\\\,");
198       builder.append(escapedElement).append(", ");
199     }
200     if (builder.length() 1) { // remove last list separator
201       builder.delete(builder.length()-2, builder.length());
202     }
203     builder.append("]");
204     return builder.toString();
205   }
206 
207   /**
208    * Create a String representation of a Map of String*String with the format
209    * {key=value, key=value}.
210    * Escape with a backslash the separator characters.
211    @param map map to convert to one String
212    @return a String that represent the map
213    @see #toMap(String)
214    */
215   public static String toString(Map<String, String> map) {
216     StringBuilder builder = new StringBuilder();
217     builder.append('{');
218     for (Map.Entry<String, String> entry : map.entrySet()) {
219       // escape list separator
220       String escapedKey = entry.getKey().replaceAll("=""\\\\=")
221         .replaceAll(",""\\\\,");
222       String escapedValue = entry.getValue().replaceAll("=""\\\\=")
223         .replaceAll(",""\\\\,");
224       builder.append(escapedKey).append("=").append(escapedValue).append(", ");
225     }
226     if (builder.length() 1) { // remove last list separator
227       builder.delete(builder.length()-2, builder.length());
228     }
229     builder.append("}");
230     return builder.toString();
231   }
232 
233   /**
234    * Get back a List of String from its String representation.
235    * Unescape backslashed separator characters.
236    @param string String to convert to a List
237    @param separator String that delimits the element of the list
238    @return a List
239    @see #toString(java.util.List)
240    */
241   public static List<String> toList(String string, String separator) {
242     List<String> list = new ArrayList<String>();
243     if (string == null
244      || string.length() 3) {
245       return list;
246     }
247     // remove last character
248     String value = string.substring(0, string.length()-1);
249     int index = 1;
250     int startIndex = 1;
251     int separatorIndex;
252     // split on list separator
253     while ((separatorIndex = value.indexOf(separator, index)) != -1) {
254       // check that the separator is not an escaped character
255       if (value.charAt(separatorIndex-1!= '\\') {
256         list.add(value.substring(startIndex, separatorIndex)
257           // unescape separator
258           .replaceAll("\\\\"+separator.charAt(0)""+separator.charAt(0)));
259         startIndex = separatorIndex + separator.length();
260       }
261       index = separatorIndex + separator.length();
262     }
263     // last element of the list
264     list.add(value.substring(startIndex));
265     return list;
266   }
267 
268   /**
269    * Get back a Map of String*String from its String representation.
270    * Unescape backslashed separator characters.
271    @param string String to convert to a Map
272    @return a Map
273    @see #toString(java.util.Map)
274    */
275   public static Map<String, String> toMap(String string) {
276     Map<String, String> map = new HashMap<String, String>();
277     if (string == null
278      || string.length() 3) {
279       return map;
280     }
281     List<String> firstList = toList(string, ", ");
282     for (String element : firstList) {
283       List<String> secondList = toList("["+element+"]""=");
284       if (secondList.size() == 2) {
285         map.put(secondList.get(0), secondList.get(1));
286       else {
287         Err.prln("Ignoring element: [" + element + "]");
288         Err.prln("Expecting: [key=value]");
289       }
290     }
291     return map;
292   }
293 
294   /**
295    * Crop the text in the middle if too long.
296    @param text text to crop
297    @param maxLength maximum length of the text
298    @return cropped text if needed otherwise the same text
299    */
300   public static String crop(String text, int maxLength) {
301     if (text.length() > maxLength) {
302       text = text.substring(0(maxLength/2)-2"..."
303         + text.substring(text.length() (maxLength/2));
304     }
305     return text;
306   }
307 
308 // class Strings