All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.firefly.utils.lang.QuotedStringTokenizer Maven / Gradle / Ivy

There is a newer version: 5.0.2
Show newest version
package com.firefly.utils.lang;

import java.io.IOException;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

/**
 * StringTokenizer with Quoting support.
 *
 * This class is a copy of the java.util.StringTokenizer API and the behaviour
 * is the same, except that single and double quoted string values are
 * recognised. Delimiters within quotes are not considered delimiters. Quotes
 * can be escaped with '\'.
 *
 * @see java.util.StringTokenizer
 *
 */
public class QuotedStringTokenizer extends StringTokenizer {
	private final static String __delim = "\t\n\r";
	private String _string;
	private String _delim = __delim;
	private boolean _returnQuotes = false;
	private boolean _returnDelimiters = false;
	private StringBuffer _token;
	private boolean _hasToken = false;
	private int _i = 0;
	private int _lastStart = 0;
	private boolean _double = true;
	private boolean _single = true;

	public QuotedStringTokenizer(String str, String delim, boolean returnDelimiters, boolean returnQuotes) {
		super("");
		_string = str;
		if (delim != null)
			_delim = delim;
		_returnDelimiters = returnDelimiters;
		_returnQuotes = returnQuotes;

		if (_delim.indexOf('\'') >= 0 || _delim.indexOf('"') >= 0)
			throw new Error("Can't use quotes as delimiters: " + _delim);

		_token = new StringBuffer(_string.length() > 1024 ? 512 : _string.length() / 2);
	}

	public QuotedStringTokenizer(String str, String delim, boolean returnDelimiters) {
		this(str, delim, returnDelimiters, false);
	}

	public QuotedStringTokenizer(String str, String delim) {
		this(str, delim, false, false);
	}

	public QuotedStringTokenizer(String str) {
		this(str, null, false, false);
	}

	@Override
	public boolean hasMoreTokens() {
		// Already found a token
		if (_hasToken)
			return true;

		_lastStart = _i;

		int state = 0;
		boolean escape = false;
		while (_i < _string.length()) {
			char c = _string.charAt(_i++);

			switch (state) {
			case 0: // Start
				if (_delim.indexOf(c) >= 0) {
					if (_returnDelimiters) {
						_token.append(c);
						return _hasToken = true;
					}
				} else if (c == '\'' && _single) {
					if (_returnQuotes)
						_token.append(c);
					state = 2;
				} else if (c == '\"' && _double) {
					if (_returnQuotes)
						_token.append(c);
					state = 3;
				} else {
					_token.append(c);
					_hasToken = true;
					state = 1;
				}
				break;

			case 1: // Token
				_hasToken = true;
				if (_delim.indexOf(c) >= 0) {
					if (_returnDelimiters)
						_i--;
					return _hasToken;
				} else if (c == '\'' && _single) {
					if (_returnQuotes)
						_token.append(c);
					state = 2;
				} else if (c == '\"' && _double) {
					if (_returnQuotes)
						_token.append(c);
					state = 3;
				} else {
					_token.append(c);
				}
				break;

			case 2: // Single Quote
				_hasToken = true;
				if (escape) {
					escape = false;
					_token.append(c);
				} else if (c == '\'') {
					if (_returnQuotes)
						_token.append(c);
					state = 1;
				} else if (c == '\\') {
					if (_returnQuotes)
						_token.append(c);
					escape = true;
				} else {
					_token.append(c);
				}
				break;

			case 3: // Double Quote
				_hasToken = true;
				if (escape) {
					escape = false;
					_token.append(c);
				} else if (c == '\"') {
					if (_returnQuotes)
						_token.append(c);
					state = 1;
				} else if (c == '\\') {
					if (_returnQuotes)
						_token.append(c);
					escape = true;
				} else {
					_token.append(c);
				}
				break;
			}
		}

		return _hasToken;
	}

	@Override
	public String nextToken() throws NoSuchElementException {
		if (!hasMoreTokens() || _token == null)
			throw new NoSuchElementException();
		String t = _token.toString();
		_token.setLength(0);
		_hasToken = false;
		return t;
	}

	@Override
	public String nextToken(String delim) throws NoSuchElementException {
		_delim = delim;
		_i = _lastStart;
		_token.setLength(0);
		_hasToken = false;
		return nextToken();
	}

	@Override
	public boolean hasMoreElements() {
		return hasMoreTokens();
	}

	@Override
	public Object nextElement() throws NoSuchElementException {
		return nextToken();
	}

	/**
	 * Not implemented.
	 */
	@Override
	public int countTokens() {
		return -1;
	}

	/**
	 * Quote a string. The string is quoted only if quoting is required due to
	 * embedded delimiters, quote characters or the empty string.
	 * 
	 * @param s
	 *            The string to quote.
	 * @param delim
	 *            the delimiter to use to quote the string
	 * @return quoted string
	 */
	public static String quoteIfNeeded(String s, String delim) {
		if (s == null)
			return null;
		if (s.length() == 0)
			return "\"\"";

		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);
			if (c == '\\' || c == '"' || c == '\'' || Character.isWhitespace(c) || delim.indexOf(c) >= 0) {
				StringBuffer b = new StringBuffer(s.length() + 8);
				quote(b, s);
				return b.toString();
			}
		}

		return s;
	}

	/**
	 * Quote a string. The string is quoted only if quoting is required due to
	 * embeded delimiters, quote characters or the empty string.
	 * 
	 * @param s
	 *            The string to quote.
	 * @return quoted string
	 */
	public static String quote(String s) {
		if (s == null)
			return null;
		if (s.length() == 0)
			return "\"\"";

		StringBuffer b = new StringBuffer(s.length() + 8);
		quote(b, s);
		return b.toString();

	}

	private static final char[] escapes = new char[32];

	static {
		Arrays.fill(escapes, (char) 0xFFFF);
		escapes['\b'] = 'b';
		escapes['\t'] = 't';
		escapes['\n'] = 'n';
		escapes['\f'] = 'f';
		escapes['\r'] = 'r';
	}

	/**
	 * Quote a string into an Appendable. Only quotes and backslash are escaped.
	 * 
	 * @param buffer
	 *            The Appendable
	 * @param input
	 *            The String to quote.
	 */
	public static void quoteOnly(Appendable buffer, String input) {
		if (input == null)
			return;

		try {
			buffer.append('"');
			for (int i = 0; i < input.length(); ++i) {
				char c = input.charAt(i);
				if (c == '"' || c == '\\')
					buffer.append('\\');
				buffer.append(c);
			}
			buffer.append('"');
		} catch (IOException x) {
			throw new RuntimeException(x);
		}
	}

	/**
	 * Quote a string into an Appendable. The characters ", \, \n, \r, \t, \f
	 * and \b are escaped
	 * 
	 * @param buffer
	 *            The Appendable
	 * @param input
	 *            The String to quote.
	 */
	public static void quote(Appendable buffer, String input) {
		if (input == null)
			return;

		try {
			buffer.append('"');
			for (int i = 0; i < input.length(); ++i) {
				char c = input.charAt(i);
				if (c >= 32) {
					if (c == '"' || c == '\\')
						buffer.append('\\');
					buffer.append(c);
				} else {
					char escape = escapes[c];
					if (escape == 0xFFFF) {
						// Unicode escape
						buffer.append('\\').append('u').append('0').append('0');
						if (c < 0x10)
							buffer.append('0');
						buffer.append(Integer.toString(c, 16));
					} else {
						buffer.append('\\').append(escape);
					}
				}
			}
			buffer.append('"');
		} catch (IOException x) {
			throw new RuntimeException(x);
		}
	}

	public static String unquoteOnly(String s) {
		return unquoteOnly(s, false);
	}

	/**
	 * Unquote a string, NOT converting unicode sequences
	 * 
	 * @param s
	 *            The string to unquote.
	 * @param lenient
	 *            if true, will leave in backslashes that aren't valid escapes
	 * @return quoted string
	 */
	public static String unquoteOnly(String s, boolean lenient) {
		if (s == null)
			return null;
		if (s.length() < 2)
			return s;

		char first = s.charAt(0);
		char last = s.charAt(s.length() - 1);
		if (first != last || (first != '"' && first != '\''))
			return s;

		StringBuilder b = new StringBuilder(s.length() - 2);
		boolean escape = false;
		for (int i = 1; i < s.length() - 1; i++) {
			char c = s.charAt(i);

			if (escape) {
				escape = false;
				if (lenient && !isValidEscaping(c)) {
					b.append('\\');
				}
				b.append(c);
			} else if (c == '\\') {
				escape = true;
			} else {
				b.append(c);
			}
		}

		return b.toString();
	}

	public static String unquote(String s) {
		return unquote(s, false);
	}

	/**
	 * Unquote a string.
	 * 
	 * @param s
	 *            The string to unquote.
	 * @param lenient
	 *            true if unquoting should be lenient to escaped content,
	 *            leaving some alone, false if string unescaping
	 * @return quoted string
	 */
	public static String unquote(String s, boolean lenient) {
		if (s == null)
			return null;
		if (s.length() < 2)
			return s;

		char first = s.charAt(0);
		char last = s.charAt(s.length() - 1);
		if (first != last || (first != '"' && first != '\''))
			return s;

		StringBuilder b = new StringBuilder(s.length() - 2);
		boolean escape = false;
		for (int i = 1; i < s.length() - 1; i++) {
			char c = s.charAt(i);

			if (escape) {
				escape = false;
				switch (c) {
				case 'n':
					b.append('\n');
					break;
				case 'r':
					b.append('\r');
					break;
				case 't':
					b.append('\t');
					break;
				case 'f':
					b.append('\f');
					break;
				case 'b':
					b.append('\b');
					break;
				case '\\':
					b.append('\\');
					break;
				case '/':
					b.append('/');
					break;
				case '"':
					b.append('"');
					break;
				case 'u':
					b.append((char) ((TypeUtils.convertHexDigit((byte) s.charAt(i++)) << 24)
							+ (TypeUtils.convertHexDigit((byte) s.charAt(i++)) << 16)
							+ (TypeUtils.convertHexDigit((byte) s.charAt(i++)) << 8)
							+ (TypeUtils.convertHexDigit((byte) s.charAt(i++)))));
					break;
				default:
					if (lenient && !isValidEscaping(c)) {
						b.append('\\');
					}
					b.append(c);
				}
			} else if (c == '\\') {
				escape = true;
			} else {
				b.append(c);
			}
		}

		return b.toString();
	}

	/**
	 * Check that char c (which is preceded by a backslash) is a valid escape
	 * sequence.
	 * 
	 * @param c
	 * @return
	 */
	private static boolean isValidEscaping(char c) {
		return ((c == 'n') || (c == 'r') || (c == 't') || (c == 'f') || (c == 'b') || (c == '\\') || (c == '/')
				|| (c == '"') || (c == 'u'));
	}

	public static boolean isQuoted(String s) {
		return s != null && s.length() > 0 && s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"';
	}

	/**
	 * @return handle double quotes if true
	 */
	public boolean getDouble() {
		return _double;
	}

	/**
	 * @param d
	 *            handle double quotes if true
	 */
	public void setDouble(boolean d) {
		_double = d;
	}

	/**
	 * @return handle single quotes if true
	 */
	public boolean getSingle() {
		return _single;
	}

	/**
	 * @param single
	 *            handle single quotes if true
	 */
	public void setSingle(boolean single) {
		_single = single;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy