/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jef.tools; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URLDecoder; import java.net.URLEncoder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import java.util.UUID; import java.util.regex.Pattern; import java.util.zip.CRC32; import jef.common.BooleanList; import jef.common.DoubleList; import jef.common.FloatList; import jef.common.IntList; import jef.common.LongList; import jef.tools.string.RegexpUtils; import jef.tools.string.StringSpliter; import jef.tools.string.Substring; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.math.NumberUtils; public final class StringUtils extends org.apache.commons.lang.StringUtils { public static final byte CR = 0x0D; public static final byte LF = 0x0A; public static final byte[] CRLF = { CR, LF }; public static final String CRLF_STR = "\r\n"; private static final String[] ISO1_SYMBOL = new String[] { "‘", "’", "”", "“", "…" }; private static final String[] ASCII_SYMBOL = new String[] { "'", "'", "\"", "\"", "--" }; private static final String EXTEND_ISO_CHAR = new String(new char[] { (char) 146, (char) 147, (char) 148 }); private static final String EXTEND_ISO_CHAR_MAPPING = (char) 39 + "\"\""; private static final String invalidCharsInFilename = "\t\\/|\"*?:<>\t\n\r";// 文件名中禁用的字符 // --------------------------------------------------------------------- // General convenience methods for working with Strings // --------------------------------------------------------------------- /** * 比较两个对象的大小,允许比较null值,null值作为最小处理 * * @param o1 * @param o2 * @return */ public static <T extends Comparable<T>> int compareNull(T o1, T o2) { if (o1 == null && o2 == null) return 0; if (o1 == null) return -1; if (o2 == null) return 1; return o1.compareTo(o2); } /** * 获得文本长度,其中双字节字符按2计算。 举例: getLengthInBytes("中国") = 4 * getLengthInBytes("卡拉OK") = 6 getLengthInBytes("太阳 月亮") = 10 * * @param str * @return */ public static int getLengthInBytes(String str) { if (str == null) return 0; int len = 0; int max = str.length(); for (int i = 0; i < max; i++) { char c = str.charAt(i); if (c > 255 && c != 65279) { len++; } } return str.length() + len; } /** * 替换最后一个出现 * * @param text * @param searchString * @param replacement * @return */ public static String replaceLast(String text, String searchString, String replacement) { if (isEmpty(text)) return text; int n = text.lastIndexOf(searchString); if (n < 0) return text; StringBuilder sb = new StringBuilder(text.length() - searchString.length() + replacement.length()); sb.append(text.substring(0, n)); sb.append(replacement); sb.append(text.substring(n + searchString.length())); return sb.toString(); } /** * 替换最后一个出现 * * @param text 传入字符串 * @param searchString 查找字符串 * @param replacement 要替换为字符串 * @return 替换后的字符串 */ public static String replaceLast(String text, char searchString, char replacement) { if (isEmpty(text)) return text; int n = text.lastIndexOf(searchString); if (n < 0) return text; StringBuilder sb = new StringBuilder(text.length()); sb.append(text.substring(0, n)); sb.append(replacement); sb.append(text.substring(n + 1)); return sb.toString(); } /** * 把[offset,offset+length)范围内的字符替换成replacement * * @param text * @param replacement * @param offset * :[0,text.length-1] * @param length * :<=text.length * @return 替换后的字符串 */ public static String replace(String text, char replacement, int offset, int length) { if (isEmpty(text) || offset >= text.length() || length <= 0) return text; if (offset < 0) offset = 0; int end = offset + length; if (end > text.length()) end = text.length(); char chars[] = text.toCharArray(); for (int i = offset; i < end; i++) chars[i] = replacement; return new String(chars); } /** * 把[offset,offset+length)范围内的字符替换成fixed个replacement * * @param text * 原字符串 * @param replacement * 替换符 * @param fixed * 个数 * @param offset * 替换起始位置 * @param length * 替换长度 * @return */ public static String replace(String text, char replacement, int fixed, int offset, int length) { if (isEmpty(text) || offset >= text.length() || length <= 0) return text; if (offset < 0) offset = 0; int end = offset + length; if (end > text.length()) end = text.length(); String left = text.substring(0, offset); String right = text.substring(end); char chars[] = new char[fixed]; for (int i = 0; i < fixed; i++) chars[i] = replacement; return concat(left, new String(chars), right); } /** * 将异常信息中的摘要输出到StringBuilder中 * * @param e * @param sb */ public static void exceptionSummary(Throwable e, StringBuilder sb) { String msg = e.getLocalizedMessage(); StackTraceElement[] stacks = e.getStackTrace(); if (msg == null && e.getCause() != null) { exceptionSummary(e.getCause(), sb); } String stack = stacks.length > 0 ? stacks[0].toString() : ""; sb.append(e.getClass().getSimpleName()).append(':').append(msg).append('\n').append(stack); } /** * 返回异常信息的堆栈摘要 * * @param e * @return */ public static String exceptionSummary(Throwable e) { String msg = e.getLocalizedMessage(); StackTraceElement[] stacks = e.getStackTrace(); if (msg == null && e.getCause() != null) { msg = exceptionSummary(e.getCause()); } String stack = stacks.length > 0 ? stacks[0].toString() : ""; return StringUtils.concat(e.getClass().getSimpleName(), ":", msg, "\r\n", stack); } /** * 將错误堆栈信息转换为String * * @param e * @param pkgStart * @return */ public static String exceptionStack(Throwable e, final String... pkgStart) { return exceptionStack("\r\n", e, pkgStart); } /** * 将异常堆栈信息转换为String * * @param cr * 换行符 * @param e * 异常 * @param pkgStart * 包的开头描述 * @return */ public static String exceptionStack(final String cr, Throwable e, final String... pkgStart) { StringWriter w = new StringWriter(); e.printStackTrace(new PrintWriter(w) { @Override public void println() { } @Override public void write(String x) { x = rtrim(x, '\r', '\n', '\t'); if (x.length() == 0) { return; } if (pkgStart.length == 0) { super.write(x, 0, x.length()); super.write(cr, 0, cr.length()); return; } String y = x.trim(); if (!y.startsWith("at ")) { super.write(x, 0, x.length()); super.write(cr, 0, cr.length()); return; } for (String s : pkgStart) { if (matchChars(y, 3, s)) { super.write(x, 0, x.length()); super.write(cr, 0, cr.length()); return; } } } }); w.flush(); IOUtils.closeQuietly(w); return w.getBuffer().toString(); } /** * 判断字符串的一部分是否和制定的文字匹配 * * @param source * @param offset * @param keyword * @return */ public static boolean matchChars(CharSequence source, int offset, CharSequence keyword) { int max = offset + keyword.length(); for (int i = offset; i < max; i++) { if (source.charAt(i) != keyword.charAt(i - offset)) { return false; } } return true; } /** * 将形如\\uxxxx的字符还原回unicode字符,即Asc2Native * * @return * @throws IOException */ public static String fromHexUnicodeString(String source) throws IOException { StringReader in = new StringReader(source); int len = source.length(); StringWriter result = new StringWriter((len > 32) ? len / 2 : 16); fromHexUnicodeString(in, result); return result.toString(); } /** * 将所有的中文字符转换为\\uxxxx形式,即Native2AscII * * @param source * @return */ public static String toHexUnicodeString(String source) { StringWriter out = new StringWriter(source.length() * 4); StringReader in = new StringReader(source); toHexUnicodeString(in, out, "\\u"); return out.toString(); } /** * 将所有的中文字符转换为{前缀}xxxx形式 * * @param source * @return */ public static String toHexUnicodeString(String source, String prefix) { StringWriter out = new StringWriter(source.length() * 4); StringReader in = new StringReader(source); toHexUnicodeString(in, out, prefix); return out.toString(); } /** * 将所有的中文字符转换为{前缀}xxxx形式(xxxx为十六进制unicode) * * @param source * @return */ public static void toHexUnicodeString(Reader in, Writer out, String prefix) { int i; try { while ((i = in.read()) > 0) { if (i > 255) { out.write(prefix); String s = Integer.toHexString(i); if (s.length() == 3) out.write('0'); out.write(s); } else { out.write((char) i); } } } catch (IOException e) { throw new RuntimeException(e); } } /** * 将形如\\uxxxx的字符还原回来 * * @return * @throws IOException */ public static void fromHexUnicodeString(Reader in, Writer result) throws IOException { char[] buffer = new char[4]; int i; while ((i = in.read()) > 0) { if (i == '\\') { i = in.read(); if (i == 'u') { int count = in.read(buffer); if (count == 4) { String unicode = new String(buffer); char uni = (char) Integer.valueOf(unicode, 16).intValue(); result.write(uni); } else {// result.write("\\u"); result.write(buffer, 0, count); } } else { result.write('\\'); if (i >= 0) result.write((char) i); } } else { result.write((char) i); } } } /** * 通过增加数字后缀来避免名称的重复 * * @param base * 原值 * @param exists * 已有的值 * @param allowRaw * 不添加后缀也不重复的情况下返回原值 * @param appendFormat * 后缀格式 * @return */ public static String escapeName(String base, String[] exists, boolean allowRaw, String appendFormat, int start) { if (allowRaw && !ArrayUtils.contains(exists, base)) { return base; } int n = start; while (ArrayUtils.contains(exists, base + (appendFormat == null ? n : String.format(appendFormat, n)))) { n++; } return base + (appendFormat == null ? n : String.format(appendFormat, n)); } /** * 将ISO8859码的文字转换成ASCII字符。 主要是西欧的一些引号等特殊字符的转换 * * @param line * @return */ public static String ISO8859ToASCII(String line) { line = replaceEach(line, ISO1_SYMBOL, ASCII_SYMBOL); line = replaceChars(line, EXTEND_ISO_CHAR, EXTEND_ISO_CHAR_MAPPING); return line; } /** * 将字节码按指定编码编码为文本,不抛出受检异常 * * @param data * @param encode * @return */ public static String convert(byte[] data, String encode) { try { return new String(data, encode); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } /** * 从文本中删除除了指定字符以外的全部字符 * * @param str * @param notremove * @return */ public static String removeCharsExcept(String str, char... notremove) { if (isEmpty(str)) return str; char chars[] = str.toCharArray(); int pos = 0; for (int i = 0; i < chars.length; i++) if (ArrayUtils.contains(notremove, chars[i])) chars[pos++] = chars[i]; return new String(chars, 0, pos); } /** * 从文本中删除指定的字符 * * @param str * @param remove * @return */ public static String removeChars(String str, char... remove) { if (isEmpty(str)) return str; char chars[] = str.toCharArray(); int pos = 0; for (int i = 0; i < chars.length; i++) if (!ArrayUtils.contains(remove, chars[i])) chars[pos++] = chars[i]; return new String(chars, 0, pos); } /** * URL解码 * * @param source * @param charset * @return */ public static String urlDecode(String source, String charset) { try { return URLDecoder.decode(source, charset); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e.getMessage()); } } /** * URL解码 * * @param source * @return */ public static String urlDecode(String source) { return urlDecode(source, "UTF-8"); } /** * URL编码 * * @param source * @return */ public static String urlEncode(String source) { try { return URLEncoder.encode(source, "UTF-8").replace("+", "%20"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e.getMessage()); } } public static String urlEncode(String source, String charset) { try { return URLEncoder.encode(source, charset).replace("+", "%20"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e.getMessage()); } } /** * 文本转换到整数Long * * @param o * @param defaultValue * @return */ public static long toLong(String o, Long defaultValue) { if (isBlank(o)) return defaultValue;// 空白则返回默认值,即便默认值为null也返回null try { return NumberUtils.createLong(o); } catch (NumberFormatException e) { if (defaultValue == null)// 默认值为null,且数值非法的情况下抛出异常 throw e; return defaultValue; } } /** * 文本转换到整数int * * @param o * @param defaultValue * @return */ public static int toInt(String o, Integer defaultValue) { if (isBlank(o)) return defaultValue;// 空白则返回默认值,即便默认值为null也返回null try { return Integer.valueOf(o); } catch (NumberFormatException e) { if (defaultValue == null)// 默认值为null,且数值非法的情况下抛出异常 throw e; return defaultValue; } } /** * 文本转换到小数float * * @param o * @param defaultValue * @return */ public static float toFloat(String o, Float defaultValue) { if (isBlank(o)) return defaultValue; try { return NumberUtils.createFloat(o); } catch (NumberFormatException e) { if (defaultValue == null)// 默认值为null,且数值非法的情况下抛出异常 throw e; return defaultValue; } } /** * 文本转换到小数double * * @param o * @param defaultValue * @return */ public static double toDouble(String o, Double defaultValue) { if (isBlank(o)) return defaultValue; try { return NumberUtils.createDouble(o); } catch (NumberFormatException e) { if (defaultValue == null)// 默认值为null,且数值非法的情况下抛出异常 throw e; return defaultValue; } } /** * 将两个数值的比值作为百分比显示 * * @param a * @param b * @return */ public static String toPercent(long a, long b) { return String.valueOf(10000 * a / b / 100f).concat("%"); } /** * 文本转换为boolean,如果不能转换则返回默认值 * * @param s * @param defaultValue * @return */ public static final boolean toBoolean(String s, Boolean defaultValue) { if ("true".equalsIgnoreCase(s) || "Y".equalsIgnoreCase(s) || "1".equals(s) || "ON".equalsIgnoreCase(s) || "yes".equalsIgnoreCase(s) || "T".equalsIgnoreCase(s)) { return true; } if ("false".equalsIgnoreCase(s) || "N".equalsIgnoreCase(s) || "0".equals(s) || "OFF".equalsIgnoreCase(s) || "no".equalsIgnoreCase(s) || "F".equalsIgnoreCase(s)) { return false; } if (defaultValue == null) {// 特别的用法,不希望有缺省值,如果字符串不能转换成布尔,则抛出异常。 throw new IllegalArgumentException(s + "can't be cast to boolean."); } return defaultValue; } /** * 将文件名中的非法字符替换成合法字符 * * @param fname * @param to * @return */ public static String toFilename(String fname, String to) { StringBuilder sb = new StringBuilder(); for (char c : fname.toCharArray()) { if (invalidCharsInFilename.indexOf(c) > -1) { sb.append(to); } else { sb.append(c); } } fname = sb.toString(); if (fname.endsWith(".")) { fname = StringUtils.substringBeforeLast(fname, "."); } return fname; } /** * 数字转换为文本,位数不足在前面补0 convert number to String, add '0' before string. * * @param number * @param length * @return */ public static String toFixLengthString(int number, int length) { String a = String.valueOf(number); if (length > a.length()) { return repeat("0", length - a.length()) + a; } else { return a; } } /** * 将字符串格式化为固定大小 * @param number * @param length * @return */ public static String toFixLengthString(String text, int length,boolean padOnLeft, char padChar) { if(text.length()==length){ return text; }else if(text.length()>length){ return text.substring(0,length); } StringBuilder sb=new StringBuilder(length); if(padOnLeft){ repeat(sb,padChar, length-text.length()); } sb.append(text); if(!padOnLeft){ repeat(sb,padChar, length-text.length()); } return sb.toString(); } /** * 取字符串右侧的部分 * * @param source * 源字符串 * @param rev * 查找 * @param keepSourceIfNotFound * 为true时找不到字串时返回全部,否则返回空串 * @return */ public static Substring stringRight(String source, String rev, boolean keepSourceIfNotFound) { if (source == null) return null; int n = source.indexOf(rev); if (n == -1) { if (keepSourceIfNotFound) { return new Substring(source); } else { return new Substring(source, source.length(), source.length()); } } return new Substring(source, n + rev.length(), source.length()); } /** * 取字符串左侧的部分 * * @param source * 源字符串 * @param rev * 查找 * @param keepSourceIfNotFound为true时找不到字串时返回全部 * ,否则返回空串 * @return */ public static Substring stringLeft(String source, String rev, boolean keepSourceIfNotFound) { if (source == null) return null; int n = source.indexOf(rev); if (n == -1) { if (keepSourceIfNotFound) { return new Substring(source); } else { return new Substring(source, 0, 0); } } return new Substring(source, 0, n); } /** * 返回字串,如果查找的字串不存在则返回全部 和substringAfter方法不同,substringAfter方法在查找不到时返回空串 * * @param source * @param rev * @return */ public static String substringAfterIfExist(String source, String rev) { if (source == null) return source; int n = source.indexOf(rev); if (n == -1) return source; return source.substring(n + rev.length()); } /** * 返回字串,如果查找的字串不存在则返回全部<br> * 和substringAfterLast方法不同,substringAfterLast方法在查找不到时返回空串 * * @param source 源字符串 * @param keyword 查找字 * @return */ public static String substringAfterLastIfExist(String source, String keyword) { if (source == null) return source; int n = source.lastIndexOf(keyword); if (n == -1) return source; return source.substring(n + keyword.length()); } /** * 在StringBuilder或各种Appendable中重复添加某个字符串若干次 * * @param sb 源 * @param str 要重复添加的字符串 * @param n 重复次数 */ public static void repeat(Appendable sb, CharSequence str, int n) { if (n <= 0) return; try { for (int i = 0; i < n; i++) { sb.append(str); } } catch (IOException e) { throw new RuntimeException(e.getMessage()); } } /** * 在StringBuilder或各种Appendable中重复添加某个字符串若干次 * * @param sb 源 * @param str 要添加的字符 * @param n 重复次数,如果传入小于等于0的值,不作处理 */ public static void repeat(Appendable sb, char str, int n) { if (n <= 0) return; try { for (int i = 0; i < n; i++) { sb.append(str); } } catch (IOException e) { throw new RuntimeException(e.getMessage()); } } /** * 重复字符串repeat the string for n times. * * @param str * String to repeat * @param n * repeat times. * @return */ public static String repeat(CharSequence str, int n) { if (n <= 0) return ""; StringBuilder s = new StringBuilder(); for (int i = 0; i < n; i++) { s.append(str); } return s.toString(); } /** * 重复字符 * * @param c * @param n * @return */ public static String repeat(char c, int n) { if (n <= 0) return ""; StringBuilder s = new StringBuilder(); for (int i = 0; i < n; i++) { s.append(c); } return s.toString(); } // //////////HTML处理 private static final String htmlEscEntities = " <>&\"'\u00A9\u00AE"; private static final String htmlEscapeSequence[] = { " ", "<", ">", "&", """, "´", "©", "®" }; /** * HTML转义 */ public static CharSequence escapeHtml(CharSequence s, boolean unicode) { if (unicode) return StringEscapeUtils.escapeHtml(s.toString()); StringBuilder sb = new StringBuilder(s.length() + 16); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); int n = htmlEscEntities.indexOf(c); if (n > -1) { sb.append(htmlEscapeSequence[n]); } else { sb.append(c); } } return sb.length() == s.length() ? s : sb.toString();// 长度一样表示没有转义发生,因此无需再创建string对象,直接返回原来的 } /** * 转义到HTML文本 * * @param s * @return */ public static CharSequence escapeHtml(CharSequence s) { return escapeHtml(s, false); } /** * HTML反转义 * * @param s * @return */ public static String unescapeHtml(String s) { return StringEscapeUtils.unescapeHtml(s); } /** * 将输入的HTML字符集转换为数据库字符集 HTML字符集:特殊字符已经被转义HTML文本 数据库字符集: 特殊字符'被转义成两个'的文本 * 用于将页面输入转换为SQL语句 */ public static String unescapeHtmlToSql(String s) { if (s == null) return null; return StringEscapeUtils.escapeSql(StringEscapeUtils.unescapeHtml(s)); } /** * 覆盖父类的方法,从两端取,Apache commons默认是从前取的 * * @param arg1 * @param arg2 * @param arg3 * @return */ public static String substringBetween(String arg1, String arg2, String arg3) { int a = arg1.indexOf(arg2); int b = arg1.lastIndexOf(arg3); if (a == -1 || b == -1) return ""; if (a == b) return ""; if (a > b) return ""; return arg1.substring(a + arg2.length(), b); } /** * 判断字符串中是否包含指定关键字 关键字中可以使用*匹配任意数量字符,使用?匹配0到1个字符 * * @param s * @param key * @param IgnoreCase * @return */ public static boolean contains(String s, String key, boolean IgnoreCase) { return matches(s, key, IgnoreCase, false, false, false); } /** * 用简易语法校验两个String是否匹配。 注意,这个方法和String.matches的逻辑完全不同 注: * 简易语法就是用*表示匹配任意字符,用?表示匹配0~1个任意字符,用+表示匹配1个或以上任意字符。 其他字符一律按照字面理解。 * 这是为了和Windows用户的习惯相吻合 */ public static boolean matches(String s, String key, boolean IgnoreCase) { return matches(s, key, IgnoreCase, true, true, false); } /** * 用简易语法校验两个String是否匹配。 注意,这个方法和String.matches的逻辑完全不同 注: * 简易语法就是用*表示匹配任意字符,用?表示匹配0~1个任意字符,用+表示匹配1个或以上任意字符。 其他字符一律按照字面理解。 * 这是为了和Windows用户的习惯相吻合 * * @param IgnoreCase * 忽略大小写 * @param matchStart * 要求头部匹配(即源字符串在头部没有多余的字符) * @param matchEnd * 要求尾部匹配(即源字符串在尾部没有多余的字符) * @param wildcardSpace * 关键字中的空格可以匹配任意数量的(\n\t空格等) * @return */ public static boolean matches(String s, String key, boolean IgnoreCase, boolean matchStart, boolean matchEnd, boolean wildcardSpace) { if (s == null && key == null) throw new NullPointerException(); if (s == null) return false; if (key == null) return true; if (IgnoreCase) { s = s.toUpperCase(); } Pattern p = RegexpUtils.simplePattern(key, IgnoreCase, matchStart, matchEnd, wildcardSpace); return p.matcher(s).matches(); } private static DecimalFormat floatFormat = new DecimalFormat("#0.00"); /** * 小数格式化(保留两位) * * @param number * @return */ public static final String formatFloat(float number) { return floatFormat.format(number); } /** * 用指定的格式将数字格式化 * * @param num * @param template * @return */ public static final String formatNumber(Number num, String template) { DecimalFormat f = new DecimalFormat(template); return f.format(num); } /** * 把字符串左边的空格给去掉 */ public static final String ltrim(String s) { int len = s.length(); int st = 0; int off = 0; /* avoid getfield opcode */ char[] val = s.toCharArray(); /* avoid getfield opcode */ while ((st < len) && (val[off + st] <= ' ')) { st++; } return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s; } /** * 从左侧删除指定的字符 * * @param s * @param trimChars * @return */ public static final String ltrim(String s, char... trimChars) { int len = s.length(); int st = 0; int off = 0; while ((st < len) && (ArrayUtils.contains(trimChars, s.charAt(off + st)))) { st++; } return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s; } /** * 从右侧删除指定的字符 * * @param s * @param trimChars * @return */ public static final String rtrim(String s, char... trimChars) { int len = s.length(); int st = 0; int off = 0; /* avoid getfield opcode */ while ((st < len) && ArrayUtils.contains(trimChars, s.charAt(off + len - 1))) { len--; } return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s; } /** * 把字符串右边的空格给去掉 * * @param s * @return */ public static final String rtrim(String s) { int len = s.length(); int st = 0; int off = 0; /* avoid getfield opcode */ char[] val = s.toCharArray(); /* avoid getfield opcode */ while ((st < len) && (val[off + len - 1] <= ' ')) { len--; } return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s; } /** * 左右两边做不同的trim * * @param s * @param lTrimChars * 左侧要trim的字符 * @param rTrimChars * 右侧要trim的字符 * @return */ public static final String lrtrim(String s, char[] lTrimChars, char[] rTrimChars) { int len = s.length(); int st = 0; int off = 0; while ((st < len) && (ArrayUtils.contains(lTrimChars, s.charAt(off + st)))) { st++; } while ((st < len) && ArrayUtils.contains(rTrimChars, s.charAt(off + len - 1))) { len--; } return ((st > 0) || (len < s.length())) ? s.substring(st, len) : s; } /** * 产生8位的随机数字 * * @return */ public static final String randomString() { return RandomStringUtils.randomNumeric(8); } /** * 获得32位的Hex uuid(實際長度36) */ public static final String generateGuid() { UUID uuid = UUID.randomUUID(); return uuid.toString(); } /** * 计算CRC摘要,8位十六进制数 */ public static String getCRC(InputStream in) { CRC32 crc32 = new CRC32(); byte[] b = new byte[8192]; int len = 0; try { while ((len = in.read(b)) != -1) { crc32.update(b, 0, len); } return Long.toHexString(crc32.getValue()); } catch (IOException e) { throw new RuntimeException(e); } finally { IOUtils.closeQuietly(in); } } /** * 计算CRC摘要,8位十六进制数 */ public static String getCRC(String s) { ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes()); return getCRC(in); } /** * 计算MD5摘要, * * @param s * 输入 * @return 32位十六进制数的MD5值 */ public final static String getMD5(String s) { ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes()); byte[] md = hash(in, "MD5"); return join(md, (char) 0, 0, md.length); } /** * 计算MD5摘要 * * @param in * @return 32位十六进制数的MD5值 */ public final static String getMD5(InputStream in) { byte[] md = hash(in, "MD5"); return join(md, (char) 0, 0, md.length); } /** * 计算SHA-1 * * @param s * @return */ public final static String getSHA1(String s) { ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes()); byte[] md = hash(in, "SHA-1"); return join(md, (char) 0, 0, md.length); } /** * 计算SHA256 * * @param s * @return */ public final static String getSHA256(String s) { ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes()); byte[] md = hash(in, "SHA-256"); return join(md, (char) 0, 0, md.length); } /** * 计算SHA-1摘要 * * @param in * @return */ public final static String getSHA1(InputStream in) { byte[] md = hash(in, "SHA-1"); return join(md, (char) 0, 0, md.length); } private static final char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /** * 将byte数组转换为可显示的十六进制文本串。效果等同于Integer.toHexString,但是实测发现JDK的方法慢3倍以上, * 所以还是用自己写的 * * @see jef.tools.ByteUtils#hex2byte(CharSequence, boolean) 其逆运算 (hex2byte) */ public static String byte2hex(byte[] b) { return join(b, ' ', 0, b.length); } /** * 将byte数组转换为可显示的十六进制文本串 * * @param b * @param offset * @param len * @return * @see jef.tools.ByteUtils#hex2byte(CharSequence, boolean) 其逆运算 (hex2byte) */ public static String byte2hex(byte[] b, int offset, int len) { return join(b, ' ', offset, len); } /* * 计算消息摘要 */ public final static byte[] hash(InputStream in, String algorithm) { try { MessageDigest mdTemp = MessageDigest.getInstance(algorithm); byte[] b = new byte[4096]; int len = 0; while ((len = in.read(b)) != -1) { mdTemp.update(b, 0, len); } return mdTemp.digest(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } finally { IOUtils.closeQuietly(in); } } /** 得到以当前毫秒数的字串 */ public static String getTimeStamp() { return String.valueOf(System.currentTimeMillis()); } /** * 计算双字节字符 * * @param s * @return */ public static int countAsian(String s) { int n = 0; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c > 255 && c != 65279) { n++; } } return n; } /** * 是否存在东亚字符 * * @param s * @return */ public static boolean hasAsian(String s) { for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c > 255 && c != 65279) { return true; } } return false; } /** * 对象转文本 * * @param obj * @return */ public static String toString(Object obj) { if (obj == null) return EMPTY; return obj.toString(); } /** * 取得字符串左边的部分,要求从左数第一位开始,且字符必须在指定的范围中 * * @return */ public static Substring subLeftWithChar(String ss, char[] chars) { int n = ss.length(); for (int i = 0; i < ss.length(); i++) { char c = ss.charAt(i); if (!ArrayUtils.contains(chars, c)) { n = i; break; } } return new Substring(ss, 0, n); } /** * 取得字符串右边的部分,要求从右数第一位开始,且字符必须在指定的范围中 * * @return */ public static Substring subRightWithChar(String ss, char[] chars) { int n = 0; for (int i = ss.length() - 1; i >= 0; i--) { char c = ss.charAt(i); if (!ArrayUtils.contains(chars, c)) { n = i + 1; break; } } return new Substring(ss, n, ss.length()); } /** * 分隔成多个子串。用分隔符之一 * * @param unknown * @param tokens * @return */ public static String[] splitOfAny(String unknown, char[] tokens) { List<String> list = new ArrayList<String>(); StringSpliter sp = new StringSpliter(unknown); while (sp.setKeyOfAny(tokens)) { list.add(sp.getLeft().toString()); sp = new StringSpliter(sp.getRight()); } list.add(sp.getSource().toString()); return list.toArray(new String[list.size()]); } /** * 分隔成多个子串。用分隔符之一 * * @param unknown * @param tokens * @return */ public static String[] splitOfAny(String unknown, String[] tokens) { List<String> list = new ArrayList<String>(); StringSpliter sp = new StringSpliter(unknown); while (sp.setKeyOfAny(tokens)) { list.add(sp.getLeft().toString()); sp = new StringSpliter(sp.getRight()); } list.add(sp.getSource().toString()); return list.toArray(new String[list.size()]); } /** * 将数组或列表拼成文本 * * @param b * @param c * @return */ public static String join(byte[] b, char c) { if (b == null) return ""; return join(b, c, 0, b.length); } /** * 将数组或列表拼成文本 * * @param b * @param dchar * @return */ public static String join(byte[] b, char dchar, int offset, int len) { if (b == null || b.length == 0) return ""; boolean appendSpace = (dchar != 0); int j = offset + len; if (j > b.length) j = b.length; // 上限 char str[] = new char[j * ((appendSpace) ? 3 : 2)]; int k = 0; for (int i = offset; i < j; i++) { byte byte0 = b[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // >>是带符号移位, >>>是无符号移位 str[k++] = hexDigits[byte0 & 0xf]; if (appendSpace) str[k++] = dchar; } if (appendSpace) { return new String(str, 0, k - 1); } else { return new String(str); } } /** * 将数组或列表拼成文本 * * @param ss * @param string * @return */ public static String join(int[] ss, String string) { StringBuilder sb = new StringBuilder(); if (ss != null && ss.length > 0) { int n = 0; sb.append(ss[n++]); while (n < ss.length) { sb.append(string); sb.append(ss[n++]); } } return sb.toString(); } /** * 将数组或列表拼成文本 * * @param ss * @param string * @return */ public static String join(float[] ss, String string) { StringBuilder sb = new StringBuilder(); if (ss != null && ss.length > 0) { int n = 0; sb.append(ss[n++]); while (n < ss.length) { sb.append(string); sb.append(ss[n++]); } } return sb.toString(); } /** * 将数组或列表拼成文本 * * @param ss * @param string * @return */ public static String join(double[] ss, String string) { StringBuilder sb = new StringBuilder(); if (ss != null && ss.length > 0) { int n = 0; sb.append(ss[n++]); while (n < ss.length) { sb.append(string); sb.append(ss[n++]); } } return sb.toString(); } /** * 数组转文本 * * @param ss * @param string * @return */ public static String join(boolean[] ss, String string) { StringBuilder sb = new StringBuilder(); if (ss != null && ss.length > 0) { int n = 0; sb.append(ss[n++]); while (n < ss.length) { sb.append(string); sb.append(ss[n++]); } } return sb.toString(); } /** * 将数组或列表拼成文本 * * @param ss * @param string * @return */ public static String join(long[] ss, String string) { StringBuilder sb = new StringBuilder(); if (ss != null && ss.length > 0) { int n = 0; sb.append(ss[n++]); while (n < ss.length) { sb.append(string); sb.append(ss[n++]); } } return sb.toString(); } /** * 将数组或列表拼成文本 * * @param ss * @param string * @return */ public static String join(short[] ss, String string) { StringBuilder sb = new StringBuilder(); if (ss != null && ss.length > 0) { int n = 0; sb.append(ss[n++]); while (n < ss.length) { sb.append(string); sb.append(ss[n++]); } } return sb.toString(); } /** * 将数组或列表拼成文本 * * @param ss * @param string * @return */ public static String join(char[] ss, String string) { int len = ss == null ? 0 : ss.length; StringBuilder sb = new StringBuilder(len + string.length() * (len - 1)); if (len > 0) { int n = 0; sb.append(ss[n++]); while (n < ss.length) { sb.append(string); sb.append(ss[n++]); } } return sb.toString(); } /** * 将数组或列表拼成文本 * * @param ss * @param sep * @return */ public static String join(Object[] os, String separator) { if (os == null || os.length == 0) return EMPTY; String[] ss = new String[os.length]; int len = 0; int sepLen = separator.length(); for (int i = 0; i < os.length; i++) { Object o = os[i]; ss[i] = o == null ? "" : o.toString(); len += ss[i].length(); len += sepLen; } StringBuilder sb = new StringBuilder(len - sepLen); int n = 0; sb.append(ss[n++]); while (n < ss.length) { sb.append(separator); sb.append(ss[n++]); } return sb.toString(); } /** * 解析字符串中的$[key},将其用properties中的值替代 * * @param s * @param prop * @return */ public static String convertProperty(String s, Properties prop) { int i = s.indexOf("${"); if (i > -1) { StringBuilder sb = new StringBuilder(); int j = -1; while (i > -1) { sb.append(s.subSequence(j + 1, i)); j = s.indexOf('}', i + 1); String key = ""; if (j > 0) {// Invalid block key = s.substring(i + 2, j); } else { j = s.indexOf("${", i + 2) - 1;// 下一处的起点作为本次的终点 if (j < 0) { j = s.length() - 1; } } if (StringUtils.isEmpty(key)) { sb.append(s.subSequence(i, j + 1));// 将J也包进去 } else { String value = prop.getProperty(key); if (value != null) sb.append(value); } i = s.indexOf("${", j); } sb.append(s.substring(j + 1)); return sb.toString(); } return s; } /** * 将数组拼成文本 当知道obj isArray的情况,但是不清楚具体的类型的情况下,做Join计算 * * @Title: join * @param 参数 * @return String 返回类型 * @throws */ public static String join(Object obj, String dchar) { Assert.notNull(obj); if (!obj.getClass().isArray()) { throw new IllegalArgumentException("The input object to join must be a Array and not null."); } Class<?> priType = obj.getClass().getComponentType(); if (priType == Boolean.TYPE) { return join((boolean[]) obj, dchar); } else if (priType == Byte.TYPE) { return join((byte[]) obj, dchar); } else if (priType == Character.TYPE) { return join((char[]) obj, dchar); } else if (priType == Integer.TYPE) { return join((int[]) obj, dchar); } else if (priType == Long.TYPE) { return join((long[]) obj, dchar); } else if (priType == Float.TYPE) { return join((float[]) obj, dchar); } else if (priType == Double.TYPE) { return join((double[]) obj, dchar); } else if (priType == Short.TYPE) { return join((short[]) obj, dchar); } else { return join((Object[]) obj, dchar); } } private static final double SIZE_1K = 1024; private static final double SIZE_1M = 1048576; private static final double SIZE_1G = 1073741824; /** * 将文件大小格式化成xxG xxM等格式 * * @param size * @return */ public static String formatSize(long size) { DecimalFormat df = new DecimalFormat("#.##"); if (size < SIZE_1K) { return String.valueOf(size); } else if (size < SIZE_1M) { return df.format(size / SIZE_1K).concat("K"); } else if (size < SIZE_1G) { return df.format(size / SIZE_1M).concat("M"); } else { return df.format(size / SIZE_1G).concat("G"); } } /** * 字符串插入 * * @param source * @param n * @param str * @return */ public static String insert(String source, int n, String str) { if (source.length() <= n) return source.concat(str); if (n < 0) n = 0; StringBuilder sb = new StringBuilder(source.length() + str.length()); sb.append(source, 0, n); sb.append(str); sb.append(source, n, source.length()); return sb.toString(); } /** * 文本截断 * * @param str * @param maxLength * @param append * 阶段后要添加的内容 * @return */ public static String truncate(String str, int maxLength, String... append) { if (str.length() <= maxLength) return str; str = str.substring(0, maxLength); if (append.length > 0) { return str.concat(append[0]); } else { return str; } } /** * 在str1当中除去str2(仅一次)。如果str1不包含str2,则返回null * * @param str1 * @param str2 * @return */ public static String removeOnce(String str1, String str2) { int n = str1.indexOf(str2); if (n == -1) return null; if (n == 0) { return str1.substring(n + str2.length()); } else if (n + str2.length() == str1.length()) { return str1.substring(0, n); } else { return str1.substring(0, n).concat(str1.substring(n + str2.length())); } } /** * 检查一个字符串是否符合数字的格式 * * @Title: isNumericOrMinus * @param isFloat * 是否允许小数 * @return boolean 返回类型 * @throws */ public static boolean isNumericOrMinus(String str, boolean isFloat) { if (str == null) return false; int sz = str.length(); if (sz == 0) return false; short hasPoint = 0; short start = 0; if (str.charAt(0) == '-') start = 1; for (int i = start; i < sz; i++) { char c = str.charAt(i); if (!Character.isDigit(c)) { if (c == '.' && hasPoint == 0 && isFloat) { hasPoint = 1; } else { return false; } } } return (sz - start) > hasPoint; } /** * 合并多个String,在参数为3个和以内时请直接使用String.concat。 * 5个和超过5个String相加后,concat方法性能急剧下降,此时此方法最快 * * @param args * @return */ public final static String concat(String... args) { if (args.length == 1) return args[0]; int n = 0; for (String s : args) { if (s == null) continue; n += s.length(); } StringBuilder sb = new StringBuilder(n); for (String s : args) { if (s == null) continue; sb.append(s); } return sb.toString(); } /** * 判断是否为合法的数字(包括负数、小数) * * @param str * @return */ public static boolean isValidNumer(String str) { return isNumericOrMinus(str, true); } /** * 是否为合法的十六进制字符,a-f A-F 0-9 * * @param str * @return */ public static boolean isHexString(String str) { int len = str.length(); for (int i = 0; i < len; i++) { char c = str.charAt(i); if (c < 48 || (c > 57 && c < 65) || (c > 70 && c < 97) || c > 102) { return false; } } return true; } /** * 判断是否为合法的数字(包括负数,但不能为小数) * * @param str * @return */ public static boolean isNumericOrMinus(String str) { return isNumericOrMinus(str, false); } /** * 当参数为对象时的非空判断,以toString后的值为准 * * @param value * @return */ public static boolean isNotEmpty(Object value) { return !isEmpty(value); } /** * 当参数为对象时的空判断,以toString后的值为准 * * @param value * @return */ public static boolean isEmpty(Object value) { if (value == null) return true; if (value instanceof CharSequence) { return ((CharSequence) value).length() == 0; } return false; } /** * 将字符串按指定的key一分为2 * * @param source * @param key * @return */ public static String[] splitLast(String source, String key) { if (source == null) return null; int n = source.lastIndexOf(key); if (n < 0) return new String[] { source, "" }; return new String[] { source.substring(0, n), source.substring(n + key.length()) }; } /** * 将文本拆成两个字符串 * @param source * @param key * @return */ public static String[] splitLast(String source, char key) { if (source == null) return null; int n = source.lastIndexOf(key); if (n < 0) return new String[] { source, "" }; return new String[] { source.substring(0, n), source.substring(n + 1) }; } /** * 将一串文本解析为Key/Value的若干值 对 * * @param source * 源数据 * @param entrySep * entry间的分隔符 * @param keyValueSep * key/value的分隔符 * @param keyUpper * key是否转大写,0不修改, -1转小写, 1转大写 * * @return */ public static Map<String, String> toMap(String source, String entrySep, String keyValueSep, int keyUpper) { Map<String, String> result = new LinkedHashMap<String, String>(); if (source != null) { for (String entry : StringUtils.split(source, entrySep)) { entry = entry.trim(); int index = entry.indexOf(keyValueSep); if (index > -1) { String key = entry.substring(0, index).trim(); if (keyUpper > 0) { key = key.toUpperCase(); } else if (keyUpper < 0) { key = key.toLowerCase(); } result.put(key, entry.substring(index + 1).trim()); } else { String key = entry; if (keyUpper > 0) { key = key.toUpperCase(); } else if (keyUpper < 0) { key = key.toLowerCase(); } result.put(key, ""); } } } return result; } /** * {@link #toMap}的逆运算,将map转回到string * @param map * @param entrySep * @param keyValueSep * @return */ public static String toString(Map<String,String> map,String entrySep,String keyValueSep){ StringBuilder sb=new StringBuilder(); Iterator<Map.Entry<String, String>> iter=map.entrySet().iterator(); if(iter.hasNext()){ { Map.Entry<String,String> e=iter.next(); sb.append(e.getKey()).append(keyValueSep).append(e.getValue()); } for(;iter.hasNext();){ Map.Entry<String,String> e=iter.next(); sb.append(entrySep).append(e.getKey()).append(keyValueSep).append(e.getValue()); } } return sb.toString(); } /** * 查找字符串的方法 * * @param str * @param searchChars * @param startPos * @return */ public static int indexOfAny(String str, char[] searchChars, int startPos) { if (isEmpty(str) || ArrayUtils.isEmpty(searchChars)) { return -1; } for (int i = startPos; i < str.length(); i++) { char ch = str.charAt(i); for (int j = 0; j < searchChars.length; j++) { if (searchChars[j] == ch) { return i; } } } return -1; } /** * 给定若干字符,从后向前寻找,任意一个匹配的字符。 * @param str * @param searchChars * @param startPos * @return */ public static int lastIndexOfAny(String str, char[] searchChars, int startPos) { if ((str == null) || (searchChars == null)) { return -1; } for (int i = str.length() - 1; i > 0; i--) { char c = str.charAt(i); for (int j = 0; j < searchChars.length; j++) { if (c == searchChars[j]) { return i; } } } return -1; } /** * 用于字符串的拼接 * * @param data * 数据 * @param sep * 分隔符 * @param sb * 拼接目标 */ public static void joinTo(Collection<?> data, String sep, StringBuilder sb) { if (data == null || data.isEmpty()) return; Iterator<?> iterator = data.iterator(); sb.append(String.valueOf(iterator.next())); while (iterator.hasNext()) { Object obj = iterator.next(); sb.append(sep).append(String.valueOf(obj)); } } /** * 用于字符串的拼接 * * @param data * 数据 * @param sep * 分隔符 * @param sb * 拼接目标 */ public static void joinTo(Object[] data, char sep, StringBuilder sb) { if (data == null || data.length == 0) return; sb.append(String.valueOf(data[0])); for (int i = 1; i < data.length; i++) { sb.append(sep).append(String.valueOf(data[i])); } } /** * 替换环境变量 * * @param content * @return */ public static String replaceTextByJvmArg(String content) { StringBuffer result = new StringBuffer(); Properties p = System.getProperties(); int pos = 0; int indexStart = -1; int indexEnd = -1; String jmvParam = null; String jmvVal = null; do { indexStart = content.indexOf("${", pos); if (indexStart > 0) { indexEnd = content.indexOf("}"); if (indexEnd < 0) throw new IllegalArgumentException("tag ${ and } should appear in pair, ${ existed, but } can't find"); } else { indexEnd = -1; } if (indexStart != -1 && indexEnd != -1) { jmvParam = content.substring(indexStart + 2, indexEnd); jmvVal = p.getProperty(jmvParam); result.append(content.substring(pos, indexStart)); if (jmvVal != null) { result.append(jmvVal); } else { throw new IllegalArgumentException("argument ${" + jmvParam + "} can't be found in jvm argument"); } } else { result.append(content.substring(pos)); } pos = indexEnd + 1; } while (pos > 0); return result.toString(); } /** * 得到字符转为小写以后的hashcode * * @param text * @return */ public static int lowerHashCode(String text) { if (text == null) { return 0; } // return text.toLowerCase().hashCode(); int h = 0; for (int i = 0; i < text.length(); ++i) { char ch = text.charAt(i); if (ch >= 'A' && ch <= 'Z') { ch = (char) (ch + 32); } h = 31 * h + ch; } return h; } /** * 将文本转换为int的列表。 * * @param text * 文本 * @param dem * 分隔字符 * @param defaultValue * 数值不合法时的缺省值 * @return 数组 */ public static int[] toIntArray(String text, char dem, int defaultValue) { String[] ss = StringUtils.split(text, dem); int[] result = new int[ss.length]; for (int i = 0; i < ss.length; i++) { String s = ss[i]; if (s.length() > 0) { try { int value = Integer.valueOf(s.trim()); result[i] = value; } catch (NumberFormatException e) { result[i] = defaultValue; } } } return result; } /** * 将文本转换为int的列表。不合法的数值将被丢弃 * * @param text * 文本 * @param dem * 分隔字符 * @return 数组 */ public static int[] toIntArray(String text, char dem) { String[] ss = StringUtils.split(text, dem); IntList result = new IntList(); for (int i = 0; i < ss.length; i++) { String s = ss[i].trim(); if (s.length() > 0) { try { int value = Integer.parseInt(s.trim()); result.add(value); } catch (NumberFormatException e) { } } } return result.toArrayUnsafe(); } /** * 将文本转换为float的列表。 * * @param text * 文本 * @param dem * 分隔字符 * @return 数组 */ public static float[] toFloatArray(String text, char dem) { String[] ss = StringUtils.split(text, dem); FloatList result = new FloatList(); for (int i = 0; i < ss.length; i++) { String s = ss[i].trim(); if (s.length() > 0) { try { float value = Float.parseFloat(s.trim()); result.add(value); } catch (NumberFormatException e) { } } } return result.toArrayUnsafe(); } /** * 将文本转换为long的列表。 * * @param text * 文本 * @param dem * 分隔字符 * @return 数组 */ public static long[] toLongArray(String text, char dem) { String[] ss = StringUtils.split(text, dem); LongList result = new LongList(); for (int i = 0; i < ss.length; i++) { String s = ss[i].trim(); if (s.length() > 0) { try { long value = Long.parseLong(s.trim()); result.add(value); } catch (NumberFormatException e) { } } } return result.toArrayUnsafe(); } /** * 将文本转换为double的列表。 * * @param text * 文本 * @param dem * 分隔字符 * @return 数组 */ public static double[] toDoubleArray(String text, char dem) { String[] ss = StringUtils.split(text, dem); DoubleList result = new DoubleList(); for (int i = 0; i < ss.length; i++) { String s = ss[i].trim(); if (s.length() > 0) { try { double value = Double.parseDouble(s.trim()); result.add(value); } catch (NumberFormatException e) { } } } return result.toArrayUnsafe(); } /** * 将文本转换为double的列表。 * * @param text * 文本 * @param dem * 分隔字符 * @return 数组 */ public static boolean[] toBooleanArray(String text, char dem) { String[] ss = StringUtils.split(text, dem); BooleanList result = new BooleanList(); for (int i = 0; i < ss.length; i++) { String s = ss[i].trim(); if (s.length() > 0) { try { boolean value = toBoolean(s.trim(), null); result.add(value); } catch (IllegalArgumentException e) { } } } return result.toArrayUnsafe(); } /** * 转换为Date数组 * @param text * @param dem * @param df * @return */ public static Date[] toDateArray(String text, char dem, DateFormat df) { String[] ss = StringUtils.split(text, dem); List<Date> list=new ArrayList<Date>(); for (int i = 0; i < ss.length; i++) { String s = ss[i].trim(); if (s.length() > 0) { try { list.add(df.parse(s)); } catch (ParseException e) { throw new IllegalArgumentException(e); } } } return list.toArray(new Date[list.size()]); } /** * Tokenize the given String into a String array via a StringTokenizer. * Trims tokens and omits empty tokens. * <p> * The given delimiters string is supposed to consist of any number of * delimiter characters. Each of those characters can be used to separate * tokens. A delimiter is always a single character; for multi-character * delimiters, consider using {@code delimitedListToStringArray} * * @param str * the String to tokenize * @param delimiters * the delimiter characters, assembled as String (each of those * characters is individually considered as delimiter). * @return an array of the tokens * @see java.util.StringTokenizer * @see String#trim() * @see #delimitedListToStringArray */ public static String[] tokenizeToStringArray(String str, String delimiters) { return tokenizeToStringArray(str, delimiters, true, true); } /** * Tokenize the given String into a String array via a StringTokenizer. * <p> * The given delimiters string is supposed to consist of any number of * delimiter characters. Each of those characters can be used to separate * tokens. A delimiter is always a single character; for multi-character * delimiters, consider using {@code delimitedListToStringArray} * * @param str * the String to tokenize * @param delimiters * the delimiter characters, assembled as String (each of those * characters is individually considered as delimiter) * @param trimTokens * trim the tokens via String's {@code trim} * @param ignoreEmptyTokens * omit empty tokens from the result array (only applies to * tokens that are empty after trimming; StringTokenizer will not * consider subsequent delimiters as token in the first place). * @return an array of the tokens ({@code null} if the input String was * {@code null}) * @see java.util.StringTokenizer * @see String#trim() * @see #delimitedListToStringArray */ public static String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { if (str == null) { return null; } StringTokenizer st = new StringTokenizer(str, delimiters); List<String> tokens = new ArrayList<String>(); while (st.hasMoreTokens()) { String token = st.nextToken(); if (trimTokens) { token = token.trim(); } if (!ignoreEmptyTokens || token.length() > 0) { tokens.add(token); } } return toStringArray(tokens); } /** * Copy the given Collection into a String array. The Collection must * contain String elements only. * <p/> * <p> * Copied from the Spring Framework while retaining all license, copyright * and author information. * * @param collection * the Collection to copy * @return the String array (<code>null</code> if the passed-in Collection * was <code>null</code>) */ public static String[] toStringArray(Collection<?> collection) { if (collection == null) { return null; } return (String[]) collection.toArray(new String[collection.size()]); } /** * Determines whether or not the sting 'searchIn' contains the string * 'searchFor', disregarding case and leading whitespace * * @param searchIn * the string to search in * @param searchFor * the string to search for * * @return true if the string starts with 'searchFor' ignoring whitespace */ public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor) { return startsWithIgnoreCaseAndWs(searchIn, searchFor, 0); } /** * Determines whether or not the sting 'searchIn' contains the string * 'searchFor', disregarding case and leading whitespace * * @param searchIn * the string to search in * @param searchFor * the string to search for * @param beginPos * where to start searching * * @return true if the string starts with 'searchFor' ignoring whitespace */ public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor, int beginPos) { if (searchIn == null) { return searchFor == null; } int inLength = searchIn.length(); for (; beginPos < inLength; beginPos++) { if (!Character.isWhitespace(searchIn.charAt(beginPos))) { break; } } return startsWithIgnoreCase(searchIn, beginPos, searchFor); } /** * Determines whether or not the string 'searchIn' contains the string * 'searchFor', dis-regarding case starting at 'startAt' Shorthand for a * String.regionMatch(...) * * @param searchIn * the string to search in * @param startAt * the position to start at * @param searchFor * the string to search for * * @return whether searchIn starts with searchFor, ignoring case */ public static boolean startsWithIgnoreCase(String searchIn, int startAt, String searchFor) { return searchIn.regionMatches(true, startAt, searchFor, 0, searchFor .length()); } }