001    /*--------------------------------------------------------------------------+
002    $Id: StringUtils.java 29159 2010-07-08 16:45:10Z heineman $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed under the Apache License, Version 2.0 (the "License");          |
007    | you may not use this file except in compliance with the License.         |
008    | You may obtain a copy of the License at                                  |
009    |                                                                          |
010    |    http://www.apache.org/licenses/LICENSE-2.0                            |
011    |                                                                          |
012    | Unless required by applicable law or agreed to in writing, software      |
013    | distributed under the License is distributed on an "AS IS" BASIS,        |
014    | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015    | See the License for the specific language governing permissions and      |
016    | limitations under the License.                                           |
017    +--------------------------------------------------------------------------*/
018    package edu.tum.cs.commons.string;
019    
020    import java.io.PrintWriter;
021    import java.io.StringWriter;
022    import java.text.NumberFormat;
023    import java.util.ArrayList;
024    import java.util.Arrays;
025    import java.util.HashMap;
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.Map;
029    import java.util.Random;
030    import java.util.Set;
031    import java.util.regex.Matcher;
032    
033    import edu.tum.cs.commons.assertion.CCSMAssert;
034    import edu.tum.cs.commons.filesystem.FileSystemUtils;
035    
036    /**
037     * A utility class providing some advanced string functionality.
038     * 
039     * @author Daniel Ratiu, Florian Deissenboeck, Tilman Seifert
040     * @author $Author: heineman $
041     * @version $Rev: 29159 $
042     * @levd.rating GREEN Hash: 3C85A252901D3932299CFD62BF0FA9B0
043     */
044    public class StringUtils {
045    
046            /** Line break. */
047            public static final String CR = System.getProperty("line.separator");
048    
049            /** The emtpy string. */
050            public static final String EMPTY_STRING = "";
051    
052            /** A symbol representing the line terminator. */
053            public static final String LINE_TERMINATOR_SYMBOL = "\\n";
054    
055            /** A space. */
056            public static final String SPACE = " ";
057    
058            /** A space character. */
059            public static final char SPACE_CHAR = ' ';
060    
061            /** A tab character. */
062            public static final String TAB = "\t";
063    
064            /** Two spaces. */
065            public static final String TWO_SPACES = "  ";
066    
067            /** Number formatter. */
068            private static NumberFormat numberFormat = NumberFormat.getInstance();
069    
070            /** Number formatter for percentages. */
071            private static NumberFormat percentageFormat = NumberFormat
072                            .getPercentInstance();
073    
074            /** Random numer generator. */
075            private static final Random random = new Random();
076    
077            /**
078             * Adds random line breaks to a string.
079             * 
080             * @param text
081             *            the original string.
082             * @param count
083             *            the number of line breaks to add.
084             * @return the string with line breaks.
085             */
086            public static String addRandomLineBreaks(String text, int count) {
087                    StringBuilder result = new StringBuilder(text);
088                    int len = text.length();
089                    for (int i = 0; i < count; i++) {
090                            int pos = random.nextInt(len);
091                            result.insert(pos, CR);
092                    }
093                    return result.toString();
094            }
095    
096            /**
097             * Create a sting of the given length and center the given string within it.
098             * Left and right areas are filled by the character provided.
099             * 
100             * @param string
101             *            The input string.
102             * @param length
103             *            The length of the string to be returned.
104             * @param c
105             *            The character to surround the input string with.
106             * @return the new string or, if the string is longer than the specified
107             *         length, the original string.
108             * @see #flushLeft(String, int, char)
109             * @see #flushRight(String, int, char)
110             */
111            public static String center(String string, int length, char c) {
112                    if (string.length() >= length) {
113                            return string;
114                    }
115                    int strLen = string.length();
116                    int fillLen = (length - strLen) / 2;
117                    String leftFiller = fillString(fillLen, c);
118    
119                    if ((length - strLen) % 2 != 0) {
120                            fillLen++;
121                    }
122    
123                    String rightFiller = fillString(fillLen, c);
124    
125                    return leftFiller + string + rightFiller;
126            }
127    
128            /**
129             * Concatenates all elements of an iterable using the
130             * <code>toString()</code>-method.
131             * 
132             * @param iterable
133             *            the iterable
134             * @return a concatenation, separated by spaces
135             */
136            public static String concat(Iterable<?> iterable) {
137                    return concat(iterable, SPACE);
138            }
139    
140            /**
141             * Concatenates all elements of an iterable using the
142             * <code>toString()</code>-method, separating them with the given
143             * <code>separator</code>.
144             * 
145             * @param iterable
146             *            the iterable containing the strings
147             * @param separator
148             *            the separator to place between the strings, may be
149             *            <code>null</code>
150             * @return a concatenation of the string in the array or <code>null</code>
151             *         if array was <code>null</code>. If array is of length 0 the empty
152             *         string is returned.
153             */
154            public static String concat(Iterable<?> iterable, String separator) {
155                    if (iterable == null) {
156                            return null;
157                    }
158    
159                    Iterator<?> iterator = iterable.iterator();
160    
161                    if (!iterator.hasNext()) {
162                            return EMPTY_STRING;
163                    }
164    
165                    if (separator == null) {
166                            separator = EMPTY_STRING;
167                    }
168    
169                    StringBuilder builder = new StringBuilder();
170    
171                    while (iterator.hasNext()) {
172                            builder.append(iterator.next());
173                            if (iterator.hasNext()) {
174                                    builder.append(separator);
175                            }
176                    }
177    
178                    return builder.toString();
179            }
180    
181            /**
182             * Concatenates all elements of an array using the <code>toString()</code>
183             * -method.
184             * 
185             * @param array
186             *            the array containing the strings
187             * @return a concatenation of the string separated by spaces
188             */
189            public static String concat(Object[] array) {
190                    return concat(array, SPACE);
191            }
192    
193            /**
194             * Concatenates all elements of an array using the <code>toString()</code>
195             * -method, separating them with the given <code>separator</code>.
196             * 
197             * @param array
198             *            the array
199             * @param separator
200             *            the separator to place between the strings, may be
201             *            <code>null</code>
202             * @return a concatenation of the string in the array or <code>null</code>
203             *         if array was <code>null</code>. If array is of length 0 the empty
204             *         string is returned.
205             */
206            public static String concat(Object[] array, String separator) {
207                    if (array == null) {
208                            return null;
209                    }
210                    return concat(Arrays.asList(array), separator);
211            }
212    
213            /**
214             * Concatenate two string arrays.
215             * 
216             * @param array1
217             * @param array2
218             * @return the concatenation
219             */
220            public static String[] concat(String[] array1, String[] array2) {
221                    String[] result = new String[array1.length + array2.length];
222                    System.arraycopy(array1, 0, result, 0, array1.length);
223                    System.arraycopy(array2, 0, result, array1.length, array2.length);
224                    return result;
225            }
226    
227            /**
228             * Build a string with a specified length from a character.
229             * 
230             * @param length
231             *            The length of the string.
232             * @param c
233             *            The character.
234             * @return The string.
235             */
236            public static String fillString(int length, char c) {
237                    char[] characters = new char[length];
238    
239                    Arrays.fill(characters, c);
240    
241                    return new String(characters);
242            }
243    
244            /**
245             * Create a sting of the given length starting with the provided string.
246             * Remaining characters are filled with the provided character.
247             * 
248             * @param string
249             *            The input string.
250             * @param length
251             *            The length of the string to be returned.
252             * @param c
253             *            The character to fill the string.
254             * @return the new string or, if the string is longer than the specified
255             *         length, the original string.
256             * @see #flushRight(String, int, char)
257             * @see #center(String, int, char)
258             */
259            public static String flushLeft(String string, int length, char c) {
260                    int gap = length - string.length();
261                    if (gap <= 0) {
262                            return string;
263                    }
264                    return string + StringUtils.fillString(gap, c);
265            }
266    
267            /**
268             * Create a sting of the given length ending with the provided string.
269             * Remaining characters are filled with the provided character.
270             * 
271             * @param string
272             *            The input string.
273             * @param length
274             *            The length of the string to be returned.
275             * @param c
276             *            The character to fill the string.
277             * @return the new string or, if the string is longer than the specified
278             *         length, the original string.
279             * @see #flushLeft(String, int, char)
280             * @see #center(String, int, char)
281             */
282            public static String flushRight(String string, int length, char c) {
283                    int gap = length - string.length();
284                    if (gap <= 0) {
285                            return string;
286                    }
287                    return StringUtils.fillString(gap, c) + string;
288            }
289    
290            /**
291             * Format number
292             */
293            public static String format(Number number) {
294                    return numberFormat.format(number);
295            }
296    
297            /**
298             * Format as percentage.
299             */
300            public static String formatAsPercentage(Number number) {
301                    return percentageFormat.format(number);
302            }
303    
304            /** Returns the first line of a string. */
305            public static String getFirstLine(String string) {
306                    LineSplitter lineSplitter = new LineSplitter();
307                    lineSplitter.setContent(string);
308                    return lineSplitter.getNextLine();
309            }
310    
311            /**
312             * Returns the first n part of a string, separated by the given character.
313             * 
314             * E.g., getStringParts("edu.tum.cs", 2, '.') gives: "edu.tum".
315             * 
316             * @param string
317             *            the base string
318             * @param partNumber
319             *            number of parts
320             * @param separator
321             *            the separator character
322             */
323            public static String getFirstParts(String string, int partNumber,
324                            char separator) {
325    
326                    if (partNumber < 0 || string == null) {
327                            return string;
328                    }
329    
330                    int idx = 0;
331    
332                    for (int i = 0; i < partNumber; i++) {
333                            idx = string.indexOf(separator, idx + 1);
334                            if (idx == -1) {
335                                    return string;
336                            }
337                    }
338    
339                    return string.substring(0, idx);
340            }
341    
342            /**
343             * Splits a key-value string and stores it in a hash map. The string must
344             * have the following format:
345             * <p>
346             * <code>key=value[,key=value]*</code>
347             * </p>
348             * If the string is <code>null</code> <code>null</code> is returned.
349             * 
350             * @param keyValueString
351             *            with format described above
352             * @return a hash map containing the key-values-pairs.
353             */
354            public static HashMap<String, String> getKeyValuePairs(String keyValueString) {
355                    if (keyValueString == null) {
356                            return null;
357                    }
358                    HashMap<String, String> result = new HashMap<String, String>();
359                    if (keyValueString.trim().equals(EMPTY_STRING)) {
360                            return result;
361                    }
362    
363                    String[] pairs = keyValueString.split(",");
364    
365                    for (String pair : pairs) {
366                            int index = pair.indexOf('=');
367                            if (index < 0) {
368                                    result.put(pair.trim(), null);
369                            } else {
370                                    String key = pair.substring(0, index).trim();
371                                    String value = pair.substring(index + 1).trim();
372                                    result.put(key, value);
373                            }
374                    }
375                    return result;
376            }
377    
378            /**
379             * Return the last part of a String which is separated by the given
380             * character.
381             * 
382             * E.g., getLastPart("edu.tum.cs.commons.string.StringUtils", '.') gives
383             * "StringUtils".
384             * 
385             * @param string
386             *            the String
387             * @param separator
388             *            separation character
389             * @return the last part of the String, or the original String if the
390             *         separation character is not found.
391             */
392            public static String getLastPart(String string, char separator) {
393                    int idx = string.lastIndexOf(separator);
394                    if (idx >= 0) {
395                            return string.substring(idx + 1);
396                    }
397                    return string;
398    
399            }
400    
401            /**
402             * Searches the elements of a string array for a string. Strings are
403             * trimmed.
404             * 
405             * @param array
406             *            the array to search
407             * @param string
408             *            the search string
409             * @return the index of the element where the string was found or
410             *         <code>-1</code> if string wasn't found.
411             */
412            public static int indexOf(String[] array, String string) {
413                    for (int i = 0; i < array.length; i++) {
414                            if (array[i].trim().equals(string.trim())) {
415                                    return i;
416                            }
417                    }
418                    return -1;
419            }
420    
421            /**
422             * Checks if a string is empty (after trimming).
423             * 
424             * @param text
425             *            the string to check.
426             * @return <code>true</code> if string is empty or <code>null</code>,
427             *         <code>false</code> otherwise.
428             */
429            public static boolean isEmpty(String text) {
430                    if (text == null) {
431                            return true;
432                    }
433                    return "".equals(text.trim());
434            }
435    
436            /**
437             * Generates a random string with a certain length. The string consists of
438             * characters with ASCII code between 33 and 126.
439             * 
440             * @param length
441             *            the length of the random string
442             * @return the random string
443             */
444            public static String randomString(int length) {
445                    return randomString(length, random);
446            }
447    
448            /**
449             * Performs the actal creation of the random string using the given
450             * randomizer.
451             */
452            private static String randomString(int length, Random random) {
453                    char[] characters = new char[length];
454                    for (int i = 0; i < length; i++) {
455                            characters[i] = (char) (random.nextInt(93) + 33);
456                    }
457                    return new String(characters);
458            }
459    
460            /**
461             * Generates an array of random strings.
462             * 
463             * @param length
464             *            number of strings
465             * @param stringLength
466             *            length of each string
467             * @return the randomly generated array.
468             */
469            public static String[] randomStringArray(int length, int stringLength) {
470                    String[] array = new String[length];
471                    for (int i = 0; i < length; i++) {
472                            array[i] = randomString(stringLength);
473                    }
474                    return array;
475            }
476    
477            /**
478             * Generates a pseudo random string with a certain length in a
479             * deterministic, reproducable fashion.
480             * 
481             * 
482             * @param length
483             *            the length of the pseudo-random string
484             * @param seed
485             *            seed value for the random number generator used for the
486             *            generation of the pseudo-random string. If the same seed value
487             *            is used, the same pseudo-random string is generated.
488             */
489            public static String generateString(int length, int seed) {
490                    Random seededRandomizer = new Random(seed);
491                    return randomString(length, seededRandomizer);
492            }
493    
494            /**
495             * Generates an array of pseudo-random strings in a deterministic,
496             * reproducable fashion.
497             * 
498             * @param length
499             *            number of strings
500             * @param stringLength
501             *            length of each string
502             * @param seed
503             *            seed value for the random number generator used for the
504             *            generation of the pseudo-random string. If the same seed value
505             *            is used, the same pseudo-random string array is generated.
506             * @return the randomly generated array.
507             */
508            public static String[] generateStringArray(int length, int stringLength,
509                            int seed) {
510                    String[] array = new String[length];
511                    for (int i = 0; i < length; i++) {
512                            array[i] = generateString(stringLength, seed + i);
513                    }
514                    return array;
515            }
516    
517            /**
518             * Returns the beginning of a String, cutting off the last part which is
519             * separated by the given character.
520             * 
521             * E.g., removeLastPart("edu.tum.cs.commons.string.StringUtils", '.') gives
522             * "edu.tum.cs.commons.string".
523             * 
524             * @param string
525             *            the String
526             * @param separator
527             *            separation character
528             * @return the String without the last part, or the original string if the
529             *         separation character is not found.
530             */
531            public static String removeLastPart(String string, char separator) {
532                    int idx = string.lastIndexOf(separator);
533                    if (idx == -1) {
534                            return string;
535                    }
536    
537                    return string.substring(0, idx);
538            }
539    
540            /**
541             * Replace all linebreaks in string with {@link #LINE_TERMINATOR_SYMBOL}.
542             * 
543             * @return a string without linebreaks
544             */
545            public static String replaceLineBreaks(String string) {
546                    return replaceLineBreaks(string, LINE_TERMINATOR_SYMBOL);
547            }
548    
549            /**
550             * Replace all linebreaks in string with the platform-specific line
551             * separator.
552             * 
553             * @return a string without linebreaks
554             */
555            public static String normalizeLineBreaks(String string) {
556                    return replaceLineBreaks(string, CR);
557            }
558    
559            /**
560             * Replace all linebreaks in string by a specified symbol.
561             * 
562             * @return a string with line breaks replaced.
563             */
564            public static String replaceLineBreaks(String string, String symbol) {
565                    symbol = symbol.replaceAll("\\\\", "\\\\\\\\");
566                    symbol = symbol.replaceAll("\\$", "\\\\\\$");
567                    return string.replaceAll("\\r\\n|\\n\\r|\\r|\\n", symbol);
568            }
569    
570            /**
571             * Split string in lines. For the the empty string and <code>null</code> an
572             * array of length zero is returned.
573             * 
574             * @see #splitLinesAsList(String)
575             */
576            public static String[] splitLines(String content) {
577                    List<String> lineList = splitLinesAsList(content);
578                    String[] result = new String[lineList.size()];
579                    lineList.toArray(result);
580                    return result;
581            }
582    
583            /**
584             * Split string in lines. For the the empty string and <code>null</code> an
585             * empty list is returned.
586             * 
587             * @see #splitLines(String)
588             */
589            public static List<String> splitLinesAsList(String content) {
590                    ArrayList<String> result = new ArrayList<String>();
591                    LineSplitter lineSplitter = new LineSplitter();
592    
593                    lineSplitter.setContent(content);
594    
595                    String line;
596                    while ((line = lineSplitter.getNextLine()) != null) {
597                            result.add(line);
598                    }
599                    return result;
600            }
601    
602            /**
603             * Remove prefix from a string.
604             * 
605             * @param prefix
606             *            the prefix
607             * @param string
608             *            the string
609             * @return the string without the prefix or the original string if it does
610             *         not start with the prefix.
611             */
612            public static String stripPrefix(String prefix, String string) {
613                    if (string.startsWith(prefix)) {
614                            return string.substring(prefix.length());
615                    }
616                    return string;
617            }
618    
619            /**
620             * Remove suffix from a string.
621             * 
622             * @param suffix
623             *            the suffix
624             * @param string
625             *            the string
626             * @return the string without the suffix or the original string if it does
627             *         not end with the suffix.
628             */
629            public static String stripSuffix(String suffix, String string) {
630                    if (string.endsWith(suffix)) {
631                            return string.substring(0, string.length() - suffix.length());
632                    }
633                    return string;
634            }
635    
636            /** Strips all digits from the given String. */
637            public static String stripDigits(String string) {
638                    return string.replaceAll("[0-9]", EMPTY_STRING);
639            }
640    
641            /**
642             * Create string representation of a map.
643             */
644            public static String toString(Map<?, ?> map) {
645                    return toString(map, EMPTY_STRING);
646            }
647    
648            /**
649             * Create string representation of a map.
650             * 
651             * @param map
652             *            the map
653             * @param indent
654             *            a line indent
655             */
656            public static String toString(Map<?, ?> map, String indent) {
657                    StringBuilder result = new StringBuilder();
658                    Iterator<?> keyIterator = map.keySet().iterator();
659    
660                    while (keyIterator.hasNext()) {
661                            result.append(indent);
662                            Object key = keyIterator.next();
663                            result.append(key);
664                            result.append(" = ");
665                            result.append(map.get(key));
666                            if (keyIterator.hasNext()) {
667                                    result.append(CR);
668                            }
669                    }
670    
671                    return result.toString();
672            }
673    
674            /**
675             * Convert stack trace of a {@link Throwable} to a string.
676             */
677            public static String obtainStackTrace(Throwable throwable) {
678                    StringWriter result = new StringWriter();
679                    PrintWriter printWriter = new PrintWriter(result);
680                    throwable.printStackTrace(printWriter);
681                    return result.toString();
682            }
683    
684            /**
685             * Test if a string starts with one of the provided prefixes. Returns
686             * <code>false</code> if the list of prefixes is empty. This should only be
687             * used for short lists of prefixes.
688             */
689            public static boolean startsWithOneOf(String string, String... prefixes) {
690                    for (String prefix : prefixes) {
691                            if (string.startsWith(prefix)) {
692                                    return true;
693                            }
694                    }
695                    return false;
696            }
697    
698            /**
699             * Test if a string contains of the provided strings. Returns
700             * <code>false</code> if the list of strings is empty. This should only be
701             * used for short lists of strings.
702             */
703            public static boolean containsOneOf(String text, String... strings) {
704                    for (String prefix : strings) {
705                            if (text.contains(prefix)) {
706                                    return true;
707                            }
708                    }
709                    return false;
710            }
711    
712            /**
713             * Test if a string ends with one of the provided suffixes. Returns
714             * <code>false</code> if the list of prefixes is empty. This should only be
715             * used for short lists of suffixes.
716             */
717            public static boolean endsWithOneOf(String string, String... suffixes) {
718                    for (String suffix : suffixes) {
719                            if (string.endsWith(suffix)) {
720                                    return true;
721                            }
722                    }
723                    return false;
724            }
725    
726            /**
727             * Prefix all lines of a string. This also replaces line breaks with the
728             * platform-specific line-separator.
729             * 
730             * @param string
731             *            the string to prefix
732             * @param prefix
733             *            the prefix to add
734             * @param prefixFirstLine
735             *            a flag that indicates if the first line should be prefixed or
736             *            not.
737             */
738            public static String prefixLines(String string, String prefix,
739                            boolean prefixFirstLine) {
740                    String[] lines = StringUtils.splitLines(string.trim());
741                    StringBuilder result = new StringBuilder();
742                    for (int i = 0; i < lines.length; i++) {
743                            if (i > 0 || prefixFirstLine) {
744                                    result.append(prefix);
745                            }
746                            result.append(lines[i]);
747                            if (i < lines.length - 1) {
748                                    result.append(CR);
749                            }
750                    }
751                    return result.toString();
752            }
753    
754            /**
755             * Splits the given string into an array of {@link Character}s. This is
756             * mostly used for testing purposes, if an array of certain objects is
757             * needed.
758             */
759            public static Character[] splitChars(String s) {
760                    Character[] result = new Character[s.length()];
761                    for (int i = 0; i < result.length; ++i) {
762                            result[i] = s.charAt(i);
763                    }
764                    return result;
765            }
766    
767            /** Capitalize string. */
768            public static String capitalize(String string) {
769                    if (StringUtils.isEmpty(string)) {
770                            return string;
771                    }
772                    return string.substring(0, 1).toUpperCase() + string.substring(1);
773            }
774    
775            /**
776             * This method splits the input string into words (delimited by whitespace)
777             * and returns a string whose words are separated by single spaces and whose
778             * lines are not longer than the given length (unless a very long word
779             * occurs)).
780             */
781            public static String wrapLongLines(String s, int maxLineLength) {
782                    String[] words = s.split("\\s+");
783    
784                    StringBuilder sb = new StringBuilder();
785                    int lineLength = 0;
786                    for (String word : words) {
787                            if (word.length() == 0) {
788                                    continue;
789                            }
790    
791                            if (lineLength > 0) {
792                                    if (lineLength + 1 + word.length() > maxLineLength) {
793                                            sb.append(CR);
794                                            lineLength = 0;
795                                    } else {
796                                            sb.append(SPACE);
797                                            lineLength += 1;
798                                    }
799                            }
800                            sb.append(word);
801                            lineLength += word.length();
802                    }
803    
804                    return sb.toString();
805            }
806    
807            /** Returns the longest common prefix of s and t */
808            public static String longestCommonPrefix(String s, String t) {
809                    int n = Math.min(s.length(), t.length());
810                    for (int i = 0; i < n; i++) {
811                            if (s.charAt(i) != t.charAt(i)) {
812                                    return s.substring(0, i);
813                            }
814                    }
815                    return s.substring(0, n);
816            }
817    
818            /**
819             * Returns the longest common prefix of the strings in the list or the empty
820             * string if no common prefix exists.
821             */
822            public static String longestCommonPrefix(Iterable<String> strings) {
823                    Iterator<String> iterator = strings.iterator();
824                    CCSMAssert
825                                    .isTrue(iterator.hasNext(), "Expected are at least 2 strings");
826                    String commonPrefix = iterator.next();
827                    CCSMAssert
828                                    .isTrue(iterator.hasNext(), "Expected are at least 2 strings");
829    
830                    while (iterator.hasNext()) {
831                            commonPrefix = longestCommonPrefix(commonPrefix, iterator.next());
832                            if (commonPrefix.length() == 0) {
833                                    break;
834                            }
835                    }
836    
837                    return commonPrefix;
838            }
839    
840            /** Removes whitespace from a string. */
841            public static String removeWhitespace(String content) {
842                    return content.replaceAll("\\s", StringUtils.EMPTY_STRING);
843            }
844    
845            /**
846             * Creates a unique name which is not contained in the given set of names.
847             * If possible the given base name is directly returned, otherwise it is
848             * extended by a number.
849             */
850            public static String createUniqueName(String baseName, Set<String> usedNames) {
851                    String name = baseName;
852                    int i = 1;
853                    while (usedNames.contains(name)) {
854                            name = baseName + ++i;
855                    }
856                    return name;
857            }
858    
859            /** Transforms a string from camel-case to lower-case with hyphens. */
860            public static String camelCaseToHyphenated(String s) {
861                    return s.replaceAll("([^^])([A-Z][a-z])", "$1-$2").toLowerCase();
862            }
863    
864            /** Encodes a byte array as a hex string. */
865            public static String encodeAsHex(byte[] data) {
866                    StringBuilder sb = new StringBuilder();
867                    for (byte b : data) {
868                            sb.append(String.format("%02X", b & 0xff));
869                    }
870                    return sb.toString();
871            }
872    
873            /** Decodes a byte array from a hex string. */
874            public static byte[] decodeFromHex(String s) {
875                    byte[] result = new byte[s.length() / 2];
876                    for (int i = 0; i < result.length; ++i) {
877                            result[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2),
878                                            16);
879                    }
880                    return result;
881            }
882    
883            /**
884             * Format number with number formatter, if number formatter is
885             * <code>null</code>, this uses {@link String#valueOf(double)}.
886             */
887            public static String format(double number, NumberFormat numberFormat) {
888                    if (numberFormat == null) {
889                            return String.valueOf(number);
890                    }
891                    return numberFormat.format(number);
892            }
893    
894            /**
895             * Regex replacement methods like
896             * {@link Matcher#appendReplacement(StringBuffer, String)} or
897             * {@link String#replaceAll(String, String)} treat dollar signs as group
898             * references. This method escapes replacement strings so that dollar signs
899             * are treated as literals.
900             */
901            public static String escapeRegexReplacementString(String replacement) {
902                    // this needs to be escape thrice as replaceAll also recognizes the
903                    // dollar sign
904                    return replacement.replaceAll("([$\\\\])", "\\\\$1");
905            }
906    
907            /** Converts a string to a (UTF-8) byte representation. */
908            public static byte[] stringToBytes(String s) {
909                    return s.getBytes(FileSystemUtils.UTF8_CHARSET);
910            }
911    
912            /** Converts a (UTF-8) byte array to a string. */
913            public static String bytesToString(byte[] b) {
914                    return new String(b, FileSystemUtils.UTF8_CHARSET);
915            }
916    }