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 }