📄 strings.java
字号:
/* Strings.java{{IS_NOTE Purpose: String utilities and constants Description: History: 2001/4/17, Tom M. Yeh: Created.}}IS_NOTECopyright (C) 2001 Potix Corporation. All Rights Reserved.{{IS_RIGHT This program is distributed under GPL Version 2.0 in the hope that it will be useful, but WITHOUT ANY WARRANTY.}}IS_RIGHT*/package org.zkoss.lang;import java.util.Date;import java.util.Locale;import java.util.TimeZone;import java.lang.reflect.InvocationTargetException;import java.text.ParseException;import java.math.BigDecimal;import java.math.BigInteger;import org.zkoss.mesg.MCommon;import org.zkoss.text.DateFormats;import org.zkoss.util.Locales;import org.zkoss.util.IllegalSyntaxException;/** * String utilties and constants * * @author tomyeh */public class Strings { /** * Returns true if the string is null or empty. */ public static final boolean isEmpty(String s) { return s == null || s.length() == 0; } /** * Returns true if the string is null or empty or pure blank. */ public static final boolean isBlank(String s) { if (s == null) return true; for (int j = s.length(); --j >= 0;) if (s.charAt(j) != ' ') return false; return true; } /** Returns an encoded string buffer, faster and shorter than * Integer.toHexString. It uses number and lower-case leters. * Thus it is a valid variable name if prefix with an alphabet. * At least one character is generated. * * <p>It works even in system that is case-insensitive, such as IE. * * <p>It is useful to generate a string to represent a number. */ public static final StringBuffer encode(StringBuffer sb, int val) { do { int v = val & 31; if (v < 10) { sb.append((char)('0' + v)); } else { sb.append((char)(v + ((int)'a' - 10))); } } while ((val >>>= 5) != 0); return sb; } /** Returns an encoded string buffer, faster and shorter than * Long.toHexString. It uses alpanumeric and '_'. * Thus it is a valid variable name if prefix with an alphabet. * At least one character is generated. * * <p>It works even in system that is case-insensitive, such as IE. * * <p>It is useful to generate a string to represent a number. */ public static final StringBuffer encode(StringBuffer sb, long val) { do { int v = ((int)val) & 31; if (v < 10) { sb.append((char)('0' + v)); } else { sb.append((char)(v + ((int)'a' - 10))); } } while ((val >>>= 5) != 0); return sb; } /** Returns an encoded string, faster and shorter than * Long.toHexString. */ public static final String encode(int val) { return encode(new StringBuffer(12), val).toString(); } /** Returns an encoded string, faster and shorter than * Long.toHexString. */ public static final String encode(long val) { return encode(new StringBuffer(20), val).toString(); } /** * Returns the index that is one of delimiters, or the length if none * of delimiter is found. * * <p>Unlike String.indexOf(String, int), this method returns the first * occurrence of <i>any</i> character in the delimiters. * * <p>This method is optimized to use String.indexOf(char, int) * if it found the length of dilimiter is 1. * * @param src the source string to search * @param from the index to start the search from * @param delimiters the set of characters to search for * * @return the index that is one of delimiters. * If return >= src.length(), it means no such delimiters * @see #lastAnyOf */ public static final int anyOf(String src, String delimiters, int from) { switch (delimiters.length()) { case 0: return src.length(); case 1: final int j = src.indexOf(delimiters.charAt(0), from); return j >= 0 ? j: src.length(); } for (int len = src.length(); from < len && delimiters.indexOf(src.charAt(from)) < 0; ++from) ; return from; } /** * The backward version of {@link #anyOf}. * * <p>This method is optimized to use String.indexOf(char, int) * if it found the length of dilimiter is 1. * * @return the previous index that is one of delimiter. * If it is negative, it means no delimiter in front of * <code>from</code> * @see #anyOf */ public static final int lastAnyOf(String src, String delimiters, int from) { switch (delimiters.length()) { case 0: return -1; case 1: return src.lastIndexOf(delimiters.charAt(0), from); } int len = src.length(); if (from >= len) from = len - 1; for (; from >= 0 && delimiters.indexOf(src.charAt(from)) < 0; --from) ; return from; } /** * Returns the next index after skipping whitespaces. */ public static final int skipWhitespaces(String src, int from) { for (final int len = src.length(); from < len && Character.isWhitespace(src.charAt(from)); ++from) ; return from; } /** * The backward version of {@link #skipWhitespaces}. * * @return the next index that is not a whitespace. * If it is negative, it means no whitespace in front of it. */ public static final int skipWhitespacesBackward(String src, int from) { final int len = src.length(); if (from >= len) from = len - 1; for (; from >= 0 && Character.isWhitespace(src.charAt(from)); --from) ; return from; } /** Returns the next whitespace. */ public static final int nextWhitespace(String src, int from) { for (final int len = src.length(); from < len && !Character.isWhitespace(src.charAt(from)); ++from) ; return from; } /** Escapes (aka, quote) the special characters with backslash. * It prefix a backslash to any characters specfied in the specials * argument. * * <p>Note: specials usually contains '\\'. * * <p>For example, {@link org.zkoss.util.Maps#parse} will un-quote * backspace. Thus, if you want to preserve backslash, you have * invoke escape(s, "\\") before calling Maps.parse(). * * @param s the string to process. If null, null is returned. * @param specials a string of characters that shall be escaped/quoted * @see #unescape */ public static final String escape(String s, String specials) { if (s == null) return null; StringBuffer sb = null; int j = 0; for (int k, len = s.length(); (k = anyOf(s, specials, j)) < len;) { if (sb == null) sb = new StringBuffer(len + 4); char cc = s.charAt(k); switch (cc) { case '\n': cc = 'n'; break; case '\t': cc = 't'; break; case '\r': cc = 'r'; break; case '\f': cc = 'f'; break; } sb.append(s.substring(j, k)).append('\\').append(cc); j = k + 1; } if (sb == null) return s; //nothing changed return sb.append(s.substring(j)).toString(); } /** Escapes (aka. quote) the special characters with backslash * and appends it the specified string buffer. */ public static final StringBuffer appendEscape(StringBuffer sb, String s, String specials) { if (s == null) return sb; for (int j = 0, len = s.length();;) { final int k = Strings.anyOf(s, specials, j); if (k >= len) return sb.append(s.substring(j)); char cc = s.charAt(k); switch (cc) { case '\n': cc = 'n'; break; case '\t': cc = 't'; break; case '\r': cc = 'r'; break; case '\f': cc = 'f'; break; } sb.append(s.substring(j, k)).append('\\').append(cc); j = k + 1; } } /** Un-escape the quoted string. * @see #escape * @see #appendEscape */ public static final String unescape(String s) { if (s == null) return null; StringBuffer sb = null; int j = 0; for (int k; (k = s.indexOf('\\', j)) >= 0;) { if (sb == null) sb = new StringBuffer(s.length()); char cc = s.charAt(k + 1); switch (cc) { case 'n': cc = '\n'; break; case 't': cc = '\t'; break; case 'r': cc = '\r'; break; case 'f': cc = '\f'; break; } sb.append(s.substring(j, k)).append(cc); j = k + 2; } if (sb == null) return s; //nothing changed return sb.append(s.substring(j)).toString(); } /** * Gets the substring from the <code>from</code> index up to the * <code>until</code> character or end-of-string. * Unlike String.subsring, it converts \f, \n, \t and \r. It doesn't * handle u and x yet. * * @return the result (never null). Result.next is the position of * the <code>until</code> character if found, or * a number larger than length() if no such character. */ public static final Result substring(String src, int from, char until) { return substring(src, from, until, true); } /** * Gets the substring from the <code>from</code> index up to the * <code>until</code> character or end-of-string. * * @param handleBackslash whether to treat '\\' specially (as escape char) * It doesn't handle u and x yet. * @return the result (never null). Result.next is the position of * the <code>until</code> character if found, or * a number larger than length() if no such character. * You can tell which case it is by examining {@link Result#separator}. */ public static final Result substring(String src, int from, char until, boolean handleBackslash) { final int len = src.length(); final StringBuffer sb = new StringBuffer(len); for (boolean quoted = false; from < len; ++from) { char cc = src.charAt(from); if (quoted) { quoted = false; switch (cc) { case 'f': cc = '\f'; break; case 'n': cc = '\n'; break; case 'r': cc = '\r'; break; case 't': cc = '\t'; break; } } else if (cc == until) { break; } else if (handleBackslash && cc == '\\') { quoted = true; continue; //skip it } sb.append(cc); } return new Result(from, sb.toString(), from < len ? until: (char)0); } /** Returns the next token with unescape. * <ul> * <li>It trims whitespaces before and after the token.</li> * <li>It handles both '\'' and '"'. All characters between them are * considered as a token.</li> * <li>If nothing found before end-of-string, null is returned</li> * </ul> * * If a separator is found, it is returned in * {@link Strings.Result#separator}. * * @exception IllegalSyntaxException if the quoted string is unclosed. */ public static final Result nextToken(String src, int from, char[] separators) throws IllegalSyntaxException { return nextToken(src, from, separators, true, true); } /** Returns the next token with unescape option. * * <ul> * <li>It trims whitespaces before and after the token.</li> * <li>It handles both '\'' and '"' if handleQuotation is true. * If true, all characters between them are considered as a token.</li> * <li>Consider '\\' as the escape char if handleBackslash is true.</li> * <li>If nothing found before end-of-string, null is returned</li> * </ul> * * If a separator is found, it is returned in * {@link Strings.Result#separator}. * * @param handleBackslash whether to treat '\\' specially (as escape char) * It doesn't handle u and x yet. * @param handleQuotation whether to handle '\'' and '"' * @exception IllegalSyntaxException if the quoted string is unclosed. */ public static final Result nextToken(String src, int from, char[] separators, boolean handleBackslash, boolean handleQuotation) throws IllegalSyntaxException { final int len = src.length(); from = skipWhitespaces(src, from); if (from >= len) return null; //end-of-string //1. handle quoted final char cc = src.charAt(from); if (handleQuotation && (cc == '\'' || cc == '"')) { final Result res = substring(src, from + 1, cc, handleBackslash); if (res.separator != cc) throw new IllegalSyntaxException(MCommon.QUOTE_UNMATCHED, src); res.next = skipWhitespaces(src, res.next + 1); if (res.next < len && isSeparator(src.charAt(res.next), separators)) ++res.next; return res; } //2. handle not-quoted final int j = nextSeparator(src, from, separators, handleBackslash, handleQuotation); int next = j; if (j < len) { if (handleQuotation) { final char c = src.charAt(j); if (c != '\'' && c != '"') ++next; } else { ++next; } } if (j == from) //nothing but separator return new Result(next, "", src.charAt(j)); int k = 1 + skipWhitespacesBackward(src, j - 1); return new Result(next, k > from ? handleBackslash ? unescape(src.substring(from, k)) : src.substring(from, k): "", j < len ? src.charAt(j): (char)0); //if the token is nothing but spaces, k < from } /** Returns the next seperator index in the src string. */ public static int nextSeparator(String src, int from, char[] separators, boolean handleBackslash, boolean handleQuotation) { boolean quoted = false; for (final int len = src.length(); from < len; ++from) { final char cc = src.charAt(from); if (quoted) { quoted = false; continue; } else if (handleBackslash && cc == '\\') { quoted = true; continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -