James Moger
2014-06-10 46bfccb0d57ba75d195be7afa54e37ba0d4321d1
commit | author | age
f13c4c 1 /*
JM 2  * Copyright 2011 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
87cc1e 16 package com.gitblit.utils;
JM 17
b34048 18 import java.io.ByteArrayOutputStream;
87cc1e 19 import java.io.UnsupportedEncodingException;
ae9e15 20 import java.nio.ByteBuffer;
JM 21 import java.nio.CharBuffer;
22 import java.nio.charset.CharacterCodingException;
23 import java.nio.charset.Charset;
24 import java.nio.charset.CharsetDecoder;
25 import java.nio.charset.IllegalCharsetNameException;
26 import java.nio.charset.UnsupportedCharsetException;
87cc1e 27 import java.security.MessageDigest;
JM 28 import java.security.NoSuchAlgorithmException;
f339f5 29 import java.util.ArrayList;
ae9e15 30 import java.util.Arrays;
0b9119 31 import java.util.Collection;
94750e 32 import java.util.Collections;
JM 33 import java.util.Comparator;
ae9e15 34 import java.util.LinkedHashSet;
87cc1e 35 import java.util.List;
ae9e15 36 import java.util.Set;
eb870f 37 import java.util.regex.Matcher;
JM 38 import java.util.regex.Pattern;
f339f5 39 import java.util.regex.PatternSyntaxException;
8c9a20 40
d9f687 41 /**
JM 42  * Utility class of string functions.
699e71 43  *
d9f687 44  * @author James Moger
699e71 45  *
d9f687 46  */
87cc1e 47 public class StringUtils {
8c9a20 48
JM 49     public static final String MD5_TYPE = "MD5:";
309c55 50
d5623a 51     public static final String COMBINED_MD5_TYPE = "CMD5:";
3e087a 52
d9f687 53     /**
JM 54      * Returns true if the string is null or empty.
699e71 55      *
d9f687 56      * @param value
JM 57      * @return true if string is null or empty
58      */
87cc1e 59     public static boolean isEmpty(String value) {
JM 60         return value == null || value.trim().length() == 0;
61     }
62
d9f687 63     /**
JM 64      * Replaces carriage returns and line feeds with html line breaks.
699e71 65      *
d9f687 66      * @param string
JM 67      * @return plain text with html line breaks
68      */
87cc1e 69     public static String breakLinesForHtml(String string) {
JM 70         return string.replace("\r\n", "<br/>").replace("\r", "<br/>").replace("\n", "<br/>");
71     }
72
d9f687 73     /**
JM 74      * Prepare text for html presentation. Replace sensitive characters with
75      * html entities.
699e71 76      *
d9f687 77      * @param inStr
JM 78      * @param changeSpace
79      * @return plain text escaped for html
80      */
87cc1e 81     public static String escapeForHtml(String inStr, boolean changeSpace) {
8a53c0 82         StringBuilder retStr = new StringBuilder();
87cc1e 83         int i = 0;
JM 84         while (i < inStr.length()) {
85             if (inStr.charAt(i) == '&') {
86                 retStr.append("&amp;");
87             } else if (inStr.charAt(i) == '<') {
88                 retStr.append("&lt;");
89             } else if (inStr.charAt(i) == '>') {
90                 retStr.append("&gt;");
91             } else if (inStr.charAt(i) == '\"') {
92                 retStr.append("&quot;");
93             } else if (changeSpace && inStr.charAt(i) == ' ') {
94                 retStr.append("&nbsp;");
95             } else if (changeSpace && inStr.charAt(i) == '\t') {
96                 retStr.append(" &nbsp; &nbsp;");
8c9a20 97             } else {
JM 98                 retStr.append(inStr.charAt(i));
99             }
100             i++;
101         }
102         return retStr.toString();
103     }
104
d9f687 105     /**
JM 106      * Decode html entities back into plain text characters.
699e71 107      *
d9f687 108      * @param inStr
JM 109      * @return returns plain text from html
110      */
85c2e6 111     public static String decodeFromHtml(String inStr) {
JM 112         return inStr.replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">")
113                 .replace("&quot;", "\"").replace("&nbsp;", " ");
114     }
115
d9f687 116     /**
JM 117      * Encodes a url parameter by escaping troublesome characters.
699e71 118      *
d9f687 119      * @param inStr
JM 120      * @return properly escaped url
121      */
8c9a20 122     public static String encodeURL(String inStr) {
8a53c0 123         StringBuilder retStr = new StringBuilder();
8c9a20 124         int i = 0;
JM 125         while (i < inStr.length()) {
126             if (inStr.charAt(i) == '/') {
127                 retStr.append("%2F");
128             } else if (inStr.charAt(i) == ' ') {
129                 retStr.append("%20");
16aa5a 130             } else if (inStr.charAt(i) == '&') {
JM 131                 retStr.append("%26");
46bfcc 132             } else if (inStr.charAt(i) == '+') {
JM 133                 retStr.append("%2B");
2a7306 134             } else {
87cc1e 135                 retStr.append(inStr.charAt(i));
2a7306 136             }
87cc1e 137             i++;
JM 138         }
139         return retStr.toString();
140     }
141
d9f687 142     /**
4bdd39 143      * Flatten the list of strings into a single string with the specified
JM 144      * separator.
145      *
146      * @param values
147      * @param separator
148      * @return flattened list
149      */
150     public static String flattenStrings(String[]  values, String separator) {
151         return flattenStrings(Arrays.asList(values), separator);
152     }
153
154     /**
d9f687 155      * Flatten the list of strings into a single string with a space separator.
699e71 156      *
d9f687 157      * @param values
JM 158      * @return flattened list
159      */
0b9119 160     public static String flattenStrings(Collection<String> values) {
8a2e9c 161         return flattenStrings(values, " ");
JM 162     }
163
d9f687 164     /**
JM 165      * Flatten the list of strings into a single string with the specified
166      * separator.
699e71 167      *
d9f687 168      * @param values
JM 169      * @param separator
170      * @return flattened list
171      */
0b9119 172     public static String flattenStrings(Collection<String> values, String separator) {
87cc1e 173         StringBuilder sb = new StringBuilder();
JM 174         for (String value : values) {
8a2e9c 175             sb.append(value).append(separator);
87cc1e 176         }
6e666f 177         if (sb.length() > 0) {
JM 178             // truncate trailing separator
179             sb.setLength(sb.length() - separator.length());
180         }
87cc1e 181         return sb.toString().trim();
JM 182     }
183
d9f687 184     /**
JM 185      * Returns a string trimmed to a maximum length with trailing ellipses. If
186      * the string length is shorter than the max, the original string is
187      * returned.
699e71 188      *
d9f687 189      * @param value
JM 190      * @param max
191      * @return trimmed string
192      */
87cc1e 193     public static String trimString(String value, int max) {
JM 194         if (value.length() <= max) {
195             return value;
196         }
197         return value.substring(0, max - 3) + "...";
198     }
199
d9f687 200     /**
JM 201      * Left pad a string with the specified character, if the string length is
202      * less than the specified length.
699e71 203      *
d9f687 204      * @param input
JM 205      * @param length
206      * @param pad
207      * @return left-padded string
208      */
87cc1e 209     public static String leftPad(String input, int length, char pad) {
JM 210         if (input.length() < length) {
211             StringBuilder sb = new StringBuilder();
212             for (int i = 0, len = length - input.length(); i < len; i++) {
213                 sb.append(pad);
214             }
215             sb.append(input);
216             return sb.toString();
217         }
218         return input;
219     }
220
d9f687 221     /**
JM 222      * Right pad a string with the specified character, if the string length is
223      * less then the specified length.
699e71 224      *
d9f687 225      * @param input
JM 226      * @param length
227      * @param pad
228      * @return right-padded string
229      */
87cc1e 230     public static String rightPad(String input, int length, char pad) {
JM 231         if (input.length() < length) {
232             StringBuilder sb = new StringBuilder();
233             sb.append(input);
234             for (int i = 0, len = length - input.length(); i < len; i++) {
235                 sb.append(pad);
236             }
237             return sb.toString();
238         }
239         return input;
240     }
241
d9f687 242     /**
JM 243      * Calculates the SHA1 of the string.
699e71 244      *
d9f687 245      * @param text
JM 246      * @return sha1 of the string
247      */
87cc1e 248     public static String getSHA1(String text) {
JM 249         try {
250             byte[] bytes = text.getBytes("iso-8859-1");
251             return getSHA1(bytes);
252         } catch (UnsupportedEncodingException u) {
253             throw new RuntimeException(u);
254         }
255     }
256
d9f687 257     /**
JM 258      * Calculates the SHA1 of the byte array.
699e71 259      *
d9f687 260      * @param bytes
JM 261      * @return sha1 of the byte array
262      */
87cc1e 263     public static String getSHA1(byte[] bytes) {
JM 264         try {
265             MessageDigest md = MessageDigest.getInstance("SHA-1");
266             md.update(bytes, 0, bytes.length);
8c9a20 267             byte[] digest = md.digest();
JM 268             return toHex(digest);
87cc1e 269         } catch (NoSuchAlgorithmException t) {
JM 270             throw new RuntimeException(t);
f97bf0 271         }
8c9a20 272     }
JM 273
d9f687 274     /**
JM 275      * Calculates the MD5 of the string.
699e71 276      *
d9f687 277      * @param string
JM 278      * @return md5 of the string
279      */
8c9a20 280     public static String getMD5(String string) {
JM 281         try {
4ad1eb 282             return getMD5(string.getBytes("iso-8859-1"));
5450d0 283         } catch (UnsupportedEncodingException u) {
JM 284             throw new RuntimeException(u);
4ad1eb 285         }
JM 286     }
699e71 287
4ad1eb 288     /**
JM 289      * Calculates the MD5 of the string.
699e71 290      *
4ad1eb 291      * @param string
JM 292      * @return md5 of the string
293      */
294     public static String getMD5(byte [] bytes) {
295         try {
296             MessageDigest md = MessageDigest.getInstance("MD5");
297             md.reset();
298             md.update(bytes);
299             byte[] digest = md.digest();
300             return toHex(digest);
5450d0 301         } catch (NoSuchAlgorithmException t) {
JM 302             throw new RuntimeException(t);
8c9a20 303         }
JM 304     }
305
d9f687 306     /**
JM 307      * Returns the hex representation of the byte array.
699e71 308      *
d9f687 309      * @param bytes
JM 310      * @return byte array as hex string
311      */
b2fec2 312     public static String toHex(byte[] bytes) {
8c9a20 313         StringBuilder sb = new StringBuilder(bytes.length * 2);
JM 314         for (int i = 0; i < bytes.length; i++) {
699e71 315             if ((bytes[i] & 0xff) < 0x10) {
8c9a20 316                 sb.append('0');
JM 317             }
699e71 318             sb.append(Long.toString(bytes[i] & 0xff, 16));
8c9a20 319         }
JM 320         return sb.toString();
321     }
85c2e6 322
d9f687 323     /**
JM 324      * Returns the root path of the specified path. Returns a blank string if
325      * there is no root path.
699e71 326      *
d9f687 327      * @param path
JM 328      * @return root path or blank
329      */
00afd7 330     public static String getRootPath(String path) {
JM 331         if (path.indexOf('/') > -1) {
ec97f7 332             return path.substring(0, path.lastIndexOf('/'));
00afd7 333         }
JM 334         return "";
335     }
008322 336
d9f687 337     /**
JM 338      * Returns the path remainder after subtracting the basePath from the
339      * fullPath.
699e71 340      *
d9f687 341      * @param basePath
JM 342      * @param fullPath
343      * @return the relative path
344      */
008322 345     public static String getRelativePath(String basePath, String fullPath) {
ffbd6e 346         String bp = basePath.replace('\\', '/').toLowerCase();
JM 347         String fp = fullPath.replace('\\', '/').toLowerCase();
348         if (fp.startsWith(bp)) {
349             String relativePath = fullPath.substring(basePath.length()).replace('\\', '/');
daaf89 350             if (relativePath.length() > 0 && relativePath.charAt(0) == '/') {
ffbd6e 351                 relativePath = relativePath.substring(1);
JM 352             }
353             return relativePath;
a125cf 354         }
ffbd6e 355         return fullPath;
a125cf 356     }
8c9a20 357
d9f687 358     /**
JM 359      * Splits the space-separated string into a list of strings.
699e71 360      *
d9f687 361      * @param value
JM 362      * @return list of strings
363      */
f339f5 364     public static List<String> getStringsFromValue(String value) {
JM 365         return getStringsFromValue(value, " ");
366     }
8c9a20 367
d9f687 368     /**
JM 369      * Splits the string into a list of string by the specified separator.
699e71 370      *
d9f687 371      * @param value
JM 372      * @param separator
373      * @return list of strings
374      */
f339f5 375     public static List<String> getStringsFromValue(String value, String separator) {
3d699c 376         List<String> strings = new ArrayList<String>();
U 377         try {
699e71 378             String[] chunks = value.split(separator + "(?=([^\"]*\"[^\"]*\")*[^\"]*$)");
3d699c 379             for (String chunk : chunks) {
U 380                 chunk = chunk.trim();
381                 if (chunk.length() > 0) {
382                     if (chunk.charAt(0) == '"' && chunk.charAt(chunk.length() - 1) == '"') {
383                         // strip double quotes
384                         chunk = chunk.substring(1, chunk.length() - 1).trim();
385                     }
386                     strings.add(chunk);
387                 }
388             }
389         } catch (PatternSyntaxException e) {
390             throw new RuntimeException(e);
391         }
392         return strings;
393     }
831469 394
JM 395     /**
396      * Validates that a name is composed of letters, digits, or limited other
397      * characters.
699e71 398      *
831469 399      * @param name
JM 400      * @return the first invalid character found or null if string is acceptable
401      */
402     public static Character findInvalidCharacter(String name) {
46bfcc 403         char[] validChars = { '/', '.', '_', '-', '~', '+' };
831469 404         for (char c : name.toCharArray()) {
JM 405             if (!Character.isLetterOrDigit(c)) {
406                 boolean ok = false;
407                 for (char vc : validChars) {
408                     ok |= c == vc;
409                 }
410                 if (!ok) {
411                     return c;
412                 }
413             }
414         }
415         return null;
416     }
417
418     /**
419      * Simple fuzzy string comparison. This is a case-insensitive check. A
420      * single wildcard * value is supported.
699e71 421      *
831469 422      * @param value
JM 423      * @param pattern
424      * @return true if the value matches the pattern
425      */
426     public static boolean fuzzyMatch(String value, String pattern) {
427         if (value.equalsIgnoreCase(pattern)) {
428             return true;
429         }
430         if (pattern.contains("*")) {
431             boolean prefixMatches = false;
432             boolean suffixMatches = false;
433
434             int wildcard = pattern.indexOf('*');
435             String prefix = pattern.substring(0, wildcard).toLowerCase();
436             prefixMatches = value.toLowerCase().startsWith(prefix);
437
438             if (pattern.length() > (wildcard + 1)) {
439                 String suffix = pattern.substring(wildcard + 1).toLowerCase();
440                 suffixMatches = value.toLowerCase().endsWith(suffix);
441                 return prefixMatches && suffixMatches;
442             }
443             return prefixMatches || suffixMatches;
444         }
445         return false;
446     }
94750e 447
JM 448     /**
449      * Compare two repository names for proper group sorting.
699e71 450      *
94750e 451      * @param r1
JM 452      * @param r2
453      * @return
454      */
455     public static int compareRepositoryNames(String r1, String r2) {
456         // sort root repositories first, alphabetically
457         // then sort grouped repositories, alphabetically
62f435 458         r1 = r1.toLowerCase();
JM 459         r2 = r2.toLowerCase();
94750e 460         int s1 = r1.indexOf('/');
JM 461         int s2 = r2.indexOf('/');
462         if (s1 == -1 && s2 == -1) {
463             // neither grouped
464             return r1.compareTo(r2);
465         } else if (s1 > -1 && s2 > -1) {
466             // both grouped
467             return r1.compareTo(r2);
468         } else if (s1 == -1) {
469             return -1;
470         } else if (s2 == -1) {
471             return 1;
472         }
473         return 0;
474     }
475
476     /**
477      * Sort grouped repository names.
699e71 478      *
94750e 479      * @param list
JM 480      */
481     public static void sortRepositorynames(List<String> list) {
482         Collections.sort(list, new Comparator<String>() {
483             @Override
484             public int compare(String o1, String o2) {
485                 return compareRepositoryNames(o1, o2);
486             }
487         });
488     }
309c55 489
JM 490     public static String getColor(String value) {
491         int cs = 0;
492         for (char c : getMD5(value.toLowerCase()).toCharArray()) {
493             cs += c;
494         }
699e71 495         int n = (cs % 360);
309c55 496         float hue = ((float) n) / 360;
JM 497         return hsvToRgb(hue, 0.90f, 0.65f);
498     }
499
500     public static String hsvToRgb(float hue, float saturation, float value) {
501         int h = (int) (hue * 6);
502         float f = hue * 6 - h;
503         float p = value * (1 - saturation);
504         float q = value * (1 - f * saturation);
505         float t = value * (1 - (1 - f) * saturation);
506
507         switch (h) {
508         case 0:
509             return rgbToString(value, t, p);
510         case 1:
511             return rgbToString(q, value, p);
512         case 2:
513             return rgbToString(p, value, t);
514         case 3:
515             return rgbToString(p, q, value);
516         case 4:
517             return rgbToString(t, p, value);
518         case 5:
519             return rgbToString(value, p, q);
520         default:
521             throw new RuntimeException(
522                     "Something went wrong when converting from HSV to RGB. Input was " + hue + ", "
523                             + saturation + ", " + value);
524         }
525     }
526
527     public static String rgbToString(float r, float g, float b) {
528         String rs = Integer.toHexString((int) (r * 256));
529         String gs = Integer.toHexString((int) (g * 256));
530         String bs = Integer.toHexString((int) (b * 256));
531         return "#" + rs + gs + bs;
532     }
699e71 533
12c31e 534     /**
JM 535      * Strips a trailing ".git" from the value.
699e71 536      *
12c31e 537      * @param value
JM 538      * @return a stripped value or the original value if .git is not found
539      */
6c6fbf 540     public static String stripDotGit(String value) {
JM 541         if (value.toLowerCase().endsWith(".git")) {
542             return value.substring(0, value.length() - 4);
543         }
544         return value;
545     }
699e71 546
12c31e 547     /**
JM 548      * Count the number of lines in a string.
699e71 549      *
12c31e 550      * @param value
JM 551      * @return the line count
552      */
672296 553     public static int countLines(String value) {
JM 554         if (isEmpty(value)) {
555             return 0;
556         }
557         return value.split("\n").length;
558     }
699e71 559
12c31e 560     /**
JM 561      * Returns the file extension of a path.
699e71 562      *
12c31e 563      * @param path
JM 564      * @return a blank string or a file extension
565      */
566     public static String getFileExtension(String path) {
567         int lastDot = path.lastIndexOf('.');
568         if (lastDot > -1) {
569             return path.substring(lastDot + 1);
570         }
571         return "";
572     }
699e71 573
f3b625 574     /**
dc7c2f 575      * Returns the file extension of a path.
JM 576      *
577      * @param path
578      * @return a blank string or a file extension
579      */
580     public static String stripFileExtension(String path) {
581         int lastDot = path.lastIndexOf('.');
582         if (lastDot > -1) {
583             return path.substring(0, lastDot);
584         }
585         return path;
586     }
587
588     /**
f3b625 589      * Replace all occurences of a substring within a string with
JC 590      * another string.
699e71 591      *
f3b625 592      * From Spring StringUtils.
699e71 593      *
f3b625 594      * @param inString String to examine
JC 595      * @param oldPattern String to replace
596      * @param newPattern String to insert
597      * @return a String with the replacements
598      */
599     public static String replace(String inString, String oldPattern, String newPattern) {
600         StringBuilder sb = new StringBuilder();
601         int pos = 0; // our position in the old string
602         int index = inString.indexOf(oldPattern);
603         // the index of an occurrence we've found, or -1
604         int patLen = oldPattern.length();
605         while (index >= 0) {
606             sb.append(inString.substring(pos, index));
607             sb.append(newPattern);
608             pos = index + patLen;
609             index = inString.indexOf(oldPattern, pos);
610         }
611         sb.append(inString.substring(pos));
612         // remember to append any characters to the right of a match
613         return sb.toString();
614     }
699e71 615
ae9e15 616     /**
JM 617      * Decodes a string by trying several charsets until one does not throw a
618      * coding exception.  Last resort is to interpret as UTF-8 with illegal
619      * character substitution.
699e71 620      *
ae9e15 621      * @param content
JM 622      * @param charsets optional
623      * @return a string
624      */
625     public static String decodeString(byte [] content, String... charsets) {
626         Set<String> sets = new LinkedHashSet<String>();
627         if (!ArrayUtils.isEmpty(charsets)) {
628             sets.addAll(Arrays.asList(charsets));
629         }
086c04 630         String value = null;
ae9e15 631         sets.addAll(Arrays.asList("UTF-8", "ISO-8859-1", Charset.defaultCharset().name()));
JM 632         for (String charset : sets) {
633             try {
634                 Charset cs = Charset.forName(charset);
635                 CharsetDecoder decoder = cs.newDecoder();
636                 CharBuffer buffer = decoder.decode(ByteBuffer.wrap(content));
086c04 637                 value = buffer.toString();
JM 638                 break;
ae9e15 639             } catch (CharacterCodingException e) {
JM 640                 // ignore and advance to the next charset
641             } catch (IllegalCharsetNameException e) {
642                 // ignore illegal charset names
643             } catch (UnsupportedCharsetException e) {
644                 // ignore unsupported charsets
645             }
646         }
872462 647         if (value != null && value.startsWith("\uFEFF")) {
086c04 648             // strip UTF-8 BOM
JM 649             return value.substring(1);
650         }
651         return value;
ae9e15 652     }
699e71 653
eb870f 654     /**
JM 655      * Attempt to extract a repository name from a given url using regular
656      * expressions.  If no match is made, then return whatever trails after
657      * the final / character.
699e71 658      *
eb870f 659      * @param regexUrls
JM 660      * @return a repository path
661      */
662     public static String extractRepositoryPath(String url, String... urlpatterns) {
663         for (String urlPattern : urlpatterns) {
664             Pattern p = Pattern.compile(urlPattern);
665             Matcher m = p.matcher(url);
666             while (m.find()) {
667                 String repositoryPath = m.group(1);
668                 return repositoryPath;
669             }
670         }
671         // last resort
672         if (url.lastIndexOf('/') > -1) {
673             return url.substring(url.lastIndexOf('/') + 1);
674         }
675         return url;
676     }
699e71 677
b34048 678     /**
JM 679      * Converts a string with \nnn sequences into a UTF-8 encoded string.
680      * @param input
681      * @return
682      */
683     public static String convertOctal(String input) {
684         try {
685             ByteArrayOutputStream bytes = new ByteArrayOutputStream();
686             Pattern p = Pattern.compile("(\\\\\\d{3})");
687             Matcher m = p.matcher(input);
688             int i = 0;
689             while (m.find()) {
690                 bytes.write(input.substring(i, m.start()).getBytes("UTF-8"));
691                 // replace octal encoded value
692                 // strip leading \ character
693                 String oct = m.group().substring(1);
694                 bytes.write(Integer.parseInt(oct, 8));
699e71 695                 i = m.end();
b34048 696             }
JM 697             if (bytes.size() == 0) {
698                 // no octal matches
699                 return input;
700             } else {
701                 if (i < input.length()) {
702                     // add remainder of string
703                     bytes.write(input.substring(i).getBytes("UTF-8"));
704                 }
705             }
706             return bytes.toString("UTF-8");
707         } catch (Exception e) {
708             e.printStackTrace();
709         }
710         return input;
711     }
699e71 712
1e1b85 713     /**
JM 714      * Returns the first path element of a path string.  If no path separator is
699e71 715      * found in the path, an empty string is returned.
JM 716      *
1e1b85 717      * @param path
JM 718      * @return the first element in the path
719      */
720     public static String getFirstPathElement(String path) {
721         if (path.indexOf('/') > -1) {
722             return path.substring(0, path.indexOf('/')).trim();
723         }
724         return "";
725     }
699e71 726
1e1b85 727     /**
JM 728      * Returns the last path element of a path string
699e71 729      *
1e1b85 730      * @param path
JM 731      * @return the last element in the path
732      */
733     public static String getLastPathElement(String path) {
734         if (path.indexOf('/') > -1) {
735             return path.substring(path.lastIndexOf('/') + 1);
736         }
737         return path;
738     }
699e71 739
e5aaa5 740     /**
JM 741      * Variation of String.matches() which disregards case issues.
699e71 742      *
e5aaa5 743      * @param regex
JM 744      * @param input
745      * @return true if the pattern matches
746      */
747     public static boolean matchesIgnoreCase(String input, String regex) {
748         Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
749         Matcher m = p.matcher(input);
750         return m.matches();
751     }
699e71 752
ac7e9a 753     /**
JM 754      * Removes new line and carriage return chars from a string.
755      * If input value is null an empty string is returned.
699e71 756      *
ac7e9a 757      * @param input
JM 758      * @return a sanitized or empty string
759      */
760     public static String removeNewlines(String input) {
761         if (input == null) {
762             return "";
763         }
764         return input.replace('\n',' ').replace('\r',  ' ').trim();
765     }
8f1c9f 766
JM 767
768     /**
769      * Encode the username for user in an url.
770      *
771      * @param name
772      * @return the encoded name
773      */
774     public static String encodeUsername(String name) {
775         return name.replace("@", "%40").replace(" ", "%20").replace("\\", "%5C");
776     }
777
778     /**
779      * Decode a username from an encoded url.
780      *
781      * @param name
782      * @return the decoded name
783      */
784     public static String decodeUsername(String name) {
785         return name.replace("%40", "@").replace("%20", " ").replace("%5C", "\\");
786     }
309c55 787 }