001    /*
002     * Copyright (C) 2008-2010 by Holger Arndt
003     *
004     * This file is part of the Universal Java Matrix Package (UJMP).
005     * See the NOTICE file distributed with this work for additional
006     * information regarding copyright ownership and licensing.
007     *
008     * UJMP is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU Lesser General Public License as
010     * published by the Free Software Foundation; either version 2
011     * of the License, or (at your option) any later version.
012     *
013     * UJMP is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016     * GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public
019     * License along with UJMP; if not, write to the
020     * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
021     * Boston, MA  02110-1301  USA
022     */
023    
024    package org.ujmp.core.util;
025    
026    import java.io.IOException;
027    import java.io.Serializable;
028    import java.text.NumberFormat;
029    import java.util.ArrayList;
030    import java.util.Collection;
031    import java.util.List;
032    import java.util.Locale;
033    import java.util.Set;
034    import java.util.regex.Pattern;
035    
036    import org.ujmp.core.Matrix;
037    import org.ujmp.core.exceptions.MatrixException;
038    
039    public abstract class StringUtil {
040    
041            private static final NumberFormat DefaultNF = NumberFormat.getNumberInstance(Locale.US);
042    
043            public static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',
044                            'c', 'd', 'e', 'f' };
045    
046            public static final String BRACKETS = "[\\[\\]\\(\\)\\{\\}]";
047    
048            public static final String SEMICOLONORNEWLINE = "\\s*[;\\n]\\s*";
049    
050            public static final String COLONORSPACES = "[,\\s*]";
051    
052            static {
053                    DefaultNF.setMinimumFractionDigits(4);
054                    DefaultNF.setMaximumFractionDigits(4);
055            }
056    
057            public static final String stripTags(String string) {
058                    return Pattern.compile("\\<[^\\>]*\\>", Pattern.DOTALL + Pattern.MULTILINE).matcher(string)
059                                    .replaceAll("");
060            }
061    
062            public static final String format(String s) {
063                    return (s == null) ? "" : s;
064            }
065    
066            public static final String format(Object o) {
067                    if (o == null) {
068                            return "";
069                    }
070                    if (o instanceof String) {
071                            return (String) o;
072                    }
073                    if (o instanceof Matrix) {
074                            if (((Matrix) o).isScalar()) {
075                                    return format(((Matrix) o).getAsObject(0, 0));
076                            } else {
077                                    return "[Matrix]";
078                            }
079                    }
080                    if (o instanceof Number) {
081                            return format((Number) o);
082                    }
083                    return o.toString();
084            }
085    
086            public static final String encodeToHex(Serializable o) throws IOException {
087                    return encodeToHex(SerializationUtil.serialize(o));
088            }
089    
090            public static final String encodeToHex(byte[] data) {
091                    final StringBuilder s = new StringBuilder(data.length * 2);
092                    final int length = data.length;
093                    for (int i = 0; i < length; i++) {
094                            s.append(HEX[(data[i] + 128) / 16]).append(HEX[(data[i] + 128) % 16]);
095                    }
096                    return s.toString();
097            }
098    
099            public static final int hexToInt(char c) {
100                    switch (c) {
101                    case '0':
102                            return 0;
103                    case '1':
104                            return 1;
105                    case '2':
106                            return 2;
107                    case '3':
108                            return 3;
109                    case '4':
110                            return 4;
111                    case '5':
112                            return 5;
113                    case '6':
114                            return 6;
115                    case '7':
116                            return 7;
117                    case '8':
118                            return 8;
119                    case '9':
120                            return 9;
121                    case 'A':
122                            return 10;
123                    case 'B':
124                            return 11;
125                    case 'C':
126                            return 12;
127                    case 'D':
128                            return 13;
129                    case 'E':
130                            return 14;
131                    case 'F':
132                            return 15;
133                    case 'a':
134                            return 10;
135                    case 'b':
136                            return 11;
137                    case 'c':
138                            return 12;
139                    case 'd':
140                            return 13;
141                    case 'e':
142                            return 14;
143                    case 'f':
144                            return 15;
145                    default:
146                            throw new RuntimeException("this is not a hex string");
147                    }
148            }
149    
150            public static final byte[] decodeFromHex(String data) {
151                    byte[] bytes = new byte[data.length() / 2];
152                    for (int i = 0; i < data.length(); i += 2) {
153                            char c1 = data.charAt(i);
154                            char c2 = data.charAt(i + 1);
155                            int i1 = hexToInt(c1);
156                            int i2 = hexToInt(c2);
157                            bytes[i / 2] = (byte) (i1 * 16 + i2 - 128);
158                    }
159                    return bytes;
160            }
161    
162            public static final String reverse(String s) {
163                    StringBuilder reverted = new StringBuilder(s.length());
164                    for (int i = s.length(); --i != -1;) {
165                            reverted.append(s.charAt(i));
166                    }
167                    return reverted.toString();
168            }
169    
170            public static final String convert(Object o) {
171                    if (o == null) {
172                            return null;
173                    }
174                    if (o instanceof String) {
175                            return (String) o;
176                    }
177                    if (o instanceof Matrix) {
178                            return ((Matrix) o).stringValue();
179                    }
180                    if (o instanceof Number) {
181                            return String.valueOf(((Number) o).doubleValue());
182                    }
183                    return o.toString();
184            }
185    
186            public static final String format(Double value) {
187                    if (value == null)
188                            return "";
189                    if (Double.isNaN(value))
190                            return "NaN";
191                    if (Double.POSITIVE_INFINITY == value)
192                            return "Inf";
193                    if (Double.NEGATIVE_INFINITY == value)
194                            return "-Inf";
195                    return DefaultNF.format(value);
196            }
197    
198            public static final String format(Number value) {
199                    if (value == null)
200                            return "";
201                    if (value instanceof Double)
202                            return format((Double) value);
203                    return DefaultNF.format(value);
204            }
205    
206            public void setDefaultMaximumFractionDigits(int n) {
207                    DefaultNF.setMaximumFractionDigits(n);
208            }
209    
210            public void setDefaultMinimumFractionDigits(int n) {
211                    DefaultNF.setMinimumFractionDigits(n);
212            }
213    
214            public static final String deleteChar(String s, char ch) {
215                    return deleteChar(s, ch, 0);
216            }
217    
218            public static final String deleteChar(String s, char ch, int startIndex) {
219                    int i = s.indexOf(ch, startIndex);
220                    if (i == -1) {
221                            return s;
222                    } else if (i == 0) {
223                            s = s.substring(1);
224                            return deleteChar(s, ch, 0);
225                    } else if (i == s.length() - 1) {
226                            s = s.substring(0, s.length() - 1);
227                            return s;
228                    } else {
229                            new String();
230                            s = s.substring(0, i) + s.substring(i + 1);
231                            return deleteChar(s, ch, i);
232                    }
233            }
234    
235            public static long[][] parseSelection(String selectionString, long[] size) {
236                    if (selectionString.contains(";")) {
237                            return parseSelectionSemicolon(selectionString, size);
238                    } else {
239                            return parseSelectionComma(selectionString, size);
240                    }
241            }
242    
243            private static long[][] parseSelectionComma(String selectionString, long[] size) {
244                    throw new MatrixException(
245                                    "Matlab style is not supported yet. Please use a semicolon (;) to separate rows and columns");
246            }
247    
248            private static long[][] parseSelectionSemicolon(String selectionString, long[] size) {
249                    String[] fields = selectionString.replaceAll(BRACKETS, "").split(";");
250                    long[][] selection = new long[fields.length][];
251    
252                    for (int i = 0; i < fields.length; i++) {
253    
254                            String dimension = fields[i].trim();
255    
256                            if (dimension.contains("*")) {
257                                    selection[i] = MathUtil.sequenceLong(0, size[i] - 1);
258                            } else {
259                                    List<Long> list = new ArrayList<Long>();
260                                    String[] dimselections = dimension.split("\\D*[ \\s,]\\D*");
261                                    for (int j = 0; j < dimselections.length; j++) {
262                                            String dimsel = dimselections[j];
263                                            if (dimsel.contains(":") || dimsel.contains("-")) {
264                                                    String[] range = dimsel.split("[:-]");
265                                                    if (range.length == 0) {
266                                                            // all coordinates in this dimension
267                                                            list.addAll(MathUtil.sequenceListLong(0, size[i] - 1));
268                                                    } else if (range.length == 2) {
269                                                            // from lower bound to upper bound
270                                                            String startS = range[0];
271                                                            String endS = range[1];
272                                                            long start = Long.parseLong(startS.replaceAll("\\D", ""));
273                                                            long end = Long.parseLong(endS.replaceAll("\\D", ""));
274    
275                                                            if (end > size[j]) {
276                                                                    throw new MatrixException("Selection is bigger than size");
277                                                            }
278    
279                                                            list.addAll(MathUtil.sequenceListLong(start, end));
280                                                    } else {
281                                                            throw new MatrixException("Selection not supported: " + dimsel);
282                                                    }
283    
284                                            } else {
285                                                    dimsel = dimsel.replaceAll("\\D", "");
286                                                    if (dimsel.length() > 0) {
287                                                            list.add(Long.parseLong(dimsel));
288                                                    }
289                                            }
290                                    }
291                                    selection[i] = MathUtil.collectionToLong(list);
292                            }
293    
294                    }
295    
296                    return selection;
297            }
298    
299            public static String duration(long time) {
300                    StringBuilder s = new StringBuilder();
301    
302                    int days = (int) (time / (24 * 60 * 60 * 1000));
303                    time = time % (24 * 60 * 60 * 1000);
304                    int hours = (int) (time / (60 * 60 * 1000));
305                    time = time % (60 * 60 * 1000);
306                    int minutes = (int) (time / (60 * 1000));
307                    time = time % (60 * 1000);
308                    int seconds = (int) (time / (1000));
309    
310                    if (days > 0) {
311                            s.append(days + "d");
312                    }
313                    if (hours > 0) {
314                            s.append(hours + "h");
315                    }
316                    if (minutes > 0) {
317                            s.append(minutes + "m");
318                    }
319                    s.append(seconds + "s");
320                    return s.toString();
321            }
322    
323            public static String getAllAsString(Collection<Matrix> collection) {
324                    StringBuffer s = new StringBuffer();
325                    int i = 0;
326                    for (Matrix m : collection) {
327                            if (m != null && !m.isEmpty()) {
328                                    s.append(StringUtil.format(m.stringValue()));
329                            }
330                            if (i < collection.size() - 1) {
331                                    s.append(", ");
332                            }
333                            i++;
334                    }
335                    return s.toString();
336            }
337    
338            public static String deleteChars(String s, Set<Character> ignoredChars, char replacement) {
339                    char[] result = new char[s.length()];
340                    for (int i = 0; i < s.length(); i++) {
341                            char c = s.charAt(i);
342                            if (!ignoredChars.contains(c)) {
343                                    result[i] = c;
344                            } else {
345                                    result[i] = replacement;
346                            }
347                    }
348                    return new String(result);
349            }
350    
351            public static String retainChars(String s, Set<Character> allowedChars, char replacement) {
352                    char[] result = new char[s.length()];
353                    for (int i = 0; i < s.length(); i++) {
354                            char c = s.charAt(i);
355                            if (allowedChars.contains(c)) {
356                                    result[i] = c;
357                            } else {
358                                    result[i] = replacement;
359                            }
360                    }
361                    return new String(result);
362            }
363    
364            public static String toString(Matrix m, Object... parameters) {
365                    int width = 10;
366                    long maxRows = UJMPSettings.getMaxRowsToPrint();
367                    long maxColumns = UJMPSettings.getMaxColumnsToPrint();
368    
369                    StringBuilder s = new StringBuilder();
370    
371                    final String EOL = System.getProperty("line.separator");
372    
373                    long rowCount = m.getRowCount();
374                    long columnCount = m.getColumnCount();
375                    for (int row = 0; row < rowCount && row < maxRows; row++) {
376                            for (int col = 0; col < columnCount && col < maxColumns; col++) {
377                                    Object o = m.getAsObject(row, col);
378                                    String v = StringUtil.format(o);
379                                    v = StringUtil.pad(v, width);
380                                    s.append(v);
381                            }
382                            s.append(EOL);
383                    }
384    
385                    if (rowCount == 0 || columnCount == 0) {
386                            s.append("[" + rowCount + "x" + columnCount + "]" + EOL);
387                    } else if (rowCount > UJMPSettings.getMaxRowsToPrint()
388                                    || columnCount > UJMPSettings.getMaxColumnsToPrint()) {
389                            s.append("[...]");
390                    }
391    
392                    return s.toString();
393    
394            }
395    
396            public static final String pad(String s, int length) {
397                    length = length - s.length();
398                    StringBuilder r = new StringBuilder(length);
399                    for (int i = 0; i < length; i++) {
400                            r.append(" ");
401                    }
402                    r.append(s);
403                    return r.toString();
404            }
405    
406            public static String getString(Object object) {
407                    if (object == null) {
408                            return null;
409                    } else {
410                            return format(object);
411                    }
412            }
413    
414            public static final boolean isASCII(char c) {
415                    return c < 128;
416            }
417    
418            public static final boolean isAlphanumeric(char c) {
419                    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
420            }
421    
422            public static final boolean isAlphanumeric(String s) {
423                    if (s == null) {
424                            return false;
425                    }
426                    for (int i = s.length(); --i != -1;) {
427                            if (!isAlphanumeric(s.charAt(i))) {
428                                    return false;
429                            }
430                    }
431                    return true;
432            }
433    
434            public static final boolean isLetter(char c) {
435                    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
436            }
437    
438            public static final boolean isControl(char c) {
439                    return c < 32 || c == 127;
440            }
441    
442            public static final boolean isNumber(char c) {
443                    return c >= '0' && c <= '9';
444            }
445    
446            public static final boolean isUmlaut(char c) {
447                    return c == 228 || c == 252 || c == 246 || c == 196 || c == 220 || c == 214;
448            }
449    
450            public static final boolean isPrintable(char c) {
451                    return (c >= 32 && c < 127) || (c >= 161 || c <= 255);
452            }
453    
454            public static final boolean isGerman(char c) {
455                    return (c >= 32 && c < 127) || isUmlaut(c) || c == 223;
456            }
457    
458            public static final boolean isLower(char c) {
459                    return c >= 'a' && c <= 'z';
460            }
461    
462            public static final boolean isUpper(char c) {
463                    return c >= 'A' && c <= 'Z';
464            }
465    
466            public static boolean isPrintable(String s) {
467                    if (s == null) {
468                            return false;
469                    }
470                    for (int i = s.length(); --i != -1;) {
471                            if (!isPrintable(s.charAt(i))) {
472                                    return false;
473                            }
474                    }
475                    return true;
476            }
477    
478            public static boolean isSuitedAsFilename(String s) {
479                    if (!StringUtil.isPrintable(s)) {
480                            return false;
481                    }
482                    for (int i = s.length(); --i != -1;) {
483                            char c = s.charAt(i);
484                            if (c == '/') {
485                                    return false;
486                            } else if (c == '\\') {
487                                    return false;
488                            } else if (c == ':') {
489                                    return false;
490                            } else if (c == ' ') {
491                                    return false;
492                            } else if (c == '*') {
493                                    return false;
494                            } else if (c == '<') {
495                                    return false;
496                            } else if (c == '>') {
497                                    return false;
498                            } else if (c == '?') {
499                                    return false;
500                            } else if (c == '|') {
501                                    return false;
502                            }
503                    }
504                    return true;
505            }
506    }