JAL-3691 patch toUpper/toLower to use Locale.ROOT for 2.11.2 src
[jalview.git] / src / jalview / util / StringUtils.java
index 2e8ace8..ff1c944 100644 (file)
  */
 package jalview.util;
 
+import java.util.Locale;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.regex.Pattern;
@@ -29,8 +33,16 @@ public class StringUtils
   private static final Pattern DELIMITERS_PATTERN = Pattern
           .compile(".*='[^']*(?!')");
 
+  private static final char PERCENT = '%';
+
   private static final boolean DEBUG = false;
 
+  /*
+   * URL encoded characters, indexed by char value
+   * e.g. urlEncodings['='] = urlEncodings[61] = "%3D"
+   */
+  private static String[] urlEncodings = new String[255];
+
   /**
    * Returns a new character array, after inserting characters into the given
    * character array.
@@ -146,7 +158,7 @@ public class StringUtils
     {
       return null;
     }
-    List<String> jv = new ArrayList<String>();
+    List<String> jv = new ArrayList<>();
     int cp = 0, pos, escape;
     boolean wasescaped = false, wasquoted = false;
     String lstitem = null;
@@ -399,9 +411,9 @@ public class StringUtils
     }
     if (s.length() <= 1)
     {
-      return s.toUpperCase();
+      return s.toUpperCase(Locale.ROOT);
     }
-    return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
+    return s.substring(0, 1).toUpperCase(Locale.ROOT) + s.substring(1).toLowerCase(Locale.ROOT);
   }
 
   /**
@@ -417,7 +429,7 @@ public class StringUtils
     {
       return null;
     }
-    String tmp2up = text.toUpperCase();
+    String tmp2up = text.toUpperCase(Locale.ROOT);
     int startTag = tmp2up.indexOf("<HTML>");
     if (startTag > -1)
     {
@@ -436,7 +448,7 @@ public class StringUtils
     {
       text = text.substring(0, endTag);
     }
-  
+
     if (startTag == -1 && (text.contains("<") || text.contains(">")))
     {
       text = text.replaceAll("<", "&lt;");
@@ -444,4 +456,132 @@ public class StringUtils
     }
     return text;
   }
+
+  /**
+   * Answers the input string with any occurrences of the 'encodeable'
+   * characters replaced by their URL encoding
+   * 
+   * @param s
+   * @param encodable
+   * @return
+   */
+  public static String urlEncode(String s, String encodable)
+  {
+    if (s == null || s.isEmpty())
+    {
+      return s;
+    }
+
+    /*
+     * do % encoding first, as otherwise it may double-encode!
+     */
+    if (encodable.indexOf(PERCENT) != -1)
+    {
+      s = urlEncode(s, PERCENT);
+    }
+
+    for (char c : encodable.toCharArray())
+    {
+      if (c != PERCENT)
+      {
+        s = urlEncode(s, c);
+      }
+    }
+    return s;
+  }
+
+  /**
+   * Answers the input string with any occurrences of {@code c} replaced with
+   * their url encoding. Answers the input string if it is unchanged.
+   * 
+   * @param s
+   * @param c
+   * @return
+   */
+  static String urlEncode(String s, char c)
+  {
+    String decoded = String.valueOf(c);
+    if (s.indexOf(decoded) != -1)
+    {
+      String encoded = getUrlEncoding(c);
+      if (!encoded.equals(decoded))
+      {
+        s = s.replace(decoded, encoded);
+      }
+    }
+    return s;
+  }
+
+  /**
+   * Answers the input string with any occurrences of the specified (unencoded)
+   * characters replaced by their URL decoding.
+   * <p>
+   * Example: {@code urlDecode("a%3Db%3Bc", "-;=,")} should answer
+   * {@code "a=b;c"}.
+   * 
+   * @param s
+   * @param encodable
+   * @return
+   */
+  public static String urlDecode(String s, String encodable)
+  {
+    if (s == null || s.isEmpty())
+    {
+      return s;
+    }
+
+    for (char c : encodable.toCharArray())
+    {
+      String encoded = getUrlEncoding(c);
+      if (s.indexOf(encoded) != -1)
+      {
+        String decoded = String.valueOf(c);
+        s = s.replace(encoded, decoded);
+      }
+    }
+    return s;
+  }
+
+  /**
+   * Does a lazy lookup of the url encoding of the given character, saving the
+   * value for repeat lookups
+   * 
+   * @param c
+   * @return
+   */
+  private static String getUrlEncoding(char c)
+  {
+    if (c < 0 || c >= urlEncodings.length)
+    {
+      return String.valueOf(c);
+    }
+
+    String enc = urlEncodings[c];
+    if (enc == null)
+    {
+      try
+      {
+        enc = urlEncodings[c] = URLEncoder.encode(String.valueOf(c),
+                "UTF-8");
+      } catch (UnsupportedEncodingException e)
+      {
+        enc = urlEncodings[c] = String.valueOf(c);
+      }
+    }
+    return enc;
+  }
+
+  public static int firstCharPosIgnoreCase(String text, String chars)
+  {
+    int min = text.length() + 1;
+    for (char c : chars.toLowerCase(Locale.ROOT).toCharArray())
+    {
+      int i = text.toLowerCase(Locale.ROOT).indexOf(c);
+      if (0 <= i && i < min)
+      {
+        min = i;
+      }
+    }
+    return min < text.length() + 1 ? min : -1;
+  }
 }