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