JAL-3130 adapted getdown src. attempt 2. first attempt failed due to cp'ed .git files
[jalview.git] / getdown / src / getdown / core / src / main / java / com / threerings / getdown / util / StringUtil.java
1 //
2 // Getdown - application installer, patcher and launcher
3 // Copyright (C) 2004-2018 Getdown authors
4 // https://github.com/threerings/getdown/blob/master/LICENSE
5
6 package com.threerings.getdown.util;
7
8 import java.util.StringTokenizer;
9
10 public class StringUtil {
11
12     /**
13      * @return true if the specified string could be a valid URL (contains no illegal characters)
14      */
15     public static boolean couldBeValidUrl (String url)
16     {
17         return url.matches("[A-Za-z0-9\\-\\._~:/\\?#\\[\\]@!$&'\\(\\)\\*\\+,;=%]+");
18     }
19
20     /**
21      * @return true if the string is null or consists only of whitespace, false otherwise.
22      */
23     public static boolean isBlank (String value)
24     {
25         for (int ii = 0, ll = (value == null) ? 0 : value.length(); ii < ll; ii++) {
26             if (!Character.isWhitespace(value.charAt(ii))) {
27                 return false;
28             }
29         }
30         return true;
31     }
32
33     /**
34      * Parses an array of integers from it's string representation. The array should be represented
35      * as a bare list of numbers separated by commas, for example:
36      *
37      * <pre>25, 17, 21, 99</pre>
38      *
39      * Any inability to parse the int array will result in the function returning null.
40      */
41     public static int[] parseIntArray (String source)
42     {
43         StringTokenizer tok = new StringTokenizer(source, ",");
44         int[] vals = new int[tok.countTokens()];
45         for (int i = 0; tok.hasMoreTokens(); i++) {
46             try {
47                 // trim the whitespace from the token
48                 vals[i] = Integer.parseInt(tok.nextToken().trim());
49             } catch (NumberFormatException nfe) {
50                 return null;
51             }
52         }
53         return vals;
54     }
55
56     /**
57      * Parses an array of strings from a single string. The array should be represented as a bare
58      * list of strings separated by commas, for example:
59      *
60      * <pre>mary, had, a, little, lamb, and, an, escaped, comma,,</pre>
61      *
62      * If a comma is desired in one of the strings, it should be escaped by putting two commas in a
63      * row. Any inability to parse the string array will result in the function returning null.
64      */
65     public static String[] parseStringArray (String source)
66     {
67         return parseStringArray(source, false);
68     }
69
70     /**
71      * Like {@link #parseStringArray(String)} but can be instructed to invoke {@link String#intern}
72      * on the strings being parsed into the array.
73      */
74     public static String[] parseStringArray (String source, boolean intern)
75     {
76         int tcount = 0, tpos = -1, tstart = 0;
77
78         // empty strings result in zero length arrays
79         if (source.length() == 0) {
80             return new String[0];
81         }
82
83         // sort out escaped commas
84         source = source.replace(",,", "%COMMA%");
85
86         // count up the number of tokens
87         while ((tpos = source.indexOf(",", tpos+1)) != -1) {
88             tcount++;
89         }
90
91         String[] tokens = new String[tcount+1];
92         tpos = -1; tcount = 0;
93
94         // do the split
95         while ((tpos = source.indexOf(",", tpos+1)) != -1) {
96             tokens[tcount] = source.substring(tstart, tpos);
97             tokens[tcount] = tokens[tcount].trim().replace("%COMMA%", ",");
98             if (intern) {
99                 tokens[tcount] = tokens[tcount].intern();
100             }
101             tstart = tpos+1;
102             tcount++;
103         }
104
105         // grab the last token
106         tokens[tcount] = source.substring(tstart);
107         tokens[tcount] = tokens[tcount].trim().replace("%COMMA%", ",");
108
109         return tokens;
110     }
111
112     /**
113      * @return the supplied string if it is non-null, "" if it is null.
114      */
115     public static String deNull (String value)
116     {
117         return (value == null) ? "" : value;
118     }
119
120     /**
121      * Generates a string from the supplied bytes that is the HEX encoded representation of those
122      * bytes.  Returns the empty string for a <code>null</code> or empty byte array.
123      *
124      * @param bytes the bytes for which we want a string representation.
125      * @param count the number of bytes to stop at (which will be coerced into being {@code <=} the
126      * length of the array).
127      */
128     public static String hexlate (byte[] bytes, int count)
129     {
130         if (bytes == null) {
131             return "";
132         }
133
134         count = Math.min(count, bytes.length);
135         char[] chars = new char[count*2];
136
137         for (int i = 0; i < count; i++) {
138             int val = bytes[i];
139             if (val < 0) {
140                 val += 256;
141             }
142             chars[2*i] = XLATE.charAt(val/16);
143             chars[2*i+1] = XLATE.charAt(val%16);
144         }
145
146         return new String(chars);
147     }
148
149     /**
150      * Generates a string from the supplied bytes that is the HEX encoded representation of those
151      * bytes.
152      */
153     public static String hexlate (byte[] bytes)
154     {
155         return (bytes == null) ? "" : hexlate(bytes, bytes.length);
156     }
157
158     /**
159      * Joins an array of strings (or objects which will be converted to strings) into a single
160      * string separated by commas.
161      */
162     public static String join (Object[] values)
163     {
164         return join(values, false);
165     }
166
167     /**
168      * Joins an array of strings into a single string, separated by commas, and optionally escaping
169      * commas that occur in the individual string values such that a subsequent call to {@link
170      * #parseStringArray} would recreate the string array properly. Any elements in the values
171      * array that are null will be treated as an empty string.
172      */
173     public static String join (Object[] values, boolean escape)
174     {
175         return join(values, ", ", escape);
176     }
177
178     /**
179      * Joins the supplied array of strings into a single string separated by the supplied
180      * separator.
181      */
182     public static String join (Object[] values, String separator)
183     {
184         return join(values, separator, false);
185     }
186
187     /**
188      * Helper function for the various <code>join</code> methods.
189      */
190     protected static String join (Object[] values, String separator, boolean escape)
191     {
192         StringBuilder buf = new StringBuilder();
193         int vlength = values.length;
194         for (int i = 0; i < vlength; i++) {
195             if (i > 0) {
196                 buf.append(separator);
197             }
198             String value = (values[i] == null) ? "" : values[i].toString();
199             buf.append((escape) ? value.replace(",", ",,") : value);
200         }
201         return buf.toString();
202     }
203
204     /** Used by {@link #hexlate} and {@link #unhexlate}. */
205     protected static final String XLATE = "0123456789abcdef";
206 }