Merge branch 'features/sequenceFeatureRefactor' into develop
[jalview.git] / src / jalview / util / StringUtils.java
index 0544864..1325ce5 100644 (file)
@@ -1,8 +1,15 @@
 package jalview.util;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
 
 public class StringUtils
 {
+  private static final Pattern DELIMITERS_PATTERN = Pattern.compile(".*='[^']*(?!')");
+
+  private static final boolean DEBUG = false;
 
   /**
    * Returns a new character array, after inserting characters into the given
@@ -103,4 +110,124 @@ public class StringUtils
     String[] st = input.split(token);
     return st[st.length - 1];
   }
+
+  /**
+   * Parses the input string into components separated by the delimiter. Unlike
+   * String.split(), this method will ignore occurrences of the delimiter which
+   * are nested within single quotes in name-value pair values, e.g. a='b,c'.
+   * 
+   * @param input
+   * @param delimiter
+   * @return elements separated by separator
+   */
+  public static String[] separatorListToArray(String input, String delimiter)
+  {
+    int seplen = delimiter.length();
+    if (input == null || input.equals("") || input.equals(delimiter))
+    {
+      return null;
+    }
+    List<String> jv = new ArrayList<String>();
+    int cp = 0, pos, escape;
+    boolean wasescaped = false, wasquoted = false;
+    String lstitem = null;
+    while ((pos = input.indexOf(delimiter, cp)) >= cp)
+    {
+      escape = (pos > 0 && input.charAt(pos - 1) == '\\') ? -1 : 0;
+      if (wasescaped || wasquoted)
+      {
+        // append to previous pos
+        jv.set(jv.size() - 1,
+                lstitem = lstitem + delimiter
+                        + input.substring(cp, pos + escape));
+      }
+      else
+      {
+        jv.add(lstitem = input.substring(cp, pos + escape));
+      }
+      cp = pos + seplen;
+      wasescaped = escape == -1;
+      // last separator may be in an unmatched quote
+      wasquoted = DELIMITERS_PATTERN.matcher(lstitem).matches();
+    }
+    if (cp < input.length())
+    {
+      String c = input.substring(cp);
+      if (wasescaped || wasquoted)
+      {
+        // append final separator
+        jv.set(jv.size() - 1, lstitem + delimiter + c);
+      }
+      else
+      {
+        if (!c.equals(delimiter))
+        {
+          jv.add(c);
+        }
+      }
+    }
+    if (jv.size() > 0)
+    {
+      String[] v = jv.toArray(new String[jv.size()]);
+      jv.clear();
+      if (DEBUG)
+      {
+        System.err.println("Array from '" + delimiter
+                + "' separated List:\n" + v.length);
+        for (int i = 0; i < v.length; i++)
+        {
+          System.err.println("item " + i + " '" + v[i] + "'");
+        }
+      }
+      return v;
+    }
+    if (DEBUG)
+    {
+      System.err.println("Empty Array from '" + delimiter
+              + "' separated List");
+    }
+    return null;
+  }
+
+  /**
+   * Returns a string which contains the list elements delimited by the
+   * separator. Null items are ignored. If the input is null or has length zero,
+   * a single delimiter is returned.
+   * 
+   * @param list
+   * @param separator
+   * @return concatenated string
+   */
+  public static String arrayToSeparatorList(String[] list, String separator)
+  {
+    StringBuffer v = new StringBuffer();
+    if (list != null && list.length > 0)
+    {
+      for (int i = 0, iSize = list.length; i < iSize; i++)
+      {
+        if (list[i] != null)
+        {
+          if (v.length() > 0)
+          {
+            v.append(separator);
+          }
+          // TODO - escape any separator values in list[i]
+          v.append(list[i]);
+        }
+      }
+      if (DEBUG)
+      {
+        System.err.println("Returning '" + separator
+                + "' separated List:\n");
+        System.err.println(v);
+      }
+      return v.toString();
+    }
+    if (DEBUG)
+    {
+      System.err.println("Returning empty '" + separator
+              + "' separated List\n");
+    }
+    return "" + separator;
+  }
 }