org.smartboot.http.common.utils.StringUtils Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2017-2020, org.smartboot. All rights reserved.
* project name: smart-http
* file name: StringUtils.java
* Date: 2020-01-01
* Author: sandao ([email protected])
******************************************************************************/
package org.smartboot.http.common.utils;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;
public class StringUtils {
/**
* An empty immutable {@code String} array.
*/
public static final String[] EMPTY_STRING_ARRAY = new String[0];
/**
* The empty String {@code ""}.
*
* @since 2.0
*/
public static final String EMPTY = "";
/**
* Represents a failed index search.
*
* @since 2.1
*/
public static final int INDEX_NOT_FOUND = -1;
public static final List[] String_CACHE_EMPTY = new List[0];
private static final int CHAR_CACHE_MAX_LENGTH = 1024;
private static final ThreadLocal charsCacheThreadLocal =
ThreadLocal.withInitial(() -> new char[CHAR_CACHE_MAX_LENGTH]);
// public static String convertToString(byte[] bytes, int length, List[] cacheList) {
// return convertToString(bytes, 0, length, cacheList);
// }
public StringUtils() {
super();
}
public static String trim(final String str) {
return str == null ? null : str.trim();
}
public static String convertToString(ByteBuffer buffer, int offset, int length) {
return convertToString(buffer, offset, length, String_CACHE_EMPTY);
}
public static String convertToString(ByteBuffer buffer, int offset, int length, List[] cacheList) {
return convertToString(buffer, offset, length, cacheList, false);
}
public static String convertToString(ByteBuffer buffer, int offset, int length, List[] cacheList,
boolean readonly) {
if (length == 0) {
return "";
}
offset = buffer.arrayOffset() + offset;
byte[] bytes = buffer.array();
if (length >= cacheList.length) {
// System.out.println(new String(bytes, offset, length));
return newAsciiString(bytes, offset, length);
}
List list = cacheList[length];
for (int i = list.size() - 1; i > -1; i--) {
StringCache cache = list.get(i);
if (equals(cache.bytes, bytes, offset)) {
return cache.value;
}
}
if (readonly) {
// System.out.println(new String(bytes, offset, length));
return newAsciiString(bytes, offset, length);
}
synchronized (list) {
for (StringCache cache : list) {
if (equals(cache.bytes, bytes, offset)) {
return cache.value;
}
}
String str = newAsciiString(bytes, offset, length);
list.add(new StringCache(str.getBytes(), str));
return str;
}
}
private static boolean equals(byte[] b0, byte[] b1, int offset) {
for (int i = b0.length - 1; i > 0; i--) {
if (b0[i] != b1[i + offset]) {
return false;
}
}
return b0[0] == b1[offset];
}
public static boolean isEmpty(final CharSequence cs) {
return cs == null || cs.length() == 0;
}
public static boolean isBlank(final CharSequence cs) {
int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
public static boolean isNotBlank(final CharSequence cs) {
return !StringUtils.isBlank(cs);
}
public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
if (cs1 == cs2) {
return true;
}
if (cs1 == null || cs2 == null) {
return false;
}
if (cs1 instanceof String && cs2 instanceof String) {
return cs1.equals(cs2);
}
return regionMatches(cs1, false, 0, cs2, 0, Math.max(cs1.length(), cs2.length()));
}
private static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart,
final CharSequence substring, final int start, final int length) {
if (cs instanceof String && substring instanceof String) {
return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
} else {
int index1 = thisStart;
int index2 = start;
int tmpLen = length;
while (tmpLen-- > 0) {
char c1 = cs.charAt(index1++);
char c2 = substring.charAt(index2++);
if (c1 == c2) {
continue;
}
if (!ignoreCase) {
return false;
}
// The same check as in String.regionMatches():
if (Character.toUpperCase(c1) != Character.toUpperCase(c2) && Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
return false;
}
}
return true;
}
}
public static String substring(final String str, int start) {
if (str == null) {
return null;
}
if (start < 0) {
start = str.length() + start;
}
if (start < 0) {
start = 0;
}
if (start > str.length()) {
return EMPTY;
}
return str.substring(start);
}
public static String substring(final String str, int start, int end) {
if (str == null) {
return null;
}
if (end < 0) {
end = str.length() + end;
}
if (start < 0) {
start = str.length() + start;
}
if (end > str.length()) {
end = str.length();
}
if (start > end) {
return EMPTY;
}
if (start < 0) {
start = 0;
}
if (end < 0) {
end = 0;
}
return str.substring(start, end);
}
public static String substringBefore(final String str, final String separator) {
if (isEmpty(str) || separator == null) {
return str;
}
if (separator.isEmpty()) {
return EMPTY;
}
final int pos = str.indexOf(separator);
if (pos == INDEX_NOT_FOUND) {
return str;
}
return str.substring(0, pos);
}
public static String substringAfter(final String str, final String separator) {
if (isEmpty(str)) {
return str;
}
if (separator == null) {
return EMPTY;
}
final int pos = str.indexOf(separator);
if (pos == INDEX_NOT_FOUND) {
return EMPTY;
}
return str.substring(pos + separator.length());
}
public static String[] split(final String str, final String separatorChars) {
return splitWorker(str, separatorChars, -1, false);
}
public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
return splitWorker(str, separatorChars, -1, true);
}
private static String[] splitWorker(final String str, final String separatorChars, final int max,
final boolean preserveAllTokens) {
if (str == null) {
return null;
}
final int len = str.length();
if (len == 0) {
return EMPTY_STRING_ARRAY;
}
final List list = new ArrayList();
int sizePlus1 = 1;
int i = 0, start = 0;
boolean match = false;
boolean lastMatch = false;
if (separatorChars == null) {
// Null separator means use whitespace
while (i < len) {
if (Character.isWhitespace(str.charAt(i))) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else if (separatorChars.length() == 1) {
// Optimise 1 character case
final char sep = separatorChars.charAt(0);
while (i < len) {
if (str.charAt(i) == sep) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else {
// standard case
while (i < len) {
if (separatorChars.indexOf(str.charAt(i)) >= 0) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
}
if (match || preserveAllTokens && lastMatch) {
list.add(str.substring(start, i));
}
return list.toArray(new String[list.size()]);
}
public static String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens,
boolean ignoreEmptyTokens) {
if (str == null) {
return null;
}
StringTokenizer st = new StringTokenizer(str, delimiters);
List tokens = new ArrayList();
while (st.hasMoreTokens()) {
String token = st.nextToken();
if (trimTokens) {
token = token.trim();
}
if (!ignoreEmptyTokens || token.length() > 0) {
tokens.add(token);
}
}
return toStringArray(tokens);
}
public static String[] toStringArray(Collection collection) {
if (collection == null) {
return null;
}
return collection.toArray(new String[collection.size()]);
}
public static int length(final CharSequence cs) {
return cs == null ? 0 : cs.length();
}
public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
return startsWith(str, prefix, false);
}
private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
if (str == null || prefix == null) {
return str == null && prefix == null;
}
if (prefix.length() > str.length()) {
return false;
}
return regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
}
public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
return endsWith(str, suffix, false);
}
private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
if (str == null || suffix == null) {
return str == null && suffix == null;
}
if (suffix.length() > str.length()) {
return false;
}
final int strOffset = str.length() - suffix.length();
return regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
}
public static ByteTree scanByteTree(ByteBuffer buffer, ByteTree.EndMatcher endMatcher, ByteTree cache) {
int position = buffer.position() + buffer.arrayOffset();
int limit = buffer.limit() + buffer.arrayOffset();
byte[] data = buffer.array();
while (position < limit && data[position] == Constant.SP) {
position++;
}
ByteTree byteTree = cache.search(data, position, limit, endMatcher, false);
if (byteTree == null) {
return null;
}
buffer.position(position + byteTree.getDepth() - buffer.arrayOffset() + 1);
return byteTree;
}
public static int scanUntilAndTrim(ByteBuffer buffer, byte split) {
trimBuffer(buffer);
int position = buffer.position() + buffer.arrayOffset();
int limit = buffer.limit() + buffer.arrayOffset();
byte[] data = buffer.array();
while (position < limit) {
if (data[position++] == split) {
int length = position - buffer.arrayOffset() - buffer.position() - 1;
buffer.position(position - buffer.arrayOffset());
return length;
}
}
return -1;
}
private static void trimBuffer(ByteBuffer buffer) {
while (buffer.hasRemaining() && buffer.get(buffer.position()) == Constant.SP) {
buffer.position(buffer.position() + 1);
}
}
public static boolean addCache(List[] cache, String str) {
byte[] bytes = str.getBytes();
if (bytes.length >= cache.length) {
return false;
}
cache[bytes.length].add(new StringCache(bytes, str));
return true;
}
private static String newAsciiString(byte[] bytes, int offset, int len) {
char[] chars;
if (len <= CHAR_CACHE_MAX_LENGTH) {
chars = charsCacheThreadLocal.get();
} else {
chars = new char[len];
}
for (int i = 0; i < len; i++) {
chars[i] = (char) bytes[offset++];
}
return new String(chars, 0, len);
}
static class StringCache {
final byte[] bytes;
final String value;
public StringCache(byte[] bytes, String value) {
this.bytes = bytes;
this.value = value;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy