533e98beabeb205e6f27f8cd866da9d1ad718768
[jalview.git] / src / jalview / util / StringUtils.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.util;
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.regex.Pattern;
26
27 public class StringUtils
28 {
29   private static final Pattern DELIMITERS_PATTERN = Pattern
30           .compile(".*='[^']*(?!')");
31
32   private static final boolean DEBUG = false;
33
34   /**
35    * Returns a new character array, after inserting characters into the given
36    * character array.
37    * 
38    * @param in
39    *          the character array to insert into
40    * @param position
41    *          the 0-based position for insertion
42    * @param count
43    *          the number of characters to insert
44    * @param ch
45    *          the character to insert
46    */
47   public static final char[] insertCharAt(char[] in, int position,
48           int count, char ch)
49   {
50     char[] tmp = new char[in.length + count];
51
52     if (position >= in.length)
53     {
54       System.arraycopy(in, 0, tmp, 0, in.length);
55       position = in.length;
56     }
57     else
58     {
59       System.arraycopy(in, 0, tmp, 0, position);
60     }
61
62     int index = position;
63     while (count > 0)
64     {
65       tmp[index++] = ch;
66       count--;
67     }
68
69     if (position < in.length)
70     {
71       System.arraycopy(in, position, tmp, index, in.length - position);
72     }
73
74     return tmp;
75   }
76
77   /**
78    * Delete
79    * 
80    * @param in
81    * @param from
82    * @param to
83    * @return
84    */
85   public static final char[] deleteChars(char[] in, int from, int to)
86   {
87     if (from >= in.length || from < 0)
88     {
89       return in;
90     }
91
92     char[] tmp;
93
94     if (to >= in.length)
95     {
96       tmp = new char[from];
97       System.arraycopy(in, 0, tmp, 0, from);
98       to = in.length;
99     }
100     else
101     {
102       tmp = new char[in.length - to + from];
103       System.arraycopy(in, 0, tmp, 0, from);
104       System.arraycopy(in, to, tmp, from, in.length - to);
105     }
106     return tmp;
107   }
108
109   /**
110    * Returns the last part of 'input' after the last occurrence of 'token'. For
111    * example to extract only the filename from a full path or URL.
112    * 
113    * @param input
114    * @param token
115    *          a delimiter which must be in regular expression format
116    * @return
117    */
118   public static String getLastToken(String input, String token)
119   {
120     if (input == null)
121     {
122       return null;
123     }
124     if (token == null)
125     {
126       return input;
127     }
128     String[] st = input.split(token);
129     return st[st.length - 1];
130   }
131
132   /**
133    * Parses the input string into components separated by the delimiter. Unlike
134    * String.split(), this method will ignore occurrences of the delimiter which
135    * are nested within single quotes in name-value pair values, e.g. a='b,c'.
136    * 
137    * @param input
138    * @param delimiter
139    * @return elements separated by separator
140    */
141   public static String[] separatorListToArray(String input, String delimiter)
142   {
143     int seplen = delimiter.length();
144     if (input == null || input.equals("") || input.equals(delimiter))
145     {
146       return null;
147     }
148     List<String> jv = new ArrayList<String>();
149     int cp = 0, pos, escape;
150     boolean wasescaped = false, wasquoted = false;
151     String lstitem = null;
152     while ((pos = input.indexOf(delimiter, cp)) >= cp)
153     {
154       escape = (pos > 0 && input.charAt(pos - 1) == '\\') ? -1 : 0;
155       if (wasescaped || wasquoted)
156       {
157         // append to previous pos
158         jv.set(jv.size() - 1,
159                 lstitem = lstitem + delimiter
160                         + input.substring(cp, pos + escape));
161       }
162       else
163       {
164         jv.add(lstitem = input.substring(cp, pos + escape));
165       }
166       cp = pos + seplen;
167       wasescaped = escape == -1;
168       // last separator may be in an unmatched quote
169       wasquoted = DELIMITERS_PATTERN.matcher(lstitem).matches();
170     }
171     if (cp < input.length())
172     {
173       String c = input.substring(cp);
174       if (wasescaped || wasquoted)
175       {
176         // append final separator
177         jv.set(jv.size() - 1, lstitem + delimiter + c);
178       }
179       else
180       {
181         if (!c.equals(delimiter))
182         {
183           jv.add(c);
184         }
185       }
186     }
187     if (jv.size() > 0)
188     {
189       String[] v = jv.toArray(new String[jv.size()]);
190       jv.clear();
191       if (DEBUG)
192       {
193         System.err.println("Array from '" + delimiter
194                 + "' separated List:\n" + v.length);
195         for (int i = 0; i < v.length; i++)
196         {
197           System.err.println("item " + i + " '" + v[i] + "'");
198         }
199       }
200       return v;
201     }
202     if (DEBUG)
203     {
204       System.err.println("Empty Array from '" + delimiter
205               + "' separated List");
206     }
207     return null;
208   }
209
210   /**
211    * Returns a string which contains the list elements delimited by the
212    * separator. Null items are ignored. If the input is null or has length zero,
213    * a single delimiter is returned.
214    * 
215    * @param list
216    * @param separator
217    * @return concatenated string
218    */
219   public static String arrayToSeparatorList(String[] list, String separator)
220   {
221     StringBuffer v = new StringBuffer();
222     if (list != null && list.length > 0)
223     {
224       for (int i = 0, iSize = list.length; i < iSize; i++)
225       {
226         if (list[i] != null)
227         {
228           if (v.length() > 0)
229           {
230             v.append(separator);
231           }
232           // TODO - escape any separator values in list[i]
233           v.append(list[i]);
234         }
235       }
236       if (DEBUG)
237       {
238         System.err.println("Returning '" + separator
239                 + "' separated List:\n");
240         System.err.println(v);
241       }
242       return v.toString();
243     }
244     if (DEBUG)
245     {
246       System.err.println("Returning empty '" + separator
247               + "' separated List\n");
248     }
249     return "" + separator;
250   }
251 }