/** * Copyright (c) 2011-2014 Robert Maupin * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. */ package org.csdgn.maru; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; /** * Some basic methods to allow easy escaping and unescaping of strings. * * @author Robert Maupin */ public class Strings { /** * This method escapes special characters in the given string. * * @param string * The string to escape. * @return A string with special characters escaped. */ public static final String escape(String string) { return escape(string, true); } /** * This method escapes special characters in the given string. * * @param string * The string to escape. * @param quotes * If quotes should be escaped. * @return A string with special characters escaped. */ public static final String escape(String string, boolean quotes) { StringBuilder sb = new StringBuilder(); for (char c : string.toCharArray()) { switch (c) { case '\n': sb.append("\\n"); break; case '\r': sb.append("\\r"); break; case '\t': sb.append("\\t"); break; case '\0': sb.append("\\0"); break; case '\b': sb.append("\\b"); break; case '\f': sb.append("\\f"); break; case '\\': sb.append("\\\\"); break; case '\"': if (quotes) { sb.append("\\\""); break; } sb.append(c); break; case '\'': if (quotes) { sb.append("\\'"); break; } default: sb.append(c); } } return sb.toString(); } /** * Joins the given strings using the specified delimiter. * @param parts The strings to join together into one string. * @param delimiter The delimiter to use to join the strings. * @return The strings joined together, separated by the delimiter. */ public static String join(String[] parts, String delimiter) { StringBuilder buf = new StringBuilder(); boolean first = true; for(String part : parts) { if(!first) buf.append(delimiter); first = false; buf.append(part); } return buf.toString(); } /** * Joins the given strings using the specified delimiter. * @param parts The strings to join together into one string. * @param delimiter The delimiter to use to join the strings. * @return The strings joined together, separated by the delimiter. */ public static String join(Collection<String> parts, String delimiter) { StringBuilder buf = new StringBuilder(); boolean first = true; for(String part : parts) { if(!first) buf.append(delimiter); first = false; buf.append(part); } return buf.toString(); } /** * Repeats the given string count number of times. * @param string The string to repeat. * @param count The number of times to repeat the string. * @return The string repeated count times. */ public static String repeat(String string, int count) { StringBuilder sb = new StringBuilder(); for(int i = 0; i < count; ++i) sb.append(string); return sb.toString(); } /** * Preserves null sections. "ab..cd" would produce [ab][][cd] with '.' * * @param src * The source string * @param delim * The delimiter string to split by * @return An array of strings. */ public static final String[] split(final String src, final char delim) { final ArrayList<String> output = new ArrayList<String>(); int index = 0; int lindex = 0; while ((index = src.indexOf(delim, lindex)) != -1) { output.add(src.substring(lindex, index)); lindex = index + 1; } output.add(src.substring(lindex)); return output.toArray(new String[output.size()]); } /** * Preserves null sections. "ab..cd" would produce [ab][][cd] with "." * * @param src * The source string * @param delim * The delimiter string to split by * @return An array of strings. */ public static final String[] split(final String src, final String delim) { final ArrayList<String> output = new ArrayList<String>(); final int len = delim.length(); int index = 0; int lindex = 0; while ((index = src.indexOf(delim, lindex)) != -1) { output.add(src.substring(lindex, index)); lindex = index + len; } output.add(src.substring(lindex)); return output.toArray(new String[output.size()]); } /** * Splits the given string into it's separate words. A word in this case * means any number of printable characters separated by any amount of * white space. * * @param src * The source string * @return An array of strings, containing the words in the string. */ public static final String[] splitWords(final String src) { final ArrayList<String> output = new ArrayList<String>(); StringBuilder buf = new StringBuilder(); for(char c : getIterable(src)) { if(c != ' ' && c != '\t') { buf.append(c); } else { output.add(buf.toString()); buf.setLength(0); } } if(buf.length() > 0) { output.add(buf.toString()); } return output.toArray(new String[output.size()]); } /** * Returns the number of times the given character occurs within the source string. */ public static final int count(final String src, final char chr) { int count = 0; int index = 0; while ((index = src.indexOf(chr, index)) != -1) { ++index; ++count; } return count; } public static final Iterable<Character> getIterable(final String string) { return new Iterable<Character>() { @Override public Iterator<Character> iterator() { return getIterator(string); } }; } public static final Iterator<Character> getIterator(final String string) { // Ensure the error is found as soon as possible. if (string == null) { throw new NullPointerException(); } return new Iterator<Character>() { private int index = 0; @Override public boolean hasNext() { return index < string.length(); } @Override public Character next() { /* * Throw NoSuchElementException as defined by the Iterator * contract, not IndexOutOfBoundsException. */ if (!hasNext()) { throw new NoSuchElementException(); } return string.charAt(index++); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } /** * This method unescapes special characters in the given string. * * @param string * The string to unescape. * @return A string with special characters unescaped. */ public static final String unescape(String string) { StringBuilder sb = new StringBuilder(); boolean wasEscape = false; boolean unicode = false; int count = 0; for (char c : string.toCharArray()) { if (unicode) { sb.append(c); if (++count == 4) { int s = sb.length() - 4; String code = sb.substring(s); sb.setLength(s); try { int ncode = Integer.parseInt(code, 16); sb.append((char) ncode); } catch (NumberFormatException e) { sb.append("\\u"); sb.append(code); } unicode = false; } } else if (wasEscape) { switch (c) { case '0': sb.append('\0'); break; case 'b': sb.append('\b'); break; case 'f': sb.append('\f'); break; case 't': sb.append('\t'); break; case 'r': sb.append('\r'); break; case 'n': sb.append('\n'); break; case '\\': sb.append('\\'); break; case '\'': sb.append('\''); break; case '"': sb.append('"'); break; case 'u': unicode = true; count = 0; break; default: sb.append('\\'); sb.append(c); } wasEscape = false; } else if (c == '\\') { wasEscape = true; } else { sb.append(c); } } if (unicode) { int s = sb.length() - count; String code = sb.substring(s); sb.setLength(s); sb.append("\\u"); sb.append(code); } if (wasEscape) { sb.append('\\'); } return sb.toString(); } }