001/* 002 * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License 003 * 004 * Permission is hereby granted, free of charge, to any person obtaining 005 * a copy of this software and associated documentation files (the 006 * "Software"), to deal in the Software without restriction, including 007 * without limitation the rights to use, copy, modify, merge, publish, 008 * distribute, sublicense, and/or sell copies of the Software, and to 009 * permit persons to whom the Software is furnished to do so, subject to 010 * the following conditions: 011 * 012 * The above copyright notice and this permission notice shall be 013 * included in all copies or substantial portions of the Software. 014 * 015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 016 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 017 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 018 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 019 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 020 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 021 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 022 */ 023 024package co.aikar.commands; 025 026 027import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil; 028import org.jetbrains.annotations.NotNull; 029import org.jetbrains.annotations.Nullable; 030 031import java.math.BigDecimal; 032import java.text.Normalizer; 033import java.text.Normalizer.Form; 034import java.text.NumberFormat; 035import java.util.ArrayList; 036import java.util.Collection; 037import java.util.List; 038import java.util.Random; 039import java.util.regex.Matcher; 040import java.util.regex.Pattern; 041import java.util.stream.Collectors; 042import java.util.stream.Stream; 043 044@SuppressWarnings({"WeakerAccess", "unused"}) 045public final class ACFUtil { 046 047 public static final Random RANDOM = new Random(); 048 049 private ACFUtil() {} 050 051 public static String padRight(String s, int n) { 052 return String.format("%1$-" + n + "s", s); 053 } 054 055 public static String padLeft(String s, int n) { 056 return String.format("%1$" + n + "s", s); 057 } 058 059 public static String formatNumber(Integer balance) { 060 return NumberFormat.getInstance().format(balance); 061 } 062 063 public static <T extends Enum> T getEnumFromName(T[] types, String name) { 064 return getEnumFromName(types, name, null); 065 } 066 public static <T extends Enum> T getEnumFromName(T[] types, String name, T def) { 067 for (T type : types) { 068 if (type.name().equalsIgnoreCase(name)) { 069 return type; 070 } 071 } 072 return def; 073 } 074 public static <T extends Enum> T getEnumFromOrdinal(T[] types, int ordinal) { 075 for (T type : types) { 076 if (type.ordinal() == ordinal) { 077 return type; 078 } 079 } 080 return null; 081 } 082 083 public static String ucfirst(String str) { 084 return ApacheCommonsLangUtil.capitalizeFully(str); 085 } 086 087 public static Double parseDouble(String var) { 088 return parseDouble(var, null); 089 } 090 091 public static Double parseDouble(String var, Double def) { 092 if (var == null) { 093 return def; 094 } 095 try { 096 return Double.parseDouble(var); 097 } catch (NumberFormatException ignored) {} 098 return def; 099 } 100 101 public static Float parseFloat(String var) { 102 return parseFloat(var, null); 103 } 104 public static Float parseFloat(String var, Float def) { 105 if (var == null) { 106 return def; 107 } 108 try { 109 return Float.parseFloat(var); 110 } catch (NumberFormatException ignored) {} 111 return def; 112 } 113 public static Long parseLong(String var) { 114 return parseLong(var, null); 115 } 116 public static Long parseLong(String var, Long def) { 117 if (var == null) { 118 return def; 119 } 120 try { 121 return Long.parseLong(var); 122 } catch (NumberFormatException ignored) {} 123 return def; 124 } 125 126 public static Integer parseInt(String var) { 127 return parseInt(var, null); 128 } 129 public static Integer parseInt(String var, Integer def) { 130 if (var == null) { 131 return def; 132 } 133 try { 134 return Integer.parseInt(var); 135 } catch (NumberFormatException ignored) {} 136 return def; 137 } 138 139 public static boolean randBool() { 140 return RANDOM.nextBoolean(); 141 } 142 143 public static <T> T nullDefault(Object val, Object def) { 144 //noinspection unchecked 145 return (T) (val != null ? val : def); 146 } 147 148 public static String join(Collection<String> args) { 149 return ApacheCommonsLangUtil.join(args, " "); 150 } 151 public static String join(Collection<String> args, String sep) { 152 return ApacheCommonsLangUtil.join(args, sep); 153 } 154 public static String join(String[] args) { 155 return join(args, 0, ' '); 156 } 157 158 public static String join(String[] args, String sep) { 159 return ApacheCommonsLangUtil.join(args, sep); 160 } 161 public static String join(String[] args, char sep) { 162 return join(args, 0, sep); 163 } 164 165 public static String join(String[] args, int index) { 166 return join(args, index, ' '); 167 } 168 169 public static String join(String[] args, int index, char sep) { 170 return ApacheCommonsLangUtil.join(args, sep, index, args.length); 171 } 172 173 public static String simplifyString(String str) { 174 if (str == null) { 175 return null; 176 } 177 return ACFPatterns.NON_ALPHA_NUMERIC.matcher(str.toLowerCase()).replaceAll(""); 178 } 179 180 public static double round(double x, int scale) { 181 try { 182 return (new BigDecimal 183 (Double.toString(x)) 184 .setScale(scale, BigDecimal.ROUND_HALF_UP)) 185 .doubleValue(); 186 } catch (NumberFormatException ex) { 187 if (Double.isInfinite(x)) { 188 return x; 189 } else { 190 return Double.NaN; 191 } 192 } 193 } 194 public static int roundUp(int num, int multiple) { 195 if(multiple == 0) { 196 return num; 197 } 198 199 int remainder = num % multiple; 200 if (remainder == 0) { 201 return num; 202 } 203 return num + multiple - remainder; 204 205 } 206 207 public static String limit(String str, int limit) { 208 return str.length() > limit ? str.substring(0, limit) : str; 209 } 210 211 /** 212 * Plain string replacement, escapes replace value. 213 * @param string 214 * @param pattern 215 * @param repl 216 * @return 217 */ 218 public static String replace(String string, Pattern pattern, String repl) { 219 return pattern.matcher(string).replaceAll(Matcher.quoteReplacement(repl)); 220 } 221 222 /** 223 * Regex version of {@link #replace(String, Pattern, String)} 224 * @param string 225 * @param pattern 226 * @param repl 227 * @return 228 */ 229 public static String replacePattern(String string, Pattern pattern, String repl) { 230 return pattern.matcher(string).replaceAll(repl); 231 } 232 233 /** 234 * Plain String replacement. If you need regex patterns, see {@link #replacePattern(String, String, String)} 235 * @param string 236 * @param pattern 237 * @param repl 238 * @return 239 */ 240 public static String replace(String string, String pattern, String repl) { 241 return replace(string, ACFPatterns.getPattern(Pattern.quote(pattern)), repl); 242 } 243 244 /** 245 * Regex version of {@link #replace(String, String, String)} 246 * @param string 247 * @param pattern 248 * @param repl 249 * @return 250 */ 251 public static String replacePattern(String string, String pattern, String repl) { 252 return replace(string, ACFPatterns.getPattern(pattern), repl); 253 } 254 /** 255 * Pure Regex Pattern matching and replacement, no escaping 256 * @param string 257 * @param pattern 258 * @param repl 259 * @return 260 */ 261 public static String replacePatternMatch(String string, Pattern pattern, String repl) { 262 return pattern.matcher(string).replaceAll(repl); 263 } 264 265 /** 266 * Pure Regex Pattern matching and replacement, no escaping 267 * @param string 268 * @param pattern 269 * @param repl 270 * @return 271 */ 272 public static String replacePatternMatch(String string, String pattern, String repl) { 273 return replacePatternMatch(string, ACFPatterns.getPattern(pattern), repl); 274 } 275 276 public static String replaceStrings(String string, String... replacements) { 277 if (replacements.length < 2 || replacements.length % 2 != 0) { 278 throw new IllegalArgumentException("Invalid Replacements"); 279 } 280 for (int i = 0; i < replacements.length; i += 2) { 281 String key = replacements[i]; 282 String value = replacements[i+1]; 283 if (value == null) value = ""; 284 string = replace(string, key, value); 285 } 286 return string; 287 } 288 public static String replacePatterns(String string, String... replacements) { 289 if (replacements.length < 2 || replacements.length % 2 != 0) { 290 throw new IllegalArgumentException("Invalid Replacements"); 291 } 292 for (int i = 0; i < replacements.length; i += 2) { 293 String key = replacements[i]; 294 String value = replacements[i+1]; 295 if (value == null) value = ""; 296 string = replacePattern(string, key, value); 297 } 298 return string; 299 } 300 301 public static String capitalize(String str, char[] delimiters) { 302 return ApacheCommonsLangUtil.capitalize(str, delimiters); 303 } 304 private static boolean isDelimiter(char ch, char[] delimiters) { 305 return ApacheCommonsLangUtil.isDelimiter(ch, delimiters); 306 } 307 308 public static <T> T random(List<T> arr) { 309 if (arr == null || arr.isEmpty()) { 310 return null; 311 } 312 return arr.get(RANDOM.nextInt(arr.size())); 313 } 314 public static <T> T random(T[] arr) { 315 if (arr == null || arr.length == 0) { 316 return null; 317 } 318 return arr[RANDOM.nextInt(arr.length)]; 319 } 320 321 /** 322 * Added as im sure we will try to "Find this" again. This is no different than Enum.values() passed to above method logically 323 * but the array version is slightly faster. 324 * @param enm 325 * @param <T> 326 * @return 327 */ 328 @Deprecated 329 public static <T extends Enum<?>> T random(Class<? extends T> enm) { 330 return random(enm.getEnumConstants()); 331 } 332 333 public static String normalize(String s) { 334 if (s == null) { 335 return null; 336 } 337 return ACFPatterns.NON_PRINTABLE_CHARACTERS.matcher(Normalizer.normalize(s, Form.NFD)).replaceAll(""); 338 } 339 340 public static int indexOf(String arg, String[] split) { 341 for (int i = 0; i < split.length; i++) { 342 if (arg == null) { 343 if (split[i] == null) { 344 return i; 345 } 346 } else if (arg.equals(split[i])) { 347 return i; 348 } 349 } 350 return -1; 351 } 352 353 public static String capitalizeFirst(String name) { 354 return capitalizeFirst(name, '_'); 355 } 356 357 public static String capitalizeFirst(String name, char separator) { 358 name = name.toLowerCase(); 359 String[] split = name.split(Character.toString(separator)); 360 StringBuilder total = new StringBuilder(3); 361 for (String s : split) { 362 total.append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).append(' '); 363 } 364 365 return total.toString().trim(); 366 } 367 368 public static String ltrim(String s) { 369 int i = 0; 370 while (i < s.length() && Character.isWhitespace(s.charAt(i))) { 371 i++; 372 } 373 return s.substring(i); 374 } 375 376 public static String rtrim(String s) { 377 int i = s.length()-1; 378 while (i >= 0 && Character.isWhitespace(s.charAt(i))) { 379 i--; 380 } 381 return s.substring(0,i+1); 382 } 383 384 public static List<String> enumNames(Enum<?>[] values) { 385 return Stream.of(values).map(Enum::name).collect(Collectors.toList()); 386 } 387 388 public static List<String> enumNames(Class<? extends Enum<?>> cls) { 389 return enumNames(cls.getEnumConstants()); 390 } 391 392 public static String combine(String[] args) { 393 return combine(args, 0); 394 } 395 public static String combine(String[] args, int start) { 396 int size = 0; 397 for (int i = start; i < args.length; i++) { 398 size += args[i].length(); 399 } 400 StringBuilder sb = new StringBuilder(size); 401 for (int i = start; i < args.length; i++) { 402 sb.append(args[i]); 403 } 404 return sb.toString(); 405 } 406 407 408 @Nullable public static <E extends Enum<E>> E simpleMatch(Class<? extends Enum<?>> list, String item) { 409 if (item == null) { 410 return null; 411 } 412 item = ACFUtil.simplifyString(item); 413 for (Enum<?> s : list.getEnumConstants()) { 414 String simple = ACFUtil.simplifyString(s.name()); 415 if (item.equals(simple)) { 416 //noinspection unchecked 417 return (E) s; 418 } 419 } 420 421 return null; 422 } 423 424 public static boolean isTruthy(String test) { 425 switch (test) { 426 case "t": 427 case "true": 428 case "on": 429 case "y": 430 case "yes": 431 case "1": 432 return true; 433 } 434 return false; 435 } 436 437 438 public static Number parseNumber(String num, boolean suffixes) { 439 double mod = 1; 440 if (suffixes) { 441 switch (num.charAt(num.length()-1)) { 442 case 'M': 443 case 'm': 444 mod = 1000000D; 445 num = num.substring(0, num.length()-1); 446 break; 447 case 'K': 448 case 'k': 449 mod = 1000D; 450 num = num.substring(0, num.length()-1); 451 } 452 } 453 454 return Double.parseDouble(num) * mod; 455 } 456 457 public static <T> boolean hasIntersection(Collection<T> list1, Collection<T> list2) { 458 for (T t : list1) { 459 if (list2.contains(t)) { 460 return true; 461 } 462 } 463 464 return false; 465 } 466 467 public static <T> Collection<T> intersection(Collection<T> list1, Collection<T> list2) { 468 List<T> list = new ArrayList<>(); 469 470 for (T t : list1) { 471 if(list2.contains(t)) { 472 list.add(t); 473 } 474 } 475 476 return list; 477 } 478 479 public static int rand(int min, int max) { 480 return min + RANDOM.nextInt(max - min + 1); 481 } 482 483 /** 484 * Calculate random between 2 points, excluding a center 485 * ex: Util.rand(-12, -6, 6, 12) would not return -5 to 5 486 * @param min1 487 * @param max1 488 * @param min2 489 * @param max2 490 * @return 491 */ 492 public static int rand(int min1, int max1, int min2, int max2) { 493 return randBool() ? rand(min1, max1) : rand(min2, max2); 494 } 495 496 public static double rand(double min, double max) { 497 return RANDOM.nextDouble() * (max - min) + min; 498 } 499 500 public static boolean isNumber(String str) { 501 return ApacheCommonsLangUtil.isNumeric(str); 502 } 503 504 public static String intToRoman(int integer) { 505 if (integer == 1) { 506 return "I"; 507 } 508 if (integer == 2) { 509 return "II"; 510 } 511 if (integer == 3) { 512 return "III"; 513 } 514 if (integer == 4) { 515 return "IV"; 516 } 517 if (integer == 5) { 518 return "V"; 519 } 520 if (integer == 6) { 521 return "VI"; 522 } 523 if (integer == 7) { 524 return "VII"; 525 } 526 if (integer == 8) { 527 return "VIII"; 528 } 529 if (integer == 9) { 530 return "IX"; 531 } 532 if (integer == 10) { 533 return "X"; 534 } 535 return null; 536 } 537 538 public static boolean isInteger(String string) { 539 return ACFPatterns.INTEGER.matcher(string).matches(); 540 } 541 542 public static boolean isFloat(String string) { 543 try { 544 //noinspection ResultOfMethodCallIgnored 545 Float.parseFloat(string); 546 return true; 547 } catch (Exception e) { 548 return false; 549 } 550 } 551 552 public static boolean isDouble(String string) { 553 try { 554 //noinspection ResultOfMethodCallIgnored 555 Double.parseDouble(string); 556 return true; 557 } catch (Exception e) { 558 return false; 559 } 560 } 561 562 public static boolean isBetween(float num, double min, double max) { 563 return num >= min && num <= max; 564 } 565 566 @SuppressWarnings("SameParameterValue") 567 public static double precision(double x, int p) { 568 double pow = Math.pow(10, p); 569 return Math.round(x * pow) / pow; 570 } 571 572 public static void sneaky(Throwable t) { 573 //noinspection RedundantTypeArguments 574 throw ACFUtil.<RuntimeException>superSneaky( t ); 575 } 576 577 private static <T extends Throwable> T superSneaky(Throwable t) throws T { 578 //noinspection ConstantConditions,unchecked 579 throw (T) t; 580 } 581 582}