/**
* <pre>
* This program is free software; you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* </pre>
*/
package com.meidusa.amoeba.util;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class StringUtil {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private final static char[] c = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M' };
public static String getRandomString(int size) {
Random random = new Random();
StringBuffer sb = new StringBuffer(size);
for (int i = 0; i < size; i++) {
sb.append(c[Math.abs(random.nextInt()) % c.length]);
}
return sb.toString();
}
/**
* Attempts to generate a string representation of the object using {@link Object#toString}, but catches any
* exceptions that are thrown and reports them in the returned string instead. Useful for situations where you can't
* trust the rat bastards that implemented the object you're toString()ing.
*/
public static String safeToString(Object object) {
try {
return object.toString();
} catch (Throwable t) {
// We catch any throwable, even Errors. Someone is just trying to
// debug something,
// probably inside another catch block.
return "<toString() failure: " + t + ">";
}
}
public static boolean isEmpty(String str) {
return ((str == null) || (str.length() == 0));
}
/**
* Used to convert a time interval to a more easily human readable string of the form: <code>1d
* 15h 4m 15s 987m</code>.
*/
public static String intervalToString(long millis) {
StringBuilder buf = new StringBuilder();
boolean started = false;
long days = millis / (24 * 60 * 60 * 1000);
if (days != 0) {
buf.append(days).append("d ");
started = true;
}
long hours = (millis / (60 * 60 * 1000)) % 24;
if (started || hours != 0) {
buf.append(hours).append("h ");
}
long minutes = (millis / (60 * 1000)) % 60;
if (started || minutes != 0) {
buf.append(minutes).append("m ");
}
long seconds = (millis / (1000)) % 60;
if (started || seconds != 0) {
buf.append(seconds).append("s ");
}
buf.append(millis % 1000).append("ms");
return buf.toString();
}
/**
* Dumps the given bytes to STDOUT as a hex dump (up to length bytes).
*
* @param byteBuffer the data to print as hex
* @param length the number of bytes to print
* @return ...
*/
public static final String dumpAsHex(byte[] byteBuffer, int length) {
StringBuffer outputBuf = new StringBuffer(length * 4);
int p = 0;
int rows = length / 8;
for (int i = 0; (i < rows) && (p < length); i++) {
int ptemp = p;
for (int j = 0; j < 8; j++) {
String hexVal = Integer.toHexString(byteBuffer[ptemp] & 0xff);
if (hexVal.length() == 1) {
hexVal = "0" + hexVal; //$NON-NLS-1$
}
outputBuf.append(hexVal + " "); //$NON-NLS-1$
ptemp++;
}
outputBuf.append(" "); //$NON-NLS-1$
for (int j = 0; j < 8; j++) {
int b = 0xff & byteBuffer[p];
if (b > 32 && b < 127) {
outputBuf.append((char) b + " "); //$NON-NLS-1$
} else {
outputBuf.append(". "); //$NON-NLS-1$
}
p++;
}
outputBuf.append("\n"); //$NON-NLS-1$
}
int n = 0;
for (int i = p; i < length; i++) {
String hexVal = Integer.toHexString(byteBuffer[i] & 0xff);
if (hexVal.length() == 1) {
hexVal = "0" + hexVal; //$NON-NLS-1$
}
outputBuf.append(hexVal + " "); //$NON-NLS-1$
n++;
}
for (int i = n; i < 8; i++) {
outputBuf.append(" "); //$NON-NLS-1$
}
outputBuf.append(" "); //$NON-NLS-1$
for (int i = p; i < length; i++) {
int b = 0xff & byteBuffer[i];
if (b > 32 && b < 127) {
outputBuf.append((char) b + " "); //$NON-NLS-1$
} else {
outputBuf.append(". "); //$NON-NLS-1$
}
}
outputBuf.append("\n"); //$NON-NLS-1$
return outputBuf.toString();
}
/**
* Unfortunately, SJIS has 0x5c as a high byte in some of its double-byte characters, so we need to escape it.
*
* @param origBytes the original bytes in SJIS format
* @param origString the string that had .getBytes() called on it
* @param offset where to start converting from
* @param length how many characters to convert.
* @return byte[] with 0x5c escaped
*/
public static byte[] escapeEasternUnicodeByteStream(byte[] origBytes, String origString, int offset, int length) {
if ((origBytes == null) || (origBytes.length == 0)) {
return origBytes;
}
int bytesLen = origBytes.length;
int bufIndex = 0;
int strIndex = 0;
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(bytesLen);
while (true) {
if (origString.charAt(strIndex) == '\\') {
// write it out as-is
bytesOut.write(origBytes[bufIndex++]);
// bytesOut.write(origBytes[bufIndex++]);
} else {
// Grab the first byte
int loByte = origBytes[bufIndex];
if (loByte < 0) {
loByte += 256; // adjust for signedness/wrap-around
}
// We always write the first byte
bytesOut.write(loByte);
//
// The codepage characters in question exist between
// 0x81-0x9F and 0xE0-0xFC...
//
// See:
//
// http://www.microsoft.com/GLOBALDEV/Reference/dbcs/932.htm
//
// Problematic characters in GBK
//
// U+905C : CJK UNIFIED IDEOGRAPH
//
// Problematic characters in Big5
//
// B9F0 = U+5C62 : CJK UNIFIED IDEOGRAPH
//
if (loByte >= 0x80) {
if (bufIndex < (bytesLen - 1)) {
int hiByte = origBytes[bufIndex + 1];
if (hiByte < 0) {
hiByte += 256; // adjust for signedness/wrap-around
}
// write the high byte here, and increment the index
// for the high byte
bytesOut.write(hiByte);
bufIndex++;
// escape 0x5c if necessary
if (hiByte == 0x5C) {
bytesOut.write(hiByte);
}
}
} else if (loByte == 0x5c) {
if (bufIndex < (bytesLen - 1)) {
int hiByte = origBytes[bufIndex + 1];
if (hiByte < 0) {
hiByte += 256; // adjust for signedness/wrap-around
}
if (hiByte == 0x62) {
// we need to escape the 0x5c
bytesOut.write(0x5c);
bytesOut.write(0x62);
bufIndex++;
}
}
}
bufIndex++;
}
if (bufIndex >= bytesLen) {
// we're done
break;
}
strIndex++;
}
return bytesOut.toByteArray();
}
public static String toString(byte[] bytes) {
if (bytes == null || bytes.length == 0) return "";
StringBuffer buffer = new StringBuffer();
for (byte byt : bytes) {
buffer.append((char) byt);
}
return buffer.toString();
}
/**
* �Ƚ������ַ�������Сд���У���
*
* <pre>
* StringUtil.equals(null, null) = true
* StringUtil.equals(null, "abc") = false
* StringUtil.equals("abc", null) = false
* StringUtil.equals("abc", "abc") = true
* StringUtil.equals("abc", "ABC") = false
* </pre>
*
* @param str1 Ҫ�Ƚϵ��ַ���1
* @param str2 Ҫ�Ƚϵ��ַ���2
* @return ��������ַ�����ͬ�����߶���<code>null</code>����<code>true</code>
*/
public static boolean equals(String str1, String str2) {
if (str1 == null) {
return str2 == null;
}
return str1.equals(str2);
}
/**
* �Ƚ������ַ�������Сд�����У���
*
* <pre>
* StringUtil.equalsIgnoreCase(null, null) = true
* StringUtil.equalsIgnoreCase(null, "abc") = false
* StringUtil.equalsIgnoreCase("abc", null) = false
* StringUtil.equalsIgnoreCase("abc", "abc") = true
* StringUtil.equalsIgnoreCase("abc", "ABC") = true
* </pre>
*
* @param str1 Ҫ�Ƚϵ��ַ���1
* @param str2 Ҫ�Ƚϵ��ַ���2
* @return ��������ַ�����ͬ�����߶���<code>null</code>����<code>true</code>
*/
public static boolean equalsIgnoreCase(String str1, String str2) {
if (str1 == null) {
return str2 == null;
}
return str1.equalsIgnoreCase(str2);
}
/* ============================================================================ */
/* �ַ����ָ���� */
/* */
/* ���ַ�����ָ���ָ����ָ */
/* ============================================================================ */
/**
* ���ַ������հ��ַ��ָ
* <p>
* �ָ������������Ŀ�������У������ķָ����ͱ�����һ��������ַ���Ϊ<code>null</code>����<code>null</code>��
*
* <pre>
* StringUtil.split(null) = null
* StringUtil.split("") = []
* StringUtil.split("abc def") = ["abc", "def"]
* StringUtil.split("abc def") = ["abc", "def"]
* StringUtil.split(" abc ") = ["abc"]
* </pre>
*
* </p>
*
* @param str Ҫ�ָ���ַ���
* @return �ָ����ַ������飬���ԭ�ַ���Ϊ<code>null</code>����<code>null</code>
*/
public static String[] split(String str) {
return split(str, null, -1);
}
/**
* ���ַ�����ָ���ַ��ָ
* <p>
* �ָ������������Ŀ�������У������ķָ����ͱ�����һ��������ַ���Ϊ<code>null</code>����<code>null</code>��
*
* <pre>
* StringUtil.split(null, *) = null
* StringUtil.split("", *) = []
* StringUtil.split("a.b.c", '.') = ["a", "b", "c"]
* StringUtil.split("a..b.c", '.') = ["a", "b", "c"]
* StringUtil.split("a:b:c", '.') = ["a:b:c"]
* StringUtil.split("a b c", ' ') = ["a", "b", "c"]
* </pre>
*
* </p>
*
* @param str Ҫ�ָ���ַ���
* @param separatorChar �ָ���
* @return �ָ����ַ������飬���ԭ�ַ���Ϊ<code>null</code>����<code>null</code>
*/
@SuppressWarnings("unchecked")
public static String[] split(String str, char separatorChar) {
if (str == null) {
return null;
}
int length = str.length();
if (length == 0) {
return EMPTY_STRING_ARRAY;
}
List list = new ArrayList();
int i = 0;
int start = 0;
boolean match = false;
while (i < length) {
if (str.charAt(i) == separatorChar) {
if (match) {
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
match = true;
i++;
}
if (match) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
/**
* ���ַ�����ָ���ַ��ָ
* <p>
* �ָ������������Ŀ�������У������ķָ����ͱ�����һ��������ַ���Ϊ<code>null</code>����<code>null</code>��
*
* <pre>
* StringUtil.split(null, *) = null
* StringUtil.split("", *) = []
* StringUtil.split("abc def", null) = ["abc", "def"]
* StringUtil.split("abc def", " ") = ["abc", "def"]
* StringUtil.split("abc def", " ") = ["abc", "def"]
* StringUtil.split(" ab: cd::ef ", ":") = ["ab", "cd", "ef"]
* StringUtil.split("abc.def", "") = ["abc.def"]
* </pre>
*
* </p>
*
* @param str Ҫ�ָ���ַ���
* @param separatorChars �ָ���
* @return �ָ����ַ������飬���ԭ�ַ���Ϊ<code>null</code>����<code>null</code>
*/
public static String[] split(String str, String separatorChars) {
return split(str, separatorChars, -1);
}
/**
* ���ַ�����ָ���ַ��ָ
* <p>
* �ָ������������Ŀ�������У������ķָ����ͱ�����һ��������ַ���Ϊ<code>null</code>����<code>null</code>��
*
* <pre>
* StringUtil.split(null, *, *) = null
* StringUtil.split("", *, *) = []
* StringUtil.split("ab cd ef", null, 0) = ["ab", "cd", "ef"]
* StringUtil.split(" ab cd ef ", null, 0) = ["ab", "cd", "ef"]
* StringUtil.split("ab:cd::ef", ":", 0) = ["ab", "cd", "ef"]
* StringUtil.split("ab:cd:ef", ":", 2) = ["ab", "cdef"]
* StringUtil.split("abc.def", "", 2) = ["abc.def"]
* </pre>
*
* </p>
*
* @param str Ҫ�ָ���ַ���
* @param separatorChars �ָ���
* @param max ���ص�����������������С�ڵ���0�����ʾ������
* @return �ָ����ַ������飬���ԭ�ַ���Ϊ<code>null</code>����<code>null</code>
*/
@SuppressWarnings("unchecked")
public static String[] split(String str, String separatorChars, int max) {
if (str == null) {
return null;
}
int length = str.length();
if (length == 0) {
return EMPTY_STRING_ARRAY;
}
List list = new ArrayList();
int sizePlus1 = 1;
int i = 0;
int start = 0;
boolean match = false;
if (separatorChars == null) {
// null��ʾʹ�ÿհ���Ϊ�ָ���
while (i < length) {
if (Character.isWhitespace(str.charAt(i))) {
if (match) {
if (sizePlus1++ == max) {
i = length;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
match = true;
i++;
}
} else if (separatorChars.length() == 1) {
// �Ż��ָ�������Ϊ1������
char sep = separatorChars.charAt(0);
while (i < length) {
if (str.charAt(i) == sep) {
if (match) {
if (sizePlus1++ == max) {
i = length;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
match = true;
i++;
}
} else {
// һ������
while (i < length) {
if (separatorChars.indexOf(str.charAt(i)) >= 0) {
if (match) {
if (sizePlus1++ == max) {
i = length;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
match = true;
i++;
}
}
if (match) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
/* ============================================================================ */
/* �滻�Ӵ��� */
/* ============================================================================ */
/**
* �滻ָ�����Ӵ���ֻ�滻��һ�����ֵ��Ӵ���
* <p>
* ����ַ���Ϊ<code>null</code>��<code>null</code>�����ָ���Ӵ�Ϊ<code>null</code>����ԭ�ַ�����
*
* <pre>
* StringUtil.replaceOnce(null, *, *) = null
* StringUtil.replaceOnce("", *, *) = ""
* StringUtil.replaceOnce("aba", null, null) = "aba"
* StringUtil.replaceOnce("aba", null, null) = "aba"
* StringUtil.replaceOnce("aba", "a", null) = "aba"
* StringUtil.replaceOnce("aba", "a", "") = "ba"
* StringUtil.replaceOnce("aba", "a", "z") = "zba"
* </pre>
*
* </p>
*
* @param text Ҫɨ����ַ���
* @param repl Ҫ�������Ӵ�
* @param with �滻�ַ���
* @return ���滻����ַ��������ԭʼ�ַ���Ϊ<code>null</code>����<code>null</code>
*/
public static String replaceOnce(String text, String repl, String with) {
return replace(text, repl, with, 1);
}
/**
* �滻ָ�����Ӵ����滻���г��ֵ��Ӵ���
* <p>
* ����ַ���Ϊ<code>null</code>��<code>null</code>�����ָ���Ӵ�Ϊ<code>null</code>����ԭ�ַ�����
*
* <pre>
* StringUtil.replace(null, *, *) = null
* StringUtil.replace("", *, *) = ""
* StringUtil.replace("aba", null, null) = "aba"
* StringUtil.replace("aba", null, null) = "aba"
* StringUtil.replace("aba", "a", null) = "aba"
* StringUtil.replace("aba", "a", "") = "b"
* StringUtil.replace("aba", "a", "z") = "zbz"
* </pre>
*
* </p>
*
* @param text Ҫɨ����ַ���
* @param repl Ҫ�������Ӵ�
* @param with �滻�ַ���
* @return ���滻����ַ��������ԭʼ�ַ���Ϊ<code>null</code>����<code>null</code>
*/
public static String replace(String text, String repl, String with) {
return replace(text, repl, with, -1);
}
/**
* �滻ָ�����Ӵ����滻ָ���Ĵ�����
* <p>
* ����ַ���Ϊ<code>null</code>��<code>null</code>�����ָ���Ӵ�Ϊ<code>null</code>����ԭ�ַ�����
*
* <pre>
* StringUtil.replace(null, *, *, *) = null
* StringUtil.replace("", *, *, *) = ""
* StringUtil.replace("abaa", null, null, 1) = "abaa"
* StringUtil.replace("abaa", null, null, 1) = "abaa"
* StringUtil.replace("abaa", "a", null, 1) = "abaa"
* StringUtil.replace("abaa", "a", "", 1) = "baa"
* StringUtil.replace("abaa", "a", "z", 0) = "abaa"
* StringUtil.replace("abaa", "a", "z", 1) = "zbaa"
* StringUtil.replace("abaa", "a", "z", 2) = "zbza"
* StringUtil.replace("abaa", "a", "z", -1) = "zbzz"
* </pre>
*
* </p>
*
* @param text Ҫɨ����ַ���
* @param repl Ҫ�������Ӵ�
* @param with �滻�ַ���
* @param max maximum number of values to replace, or <code>-1</code> if no maximum
* @return ���滻����ַ��������ԭʼ�ַ���Ϊ<code>null</code>����<code>null</code>
*/
public static String replace(String text, String repl, String with, int max) {
if ((text == null) || (repl == null) || (with == null) || (repl.length() == 0) || (max == 0)) {
return text;
}
StringBuffer buf = new StringBuffer(text.length());
int start = 0;
int end = 0;
while ((end = text.indexOf(repl, start)) != -1) {
buf.append(text.substring(start, end)).append(with);
start = end + repl.length();
if (--max == 0) {
break;
}
}
buf.append(text.substring(start));
return buf.toString();
}
/**
* ���ַ���������ָ�����ַ����滻����һ����
* <p>
* ����ַ���Ϊ<code>null</code>��<code>null</code>��
*
* <pre>
* StringUtil.replaceChars(null, *, *) = null
* StringUtil.replaceChars("", *, *) = ""
* StringUtil.replaceChars("abcba", 'b', 'y') = "aycya"
* StringUtil.replaceChars("abcba", 'z', 'y') = "abcba"
* </pre>
*
* </p>
*
* @param str Ҫɨ����ַ���
* @param searchChar Ҫ�������ַ�
* @param replaceChar �滻�ַ�
* @return ���滻����ַ��������ԭʼ�ַ���Ϊ<code>null</code>����<code>null</code>
*/
public static String replaceChars(String str, char searchChar, char replaceChar) {
if (str == null) {
return null;
}
return str.replace(searchChar, replaceChar);
}
/**
* ���ַ���������ָ�����ַ����滻����һ����
* <p>
* ����ַ���Ϊ<code>null</code>��<code>null</code>����������ַ���Ϊ<code>null</code>��գ���ԭ�ַ�����
* </p>
* <p>
* ���磺 <code>replaceChars("hello", "ho", "jy") = jelly</code>��
* </p>
* <p>
* ͨ�������ַ������滻�ַ����ǵȳ��ģ���������ַ������滻�ַ��������������ַ�����ɾ���� ��������ַ������滻�ַ����̣���ȱ�ٵ��ַ��������ԡ�
*
* <pre>
* StringUtil.replaceChars(null, *, *) = null
* StringUtil.replaceChars("", *, *) = ""
* StringUtil.replaceChars("abc", null, *) = "abc"
* StringUtil.replaceChars("abc", "", *) = "abc"
* StringUtil.replaceChars("abc", "b", null) = "ac"
* StringUtil.replaceChars("abc", "b", "") = "ac"
* StringUtil.replaceChars("abcba", "bc", "yz") = "ayzya"
* StringUtil.replaceChars("abcba", "bc", "y") = "ayya"
* StringUtil.replaceChars("abcba", "bc", "yzx") = "ayzya"
* </pre>
*
* </p>
*
* @param str Ҫɨ����ַ���
* @param searchChars Ҫ�������ַ���
* @param replaceChars �滻�ַ���
* @return ���滻����ַ��������ԭʼ�ַ���Ϊ<code>null</code>����<code>null</code>
*/
public static String replaceChars(String str, String searchChars, String replaceChars) {
if ((str == null) || (str.length() == 0) || (searchChars == null) || (searchChars.length() == 0)) {
return str;
}
char[] chars = str.toCharArray();
int len = chars.length;
boolean modified = false;
for (int i = 0, isize = searchChars.length(); i < isize; i++) {
char searchChar = searchChars.charAt(i);
if ((replaceChars == null) || (i >= replaceChars.length())) {
// ɾ��
int pos = 0;
for (int j = 0; j < len; j++) {
if (chars[j] != searchChar) {
chars[pos++] = chars[j];
} else {
modified = true;
}
}
len = pos;
} else {
// �滻
for (int j = 0; j < len; j++) {
if (chars[j] == searchChar) {
chars[j] = replaceChars.charAt(i);
modified = true;
}
}
}
}
if (!modified) {
return str;
}
return new String(chars, 0, len);
}
}