blob: 36fc9485971696bfb8d02f00d0de1fe0b85bf379 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.directory.api.util;
import static org.apache.directory.api.util.Chars.isHex;
import static org.apache.directory.api.util.Hex.encodeHex;
import static org.apache.directory.api.util.Hex.getHexValue;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.directory.api.i18n.I18n;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Various string manipulation methods that are more efficient then chaining
* string operations: all is done in the same buffer without creating a bunch of
* string objects.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public final class Strings
{
/** A logger for this class */
private static final Logger LOG = LoggerFactory.getLogger( Strings.class );
/** Hex chars */
public static final byte[] HEX_CHAR = new byte[]
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/** A table containing booleans when the corresponding char is printable */
private static final boolean[] IS_PRINTABLE_CHAR =
{
// ---, ---, ---, ---, ---, ---, ---, ---
false, false, false, false, false, false, false, false,
// ---, ---, ---, ---, ---, ---, ---, ---
false, false, false, false, false, false, false, false,
// ---, ---, ---, ---, ---, ---, ---, ---
false, false, false, false, false, false, false, false,
// ---, ---, ---, ---, ---, ---, ---, ---
false, false, false, false, false, false, false, false,
// ' ', ---, ---, ---, ---, ---, ---, "'"
true, false, false, false, false, false, false, true,
// '(', ')', ---, '+', ',', '-', '.', '/'
true, true, false, true, true, true, true, true,
// '0', '1', '2', '3', '4', '5', '6', '7',
true, true, true, true, true, true, true, true,
// '8', '9', ':', ---, ---, '=', ---, '?'
true, true, true, false, false, true, false, true,
// ---, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
false, true, true, true, true, true, true, true,
// 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'
true, true, true, true, true, true, true, true,
// 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W'
true, true, true, true, true, true, true, true,
// 'X', 'Y', 'Z', ---, ---, ---, ---, ---
true, true, true, false, false, false, false, false,
// ---, 'a', 'b', 'c', 'd', 'e', 'f', 'g'
false, true, true, true, true, true, true, true,
// 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'
true, true, true, true, true, true, true, true,
// 'p', 'q', 'r', 's', 't', 'u', 'v', 'w'
true, true, true, true, true, true, true, true,
// 'x', 'y', 'z', ---, ---, ---, ---, ---
true, true, true, false, false, false, false, false
};
private static final char[] TO_LOWER_CASE =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
' ', 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, '\'',
'(', ')', 0x2A, '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', 0x3B, 0x3C, '=', 0x3E, '?',
0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
private static final byte[] TO_LOWER_CASE_BYTE =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
' ', 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, '\'',
'(', ')', 0x2A, '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', 0x3B, 0x3C, '=', 0x3E, '?',
0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
( byte ) 0x80, ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83,
( byte ) 0x84, ( byte ) 0x85, ( byte ) 0x86, ( byte ) 0x87,
( byte ) 0x88, ( byte ) 0x89, ( byte ) 0x8A, ( byte ) 0x8B,
( byte ) 0x8C, ( byte ) 0x8D, ( byte ) 0x8E, ( byte ) 0x8F,
( byte ) 0x90, ( byte ) 0x91, ( byte ) 0x92, ( byte ) 0x93,
( byte ) 0x94, ( byte ) 0x95, ( byte ) 0x96, ( byte ) 0x97,
( byte ) 0x98, ( byte ) 0x99, ( byte ) 0x9A, ( byte ) 0x9B,
( byte ) 0x9C, ( byte ) 0x9D, ( byte ) 0x9E, ( byte ) 0x9F,
( byte ) 0xA0, ( byte ) 0xA1, ( byte ) 0xA2, ( byte ) 0xA3,
( byte ) 0xA4, ( byte ) 0xA5, ( byte ) 0xA6, ( byte ) 0xA7,
( byte ) 0xA8, ( byte ) 0xA9, ( byte ) 0xAA, ( byte ) 0xAB,
( byte ) 0xAC, ( byte ) 0xAD, ( byte ) 0xAE, ( byte ) 0xAF,
( byte ) 0xB0, ( byte ) 0xB1, ( byte ) 0xB2, ( byte ) 0xB3,
( byte ) 0xB4, ( byte ) 0xB5, ( byte ) 0xB6, ( byte ) 0xB7,
( byte ) 0xB8, ( byte ) 0xB9, ( byte ) 0xBA, ( byte ) 0xBB,
( byte ) 0xBC, ( byte ) 0xBD, ( byte ) 0xBE, ( byte ) 0xBF,
( byte ) 0xC0, ( byte ) 0xC1, ( byte ) 0xC2, ( byte ) 0xC3,
( byte ) 0xC4, ( byte ) 0xC5, ( byte ) 0xC6, ( byte ) 0xC7,
( byte ) 0xC8, ( byte ) 0xC9, ( byte ) 0xCA, ( byte ) 0xCB,
( byte ) 0xCC, ( byte ) 0xCD, ( byte ) 0xCE, ( byte ) 0xCF,
( byte ) 0xD0, ( byte ) 0xD1, ( byte ) 0xD2, ( byte ) 0xD3,
( byte ) 0xD4, ( byte ) 0xD5, ( byte ) 0xD6, ( byte ) 0xD7,
( byte ) 0xD8, ( byte ) 0xD9, ( byte ) 0xDA, ( byte ) 0xDB,
( byte ) 0xDC, ( byte ) 0xDD, ( byte ) 0xDE, ( byte ) 0xDF,
( byte ) 0xE0, ( byte ) 0xE1, ( byte ) 0xE2, ( byte ) 0xE3,
( byte ) 0xE4, ( byte ) 0xE5, ( byte ) 0xE6, ( byte ) 0xE7,
( byte ) 0xE8, ( byte ) 0xE9, ( byte ) 0xEA, ( byte ) 0xEB,
( byte ) 0xEC, ( byte ) 0xED, ( byte ) 0xEE, ( byte ) 0xEF,
( byte ) 0xF0, ( byte ) 0xF1, ( byte ) 0xF2, ( byte ) 0xF3,
( byte ) 0xF4, ( byte ) 0xF5, ( byte ) 0xF6, ( byte ) 0xF7,
( byte ) 0xF8, ( byte ) 0xF9, ( byte ) 0xFA, ( byte ) 0xFB,
( byte ) 0xFC, ( byte ) 0xFD, ( byte ) 0xFE, ( byte ) 0xFF
};
/** upperCase = 'A' .. 'Z', '0'..'9', '-' */
private static final char[] UPPER_CASE =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, '-', 0, 0,
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 0, 0, 0, 0, 0, 0,
0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 0, 0, 0, 0, 0,
0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
/** The ASCI chars */
private static final byte[] UTF8 = new byte[]
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F
};
/** An empty byte array */
public static final byte[] EMPTY_BYTES = new byte[0];
/** An empty String */
public static final String EMPTY_STRING = "";
/** An empty String array */
public static final String[] EMPTY_STRING_ARRAY = new String[]{};
/**
* Private constructor
*/
private Strings()
{
}
/**
* Helper function that dump an array of bytes in hex form
*
* @param buffer The bytes array to dump
* @return A string representation of the array of bytes
*/
public static String dumpBytes( byte[] buffer )
{
if ( buffer == null )
{
return "";
}
StringBuilder sb = new StringBuilder();
for ( int i = 0; i < buffer.length; i++ )
{
sb.append( "0x" ).append( ( char ) ( HEX_CHAR[( buffer[i] & 0x00F0 ) >> 4] ) ).append(
( char ) ( HEX_CHAR[buffer[i] & 0x000F] ) ).append( " " );
}
return sb.toString();
}
/**
* Helper function that dump a byte as a double digit value
*
* @param b The byte to dump
* @return A string representation of byte as a string
*/
public static String byteToString( byte b )
{
return Strings.utf8ToString( new byte[]
{ HEX_CHAR[( b & 0x00F0 ) >> 4], HEX_CHAR[b & 0x000F] } );
}
/**
* Helper function that dump a byte in hex form
*
* @param octet The byte to dump
* @return A string representation of the byte
*/
public static String dumpByte( byte octet )
{
return Strings.utf8ToString( new byte[]
{ '0', 'x', HEX_CHAR[( octet & 0x00F0 ) >> 4], HEX_CHAR[octet & 0x000F] } );
}
/**
* Helper function that returns a char from an hex
*
* @param hex The hex to dump
* @return A char representation of the hex
*/
public static char dumpHex( byte hex )
{
return ( char ) HEX_CHAR[hex & 0x000F];
}
/**
* Helper function that dump an array of bytes in hex pair form,
* without '0x' and space chars
*
* @param buffer The bytes array to dump
* @return A string representation of the array of bytes
*/
public static String dumpHexPairs( byte[] buffer )
{
if ( buffer == null )
{
return "";
}
char[] str = new char[buffer.length << 1];
int pos = 0;
for ( int i = 0; i < buffer.length; i++ )
{
str[pos++] = ( char ) ( HEX_CHAR[( buffer[i] & 0x00F0 ) >> 4] );
str[pos++] = ( char ) ( HEX_CHAR[buffer[i] & 0x000F] );
}
return new String( str );
}
/**
* Put common code to deepTrim(String) and deepTrimToLower here.
*
* @param str the string to deep trim
* @param toLowerCase how to normalize for case: upper or lower
* @return the deep trimmed string
* @see Strings#deepTrim( String )
*/
public static String deepTrim( String str, boolean toLowerCase )
{
if ( ( null == str ) || ( str.length() == 0 ) )
{
return "";
}
char ch;
int length = str.length();
char[] newbuf = new char[length];
boolean wsSeen = false;
boolean isStart = true;
int pos = 0;
for ( int i = 0; i < length; i++ )
{
ch = str.charAt( i );
// filter out all uppercase characters
if ( toLowerCase && Character.isUpperCase( ch ) )
{
ch = Character.toLowerCase( ch );
}
// Check to see if we should add space
if ( Character.isWhitespace( ch ) )
{
// If the buffer has had characters added already check last
// added character. Only append a spc if last character was
// not whitespace.
if ( !wsSeen )
{
wsSeen = true;
if ( isStart )
{
isStart = false;
}
else
{
newbuf[pos++] = ch;
}
}
}
else
{
// Add all non-whitespace
wsSeen = false;
isStart = false;
newbuf[pos++] = ch;
}
}
return pos == 0 ? "" : new String( newbuf, 0, wsSeen ? pos - 1 : pos );
}
/**
* This does the same thing as a trim but we also lowercase the string while
* performing the deep trim within the same buffer. This saves us from
* having to create multiple String and StringBuilder objects and is much
* more efficient.
*
* @see Strings#deepTrim( String )
* @param string The String to modify
* @return The modified String
*/
public static String deepTrimToLower( String string )
{
return deepTrim( string, true );
}
/**
* A deep trim of a string remove whitespace from the ends as well as
* excessive whitespace within the inside of the string between
* non-whitespace characters. A deep trim reduces internal whitespace down
* to a single space to preserve the whitespace separated tokenization order
* of the String.
*
* @param string the string to deep trim.
* @return the trimmed string.
*/
public static String deepTrim( String string )
{
return deepTrim( string, false );
}
/**
* Trims several consecutive characters into one.
*
* @param str the string to trim consecutive characters of
* @param ch the character to trim down
* @return the newly trimmed down string
*/
public static String trimConsecutiveToOne( String str, char ch )
{
if ( ( null == str ) || ( str.length() == 0 ) )
{
return "";
}
char[] buffer = str.toCharArray();
char[] newbuf = new char[buffer.length];
int pos = 0;
boolean same = false;
for ( int i = 0; i < buffer.length; i++ )
{
char car = buffer[i];
if ( car == ch )
{
if ( !same )
{
same = true;
newbuf[pos++] = car;
}
}
else
{
same = false;
newbuf[pos++] = car;
}
}
return new String( newbuf, 0, pos );
}
/**
* Truncates large Strings showing a portion of the String's head and tail
* with the center cut out and replaced with '...'. Also displays the total
* length of the truncated string so size of '...' can be interpreted.
* Useful for large strings in UIs or hex dumps to log files.
*
* @param str the string to truncate
* @param head the amount of the head to display
* @param tail the amount of the tail to display
* @return the center truncated string
*/
public static String centerTrunc( String str, int head, int tail )
{
// Return as-is if String is smaller than or equal to the head plus the
// tail plus the number of characters added to the trunc representation
// plus the number of digits in the string length.
if ( str.length() <= ( head + tail + 7 + str.length() / 10 ) )
{
return str;
}
StringBuilder buf = new StringBuilder();
buf.append( '[' ).append( str.length() ).append( "][" );
buf.append( str.substring( 0, head ) ).append( "..." );
buf.append( str.substring( str.length() - tail ) );
buf.append( ']' );
return buf.toString();
}
/**
* Gets a hex string from byte array.
*
* @param res the byte array
* @return the hex string representing the binary values in the array
*/
public static String toHexString( byte[] res )
{
StringBuilder buf = new StringBuilder( res.length << 1 );
for ( int ii = 0; ii < res.length; ii++ )
{
String digit = Integer.toHexString( 0xFF & res[ii] );
if ( digit.length() == 1 )
{
digit = '0' + digit;
}
buf.append( digit );
}
return upperCase( buf.toString() );
}
/**
* Get byte array from hex string
*
* @param hexString the hex string to convert to a byte array
* @return the byte form of the hex string.
*/
public static byte[] toByteArray( String hexString )
{
int arrLength = hexString.length() >> 1;
byte[] buf = new byte[arrLength];
for ( int ii = 0; ii < arrLength; ii++ )
{
int index = ii << 1;
String digit = hexString.substring( index, index + 2 );
buf[ii] = ( byte ) Integer.parseInt( digit, 16 );
}
return buf;
}
/**
* This method is used to insert HTML block dynamically
*
* @param source the HTML code to be processes
* @param replaceNl if true '\n' will be replaced by &lt;br&gt;
* @param replaceTag if true '&lt;' will be replaced by &lt; and '&gt;' will be replaced
* by &gt;
* @param replaceQuote if true '\"' will be replaced by &quot;
* @return the formated html block
*/
public static String formatHtml( String source, boolean replaceNl, boolean replaceTag,
boolean replaceQuote )
{
StringBuilder buf = new StringBuilder();
int len = source.length();
for ( int i = 0; i < len; i++ )
{
char ch = source.charAt( i );
switch ( ch )
{
case '\"':
if ( replaceQuote )
{
buf.append( "&quot;" );
}
else
{
buf.append( ch );
}
break;
case '<':
if ( replaceTag )
{
buf.append( "&lt;" );
}
else
{
buf.append( ch );
}
break;
case '>':
if ( replaceTag )
{
buf.append( "&gt;" );
}
else
{
buf.append( ch );
}
break;
case '\n':
if ( replaceNl )
{
if ( replaceTag )
{
buf.append( "&lt;br&gt;" );
}
else
{
buf.append( "<br>" );
}
}
else
{
buf.append( ch );
}
break;
case '\r':
break;
case '&':
buf.append( "&amp;" );
break;
default:
buf.append( ch );
break;
}
}
return buf.toString();
}
/**
* Check if a text is present at the current position in another string.
*
* @param string The string which contains the data
* @param index Current position in the string
* @param text The text we want to check
* @return <code>true</code> if the string contains the text.
*/
public static boolean areEquals( String string, int index, String text )
{
if ( ( string == null ) || ( text == null ) )
{
return false;
}
int length1 = string.length();
int length2 = text.length();
if ( ( length1 == 0 ) || ( length1 <= index ) || ( index < 0 )
|| ( length2 == 0 ) || ( length2 > ( length1 + index ) ) )
{
return false;
}
else
{
return string.substring( index ).startsWith( text );
}
}
/**
* Test if the current character is equal to a specific character. This
* function works only for character between 0 and 127, as it does compare a
* byte and a char (which is 16 bits wide)
*
* @param byteArray The buffer which contains the data
* @param index Current position in the buffer
* @param car The character we want to compare with the current buffer position
* @return <code>true</code> if the current character equals the given character.
*/
public static boolean isCharASCII( byte[] byteArray, int index, char car )
{
if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) || ( index >= byteArray.length ) )
{
return false;
}
else
{
return byteArray[index] == car;
}
}
/**
* Test if the current character is equal to a specific character. This
* function works only for character between 0 and 127, as it does compare a
* byte and a char (which is 16 bits wide)
*
* @param charArray The buffer which contains the data
* @param index Current position in the buffer
* @param car The character we want to compare with the current buffer position
* @return <code>true</code> if the current character equals the given character.
*/
public static boolean isCharASCII( char[] charArray, int index, char car )
{
if ( ( charArray == null ) || ( charArray.length == 0 ) || ( index < 0 ) || ( index >= charArray.length ) )
{
return false;
}
else
{
return charArray[index] == car;
}
}
/**
* Test if the current character is equal to a specific character.
*
* @param string The String which contains the data
* @param index Current position in the string
* @param car The character we want to compare with the current string position
* @return <code>true</code> if the current character equals the given character.
*/
public static boolean isCharASCII( String string, int index, char car )
{
if ( string == null )
{
return false;
}
int length = string.length();
if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
{
return false;
}
else
{
return string.charAt( index ) == car;
}
}
/**
* Return an UTF-8 encoded String
*
* @param bytes The byte array to be transformed to a String
* @return A String.
*/
public static String utf8ToString( byte[] bytes )
{
if ( bytes == null )
{
return "";
}
char[] chars = new char[bytes.length];
int pos = 0;
try
{
for ( byte b : bytes )
{
chars[pos++] = ( char ) UTF8[b];
}
}
catch ( ArrayIndexOutOfBoundsException aioobe )
{
return new String( bytes, StandardCharsets.UTF_8 );
}
return new String( chars );
}
/**
* Return an UTF-8 encoded String
*
* @param bytes The byte array to be transformed to a String
* @param length The length of the byte array to be converted
* @return A String.
*/
public static String utf8ToString( byte[] bytes, int length )
{
if ( bytes == null )
{
return "";
}
return new String( bytes, 0, length, StandardCharsets.UTF_8 );
}
/**
* Return an UTF-8 encoded String
*
* @param bytes The byte array to be transformed to a String
* @param start the starting position in the byte array
* @param length The length of the byte array to be converted
* @return A String.
*/
public static String utf8ToString( byte[] bytes, int start, int length )
{
if ( bytes == null )
{
return "";
}
return new String( bytes, start, length, StandardCharsets.UTF_8 );
}
/**
* Check if a text is present at the current position in a buffer.
*
* @param bytes The buffer which contains the data
* @param index Current position in the buffer
* @param text The text we want to check
* @return <code>true</code> if the buffer contains the text.
*/
public static int areEquals( byte[] bytes, int index, String text )
{
if ( ( bytes == null ) || ( bytes.length == 0 ) || ( bytes.length <= index ) || ( index < 0 )
|| ( text == null ) )
{
return StringConstants.NOT_EQUAL;
}
else
{
byte[] data = text.getBytes( StandardCharsets.UTF_8 );
return areEquals( bytes, index, data );
}
}
/**
* Check if a text is present at the current position in a buffer.
*
* @param chars The buffer which contains the data
* @param index Current position in the buffer
* @param text The text we want to check
* @return <code>true</code> if the buffer contains the text.
*/
public static int areEquals( char[] chars, int index, String text )
{
return areEquals( chars, index, text, true );
}
/**
* Check if a text is present at the current position in a buffer.
*
* @param chars The buffer which contains the data
* @param index Current position in the buffer
* @param text The text we want to check
* @param caseSensitive If the comparison is case-sensitive
* @return <code>true</code> if the buffer contains the text.
*/
public static int areEquals( char[] chars, int index, String text, boolean caseSensitive )
{
if ( ( chars == null ) || ( chars.length == 0 ) || ( chars.length <= index ) || ( index < 0 )
|| ( text == null ) )
{
return StringConstants.NOT_EQUAL;
}
else
{
char[] data = text.toCharArray();
return areEquals( chars, index, data, caseSensitive );
}
}
/**
* Check if a text is present at the current position in a buffer.
*
* @param chars The buffer which contains the data
* @param index Current position in the buffer
* @param chars2 The text we want to check
* @return <code>true</code> if the buffer contains the text.
*/
public static int areEquals( char[] chars, int index, char[] chars2 )
{
return areEquals( chars, index, chars2, true );
}
/**
* Check if a text is present at the current position in a buffer.
*
* @param chars The buffer which contains the data
* @param index Current position in the buffer
* @param chars2 The text we want to check
* @param caseSensitive If the comparison is case-sensitive
* @return <code>true</code> if the buffer contains the text.
*/
public static int areEquals( char[] chars, int index, char[] chars2, boolean caseSensitive )
{
if ( ( chars == null ) || ( chars.length == 0 ) || ( chars.length <= index ) || ( index < 0 )
|| ( chars2 == null ) || ( chars2.length == 0 )
|| ( chars2.length > ( chars.length - index ) ) )
{
return StringConstants.NOT_EQUAL;
}
else
{
for ( int i = 0; i < chars2.length; i++ )
{
char c1 = chars[index++];
char c2 = chars2[i];
if ( !caseSensitive )
{
c1 = Character.toLowerCase( c1 );
c2 = Character.toLowerCase( c2 );
}
if ( c1 != c2 )
{
return StringConstants.NOT_EQUAL;
}
}
return index;
}
}
/**
* Check if a text is present at the current position in a buffer.
*
* @param bytes The buffer which contains the data
* @param index Current position in the buffer
* @param bytes2 The text we want to check
* @return <code>true</code> if the buffer contains the text.
*/
public static int areEquals( byte[] bytes, int index, byte[] bytes2 )
{
if ( ( bytes == null ) || ( bytes.length == 0 ) || ( bytes.length <= index ) || ( index < 0 )
|| ( bytes2 == null ) || ( bytes2.length == 0 )
|| ( bytes2.length > ( bytes.length - index ) ) )
{
return StringConstants.NOT_EQUAL;
}
else
{
for ( int i = 0; i < bytes2.length; i++ )
{
if ( bytes[index++] != bytes2[i] )
{
return StringConstants.NOT_EQUAL;
}
}
return index;
}
}
/**
* <p>
* Checks if a String is empty ("") or null.
* </p>
*
* <pre>
* StringUtils.isEmpty(null) = true
* StringUtils.isEmpty(&quot;&quot;) = true
* StringUtils.isEmpty(&quot; &quot;) = false
* StringUtils.isEmpty(&quot;bob&quot;) = false
* StringUtils.isEmpty(&quot; bob &quot;) = false
* </pre>
*
* <p>
* NOTE: This method changed in Lang version 2.0. It no longer trims the
* String. That functionality is available in isBlank().
* </p>
*
* @param str the String to check, may be null
* @return <code>true</code> if the String is empty or null
*/
public static boolean isEmpty( String str )
{
return ( str == null ) || ( str.length() == 0 );
}
/**
* Checks if a bytes array is empty or null.
*
* @param bytes The bytes array to check, may be null
* @return <code>true</code> if the bytes array is empty or null
*/
public static boolean isEmpty( byte[] bytes )
{
return ( bytes == null ) || ( bytes.length == 0 );
}
/**
* <p>
* Removes spaces (char &lt;= 32) from both start and ends of this String,
* handling <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start and end characters &lt;= 32.
*
* <pre>
* StringUtils.trim(null) = null
* StringUtils.trim(&quot;&quot;) = &quot;&quot;
* StringUtils.trim(&quot; &quot;) = &quot;&quot;
* StringUtils.trim(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trim(&quot; abc &quot;) = &quot;abc&quot;
* </pre>
*
* @param str the String to be trimmed, may be null
* @return the trimmed string, <code>null</code> if null String input
*/
public static String trim( String str )
{
return isEmpty( str ) ? "" : str.trim();
}
/**
* <p>
* Removes spaces (char &lt;= 32) from both start and ends of this bytes
* array, handling <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start and end characters &lt;= 32.
*
* <pre>
* StringUtils.trim(null) = null
* StringUtils.trim(&quot;&quot;) = &quot;&quot;
* StringUtils.trim(&quot; &quot;) = &quot;&quot;
* StringUtils.trim(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trim(&quot; abc &quot;) = &quot;abc&quot;
* </pre>
*
* @param bytes the byte array to be trimmed, may be null
*
* @return the trimmed byte array
*/
public static byte[] trim( byte[] bytes )
{
if ( isEmpty( bytes ) )
{
return EMPTY_BYTES;
}
int start = trimLeft( bytes, 0 );
int end = trimRight( bytes, bytes.length - 1 );
int length = end - start + 1;
if ( length != 0 )
{
byte[] newBytes = new byte[end - start + 1];
System.arraycopy( bytes, start, newBytes, 0, length );
return newBytes;
}
else
{
return EMPTY_BYTES;
}
}
/**
* <p>
* Removes spaces (char &lt;= 32) from start of this String, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimLeft(null) = null
* StringUtils.trimLeft(&quot;&quot;) = &quot;&quot;
* StringUtils.trimLeft(&quot; &quot;) = &quot;&quot;
* StringUtils.trimLeft(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trimLeft(&quot; abc &quot;) = &quot;abc &quot;
* </pre>
*
* @param str the String to be trimmed, may be null
* @return the trimmed string, <code>null</code> if null String input
*/
public static String trimLeft( String str )
{
if ( isEmpty( str ) )
{
return "";
}
int start = 0;
int end = str.length();
while ( ( start < end ) && ( str.charAt( start ) == ' ' ) )
{
start++;
}
return start == 0 ? str : str.substring( start );
}
/**
* <p>
* Removes spaces (char &lt;= 32) from start of this array, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimLeft(null) = null
* StringUtils.trimLeft(&quot;&quot;) = &quot;&quot;
* StringUtils.trimLeft(&quot; &quot;) = &quot;&quot;
* StringUtils.trimLeft(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trimLeft(&quot; abc &quot;) = &quot;abc &quot;
* </pre>
*
* @param chars the chars array to be trimmed, may be null
* @param pos The position in the char[]
* @return the position of the first char which is not a space, or the last
* position of the array.
*/
public static int trimLeft( char[] chars, int pos )
{
if ( chars == null )
{
return pos;
}
while ( ( pos < chars.length ) && ( chars[pos] == ' ' ) )
{
pos++;
}
return pos;
}
/**
* <p>
* Removes spaces (char &lt;= 32) from a position in this array, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimLeft(null) = null
* StringUtils.trimLeft(&quot;&quot;,...) = &quot;&quot;
* StringUtils.trimLeft(&quot; &quot;,...) = &quot;&quot;
* StringUtils.trimLeft(&quot;abc&quot;,...) = &quot;abc&quot;
* StringUtils.trimLeft(&quot; abc &quot;,...) = &quot;abc &quot;
* </pre>
*
* @param string the string to be trimmed, may be null
* @param pos The position in the String
*/
public static void trimLeft( String string, Position pos )
{
if ( string == null )
{
return;
}
int length = string.length();
while ( ( pos.start < length ) && ( string.charAt( pos.start ) == ' ' ) )
{
pos.start++;
}
pos.end = pos.start;
}
/**
* <p>
* Removes spaces (char &lt;= 32) from a position in this array, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimLeft(null) = null
* StringUtils.trimLeft(&quot;&quot;,...) = &quot;&quot;
* StringUtils.trimLeft(&quot; &quot;,...) = &quot;&quot;
* StringUtils.trimLeft(&quot;abc&quot;,...) = &quot;abc&quot;
* StringUtils.trimLeft(&quot; abc &quot;,...) = &quot;abc &quot;
* </pre>
*
* @param bytes the byte array to be trimmed, may be null
* @param pos The position in the byte[]
*/
public static void trimLeft( byte[] bytes, Position pos )
{
if ( bytes == null )
{
return;
}
int length = bytes.length;
while ( ( pos.start < length ) && ( bytes[pos.start] == ' ' ) )
{
pos.start++;
}
pos.end = pos.start;
}
/**
* <p>
* Removes spaces (char &lt;= 32) from start of this array, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimLeft(null) = null
* StringUtils.trimLeft(&quot;&quot;) = &quot;&quot;
* StringUtils.trimLeft(&quot; &quot;) = &quot;&quot;
* StringUtils.trimLeft(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trimLeft(&quot; abc &quot;) = &quot;abc &quot;
* </pre>
*
* @param bytes the byte array to be trimmed, may be null
* @param pos The position in the byte[]
* @return the position of the first byte which is not a space, or the last
* position of the array.
*/
public static int trimLeft( byte[] bytes, int pos )
{
if ( bytes == null )
{
return pos;
}
while ( ( pos < bytes.length ) && ( bytes[pos] == ' ' ) )
{
pos++;
}
return pos;
}
/**
* <p>
* Removes spaces (char &lt;= 32) from end of this String, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimRight(null) = null
* StringUtils.trimRight(&quot;&quot;) = &quot;&quot;
* StringUtils.trimRight(&quot; &quot;) = &quot;&quot;
* StringUtils.trimRight(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trimRight(&quot; abc &quot;) = &quot; abc&quot;
* </pre>
*
* @param str the String to be trimmed, may be null
* @return the trimmed string, <code>null</code> if null String input
*/
public static String trimRight( String str )
{
if ( isEmpty( str ) )
{
return "";
}
int length = str.length();
int end = length;
while ( ( end > 0 ) && ( str.charAt( end - 1 ) == ' ' ) )
{
if ( ( end > 1 ) && ( str.charAt( end - 2 ) == '\\' ) )
{
break;
}
end--;
}
return end == length ? str : str.substring( 0, end );
}
/**
* <p>
* Removes spaces (char &lt;= 32) from end of this String, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimRight(null) = null
* StringUtils.trimRight(&quot;&quot;) = &quot;&quot;
* StringUtils.trimRight(&quot; &quot;) = &quot;&quot;
* StringUtils.trimRight(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trimRight(&quot; abc &quot;) = &quot; abc&quot;
* </pre>
*
* @param str the String to be trimmed, may be null
* @param escapedSpace The last escaped space, if any
* @return the trimmed string, <code>null</code> if null String input
*/
public static String trimRight( String str, int escapedSpace )
{
if ( isEmpty( str ) )
{
return "";
}
int length = str.length();
int end = length;
while ( ( end > 0 ) && ( str.charAt( end - 1 ) == ' ' ) && ( end > escapedSpace ) )
{
if ( ( end > 1 ) && ( str.charAt( end - 2 ) == '\\' ) )
{
break;
}
end--;
}
return end == length ? str : str.substring( 0, end );
}
/**
* <p>
* Removes spaces (char &lt;= 32) from end of this array, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimRight(null) = null
* StringUtils.trimRight(&quot;&quot;) = &quot;&quot;
* StringUtils.trimRight(&quot; &quot;) = &quot;&quot;
* StringUtils.trimRight(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trimRight(&quot; abc &quot;) = &quot; abc&quot;
* </pre>
*
* @param chars the chars array to be trimmed, may be null
* @param pos The position in the char[]
* @return the position of the first char which is not a space, or the last
* position of the array.
*/
public static int trimRight( char[] chars, int pos )
{
if ( chars == null )
{
return pos;
}
while ( ( pos >= 0 ) && ( chars[pos - 1] == ' ' ) )
{
pos--;
}
return pos;
}
/**
* <p>
* Removes spaces (char &lt;= 32) from end of this string, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimRight(null) = null
* StringUtils.trimRight(&quot;&quot;) = &quot;&quot;
* StringUtils.trimRight(&quot; &quot;) = &quot;&quot;
* StringUtils.trimRight(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trimRight(&quot; abc &quot;) = &quot; abc&quot;
* </pre>
*
* @param string the string to be trimmed, may be null
* @param pos The position in the String
* @return the position of the first char which is not a space, or the last
* position of the string.
*/
public static String trimRight( String string, Position pos )
{
if ( string == null )
{
return "";
}
while ( ( pos.end >= 0 ) && ( string.charAt( pos.end - 1 ) == ' ' ) )
{
if ( ( pos.end > 1 ) && ( string.charAt( pos.end - 2 ) == '\\' ) )
{
break;
}
pos.end--;
}
return pos.end == string.length() ? string : string.substring( 0, pos.end );
}
/**
* <p>
* Removes spaces (char &lt;= 32) from end of this string, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimRight(null) = null
* StringUtils.trimRight(&quot;&quot;) = &quot;&quot;
* StringUtils.trimRight(&quot; &quot;) = &quot;&quot;
* StringUtils.trimRight(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trimRight(&quot; abc &quot;) = &quot; abc&quot;
* </pre>
*
* @param bytes the byte array to be trimmed, may be null
* @param pos The position in the byte[]
* @return the position of the first char which is not a space, or the last
* position of the byte array.
*/
public static String trimRight( byte[] bytes, Position pos )
{
if ( bytes == null )
{
return "";
}
while ( ( pos.end >= 0 ) && ( bytes[pos.end - 1] == ' ' ) )
{
if ( ( pos.end > 1 ) && ( bytes[pos.end - 2] == '\\' ) )
{
break;
}
pos.end--;
}
if ( pos.end == bytes.length )
{
return utf8ToString( bytes );
}
else
{
return utf8ToString( bytes, pos.end );
}
}
/**
* <p>
* Removes spaces (char &lt;= 32) from end of this array, handling
* <code>null</code> by returning <code>null</code>.
* </p>
* Trim removes start characters &lt;= 32.
*
* <pre>
* StringUtils.trimRight(null) = null
* StringUtils.trimRight(&quot;&quot;) = &quot;&quot;
* StringUtils.trimRight(&quot; &quot;) = &quot;&quot;
* StringUtils.trimRight(&quot;abc&quot;) = &quot;abc&quot;
* StringUtils.trimRight(&quot; abc &quot;) = &quot; abc&quot;
* </pre>
*
* @param bytes the byte array to be trimmed, may be null
* @param pos The position in the byte[]
* @return the position of the first char which is not a space, or the last
* position of the array.
*/
public static int trimRight( byte[] bytes, int pos )
{
if ( bytes == null )
{
return pos;
}
while ( ( pos >= 0 ) && ( bytes[pos] == ' ' ) )
{
pos--;
}
return pos;
}
/**
* Get the character at a given position in a string, checking for limits
*
* @param string The string which contains the data
* @param index Current position in the string
* @return The character at the given position, or '\0' if something went wrong
*/
public static char charAt( String string, int index )
{
if ( string == null )
{
return '\0';
}
int length = string.length();
if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
{
return '\0';
}
else
{
return string.charAt( index );
}
}
/**
* Get the byte at a given position in a byte array, checking for limits
*
* @param bytes The byte[] which contains the data
* @param index Current position in the byte[]
* @return The byte at the given position, or '\0' if something went wrong
*/
public static byte byteAt( byte[] bytes, int index )
{
if ( bytes == null )
{
return '\0';
}
int length = bytes.length;
if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
{
return '\0';
}
else
{
return bytes[index];
}
}
/**
* Get the char at a given position in a byte array, checking for limits
*
* @param chars The char[] which contains the data
* @param index Current position in the char[]
* @return The byte at the given position, or '\0' if something went wrong
*/
public static char charAt( char[] chars, int index )
{
if ( chars == null )
{
return '\0';
}
int length = chars.length;
if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
{
return '\0';
}
else
{
return chars[index];
}
}
/**
* Transform an array of ASCII bytes to a string. the byte array should contains
* only values in [0, 127].
*
* @param bytes The byte array to transform
* @return The resulting string
*/
public static String asciiBytesToString( byte[] bytes )
{
if ( ( bytes == null ) || ( bytes.length == 0 ) )
{
return "";
}
char[] result = new char[bytes.length];
for ( int i = 0; i < bytes.length; i++ )
{
result[i] = ( char ) bytes[i];
}
return new String( result );
}
/**
* Return UTF-8 encoded byte[] representation of a String
*
* @param string The string to be transformed to a byte array
* @return The transformed byte array
*/
public static byte[] getBytesUtf8( String string )
{
if ( string == null )
{
return EMPTY_BYTES;
}
return string.getBytes( StandardCharsets.UTF_8 );
}
/**
* When the string to convert to bytes is pure ascii, this is a faster
* method than the getBytesUtf8. Otherwise, it's slower.
*
* @param string The string to convert to byte[]
* @return The bytes
*/
public static byte[] getBytesUtf8Ascii( String string )
{
if ( string == null )
{
return EMPTY_BYTES;
}
try
{
byte[] bytes = new byte[string.length()];
int pos = 0;
for ( int i = 0; i < string.length(); i++ )
{
bytes[pos++] = UTF8[string.charAt( i )];
}
return bytes;
}
catch ( ArrayIndexOutOfBoundsException aioobe )
{
return string.getBytes( StandardCharsets.UTF_8 );
}
}
/**
* Get the default charset
*
* @return The default charset
*/
public static String getDefaultCharsetName()
{
return Charset.defaultCharset().name();
}
/**
* <p>
* Compares two Strings, returning <code>true</code> if they are equal.
* </p>
* <p>
* <code>null</code>s are handled without exceptions. Two
* <code>null</code> references are considered to be equal. The comparison
* is case sensitive.
* </p>
*
* <pre>
* StringUtils.equals(null, null) = true
* StringUtils.equals(null, &quot;abc&quot;) = false
* StringUtils.equals(&quot;abc&quot;, null) = false
* StringUtils.equals(&quot;abc&quot;, &quot;abc&quot;) = true
* StringUtils.equals(&quot;abc&quot;, &quot;ABC&quot;) = false
* </pre>
*
* @see String#equals(Object)
* @param str1 the first String, may be null
* @param str2 the second String, may be null
* @return <code>true</code> if the Strings are equal, case sensitive, or
* both <code>null</code>
*/
public static boolean equals( String str1, String str2 )
{
return str1 == null ? str2 == null : str1.equals( str2 );
}
/**
* Utility method that return a String representation of a list
*
* @param list The list to transform to a string
* @return A csv string
*/
public static String listToString( List<?> list )
{
if ( ( list == null ) || list.isEmpty() )
{
return "";
}
StringBuilder sb = new StringBuilder();
boolean isFirst = true;
for ( Object elem : list )
{
if ( isFirst )
{
isFirst = false;
}
else
{
sb.append( ", " );
}
sb.append( elem );
}
return sb.toString();
}
/**
* Utility method that return a String representation of a set
*
* @param set The set to transform to a string
* @return A csv string
*/
public static String setToString( Set<?> set )
{
if ( ( set == null ) || set.isEmpty() )
{
return "";
}
StringBuilder sb = new StringBuilder();
boolean isFirst = true;
for ( Object elem : set )
{
if ( isFirst )
{
isFirst = false;
}
else
{
sb.append( ", " );
}
sb.append( elem );
}
return sb.toString();
}
/**
* Utility method that return a String representation of a list
*
* @param list The list to transform to a string
* @param tabs The tabs to add in front of the elements
* @return A csv string
*/
public static String listToString( List<?> list, String tabs )
{
if ( ( list == null ) || list.isEmpty() )
{
return "";
}
StringBuilder sb = new StringBuilder();
for ( Object elem : list )
{
sb.append( tabs );
sb.append( elem );
sb.append( '\n' );
}
return sb.toString();
}
/**
* Utility method that return a String representation of a map. The elements
* will be represented as "key = value"
*
* @param map The map to transform to a string
* @return A csv string
*/
public static String mapToString( Map<?, ?> map )
{
if ( ( map == null ) || ( map.size() == 0 ) )
{
return "";
}
StringBuilder sb = new StringBuilder();
boolean isFirst = true;
for ( Map.Entry<?, ?> entry : map.entrySet() )
{
if ( isFirst )
{
isFirst = false;
}
else
{
sb.append( ", " );
}
sb.append( entry.getKey() );
sb.append( " = '" ).append( entry.getValue() ).append( "'" );
}
return sb.toString();
}
/**
* Utility method that return a String representation of a map. The elements
* will be represented as "key = value"
*
* @param map The map to transform to a string
* @param tabs The tabs to add in ffront of the elements
* @return A csv string
*/
public static String mapToString( Map<?, ?> map, String tabs )
{
if ( ( map == null ) || ( map.size() == 0 ) )
{
return "";
}
StringBuilder sb = new StringBuilder();
for ( Map.Entry<?, ?> entry : map.entrySet() )
{
sb.append( tabs );
sb.append( entry.getKey() );
sb.append( " = '" ).append( entry.getValue().toString() ).append( "'\n" );
}
return sb.toString();
}
/**
* Rewrote the toLowercase method to improve performances.
* In Ldap, attributesType are supposed to use ASCII chars :
* 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
* <br>
* Deprecated : Use {@link #toLowerCaseAscii(String)}
*
* @param value The String to lowercase
* @return The lowercase string
* @deprecated Use {@link #toLowerCaseAscii(String)}
*/
@Deprecated
public static String toLowerCase( String value )
{
if ( ( null == value ) || ( value.length() == 0 ) )
{
return "";
}
char[] chars = value.toCharArray();
for ( int i = 0; i < chars.length; i++ )
{
chars[i] = TO_LOWER_CASE[chars[i]];
}
return new String( chars );
}
/**
* Rewrote the toLowercase method to improve performances.
* In Ldap, attributesType are supposed to use ASCII chars :
* 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
*
* @param value The String to lowercase
* @return The lowercase string
*/
public static String toLowerCaseAscii( String value )
{
if ( ( null == value ) || ( value.length() == 0 ) )
{
return "";
}
char[] chars = value.toCharArray();
for ( int i = 0; i < chars.length; i++ )
{
chars[i] = TO_LOWER_CASE[chars[i]];
}
return new String( chars );
}
/**
* Rewrote the toLowercase method to improve performances.
* In Ldap, attributesType are supposed to use ASCII chars :
* 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
*
* @param value The byte[] to lowercase
* @return The lowercase string
*/
public static String toLowerCase( byte[] value )
{
if ( ( null == value ) || ( value.length == 0 ) )
{
return "";
}
for ( int i = 0; i < value.length; i++ )
{
value[i] = TO_LOWER_CASE_BYTE[value[i]];
}
return Strings.utf8ToString( value );
}
/**
* Rewrote the toUppercase method to improve performances.
* In Ldap, attributesType are supposed to use ASCII chars :
* 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only. We also add the '_' char
* <br>
* Deprecated Use {@link #toUpperCaseAscii(String)}
* @param value The String to uppercase
* @return The uppercase string
* @deprecated Use {@link #toUpperCaseAscii(String)}
*/
@Deprecated
public static String toUpperCase( String value )
{
if ( ( null == value ) || ( value.length() == 0 ) )
{
return "";
}
char[] chars = value.toCharArray();
for ( int i = 0; i < chars.length; i++ )
{
chars[i] = UPPER_CASE[chars[i]];
}
return new String( chars );
}
/**
* Rewrote the toLowercase method to improve performances.
* In Ldap, attributesType are supposed to use ASCII chars :
* 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
*
* @param value The String to uppercase
* @return The uppercase string
*/
public static String toUpperCaseAscii( String value )
{
if ( ( null == value ) || ( value.length() == 0 ) )
{
return "";
}
char[] chars = value.toCharArray();
for ( int i = 0; i < chars.length; i++ )
{
chars[i] = UPPER_CASE[chars[i]];
}
return new String( chars );
}
/**
* <p>
* Converts a String to upper case as per {@link String#toUpperCase( Locale )}.
* </p>
* <p>
* A <code>null</code> input String returns <code>null</code>.
* </p>
*
* <pre>
* StringUtils.upperCase(null) = null
* StringUtils.upperCase(&quot;&quot;) = &quot;&quot;
* StringUtils.upperCase(&quot;aBc&quot;) = &quot;ABC&quot;
* </pre>
*
* @param str the String to upper case, may be null
* @return the upper cased String, <code>null</code> if null String input
*/
public static String upperCase( String str )
{
if ( str == null )
{
return null;
}
return str.toUpperCase( Locale.ROOT );
}
/**
* <p>
* Converts a String to lower case as per {@link String#toLowerCase()}.
* </p>
* <p>
* A <code>null</code> input String returns <code>null</code>.
* </p>
*
* <pre>
* StringUtils.lowerCase(null) = null
* StringUtils.lowerCase(&quot;&quot;) = &quot;&quot;
* StringUtils.lowerCase(&quot;aBc&quot;) = &quot;abc&quot;
* </pre>
*
* @param str the String to lower case, may be null
* @return the lower cased String, <code>null</code> if null String input
*/
public static String lowerCase( String str )
{
if ( str == null )
{
return null;
}
return str.toLowerCase( Locale.ROOT );
}
/**
* Rewrote the toLowercase method to improve performances.
* In Ldap, attributesType are supposed to use ASCII chars :
* 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only. We will take
* care of any other chars either.
*
* @param str The String to lowercase
* @return The lowercase string
*/
public static String lowerCaseAscii( String str )
{
if ( str == null )
{
return null;
}
char[] chars = str.toCharArray();
int pos = 0;
for ( char c : chars )
{
chars[pos++] = TO_LOWER_CASE[c];
}
return new String( chars );
}
/**
*
* Check that a String is a valid PrintableString. A PrintableString contains only
* the following set of chars :
* { ' ', ''', '(', ')', '+', '-', '.', '/', [0-9], ':', '=', '?', [A-Z], [a-z]}
*
* @param str The String to check
* @return <code>true</code> if the string is a PrintableString or is empty,
* <code>false</code> otherwise
*/
public static boolean isPrintableString( String str )
{
if ( ( str == null ) || ( str.length() == 0 ) )
{
return true;
}
for ( char c : str.toCharArray() )
{
if ( ( c > 127 ) || !IS_PRINTABLE_CHAR[c] )
{
return false;
}
}
return true;
}
/**
* <p>
* Checks if a String is not empty ("") and not null.
* </p>
*
* <pre>
* StringUtils.isNotEmpty(null) = false
* StringUtils.isNotEmpty(&quot;&quot;) = false
* StringUtils.isNotEmpty(&quot; &quot;) = true
* StringUtils.isNotEmpty(&quot;bob&quot;) = true
* StringUtils.isNotEmpty(&quot; bob &quot;) = true
* </pre>
*
* @param str the String to check, may be null
* @return <code>true</code> if the String is not empty and not null
*/
public static boolean isNotEmpty( String str )
{
return ( str != null ) && ( str.length() > 0 );
}
/**
*
* Check that a String is a valid IA5String. An IA5String contains only
* char which values is between [0, 7F]
*
* @param str The String to check
* @return <code>true</code> if the string is an IA5String or is empty,
* <code>false</code> otherwise
*/
public static boolean isIA5String( String str )
{
if ( ( str == null ) || ( str.length() == 0 ) )
{
return true;
}
// All the chars must be in [0x00, 0x7F]
for ( char c : str.toCharArray() )
{
if ( ( c < 0 ) || ( c > 0x7F ) )
{
return false;
}
}
return true;
}
/**
* Checks to see if a String is a valid UUID.
*
* @param uuid the UUID to check for validity
* @return true if the UUID is valid, false otherwise
*/
public static boolean isValidUuid( String uuid )
{
if ( uuid.length() < 36 )
{
return false;
}
if ( isHex( uuid.charAt( 0 ) ) && isHex( uuid.charAt( 1 ) ) && isHex( uuid.charAt( 2 ) )
&& isHex( uuid.charAt( 3 ) ) && isHex( uuid.charAt( 4 ) ) && isHex( uuid.charAt( 5 ) )
&& isHex( uuid.charAt( 6 ) ) && isHex( uuid.charAt( 7 ) ) && ( uuid.charAt( 8 ) == '-' )
&& isHex( uuid.charAt( 9 ) ) && isHex( uuid.charAt( 10 ) ) && isHex( uuid.charAt( 11 ) )
&& isHex( uuid.charAt( 12 ) ) && ( uuid.charAt( 13 ) == '-' ) && isHex( uuid.charAt( 14 ) )
&& isHex( uuid.charAt( 15 ) ) && isHex( uuid.charAt( 16 ) ) && isHex( uuid.charAt( 17 ) )
&& ( uuid.charAt( 18 ) == '-' ) && isHex( uuid.charAt( 19 ) ) && isHex( uuid.charAt( 20 ) )
&& isHex( uuid.charAt( 21 ) ) && isHex( uuid.charAt( 22 ) ) && ( uuid.charAt( 23 ) == '-' )
&& isHex( uuid.charAt( 24 ) ) && isHex( uuid.charAt( 25 ) ) && isHex( uuid.charAt( 26 ) )
&& isHex( uuid.charAt( 27 ) ) && isHex( uuid.charAt( 28 ) ) && isHex( uuid.charAt( 29 ) )
&& isHex( uuid.charAt( 30 ) ) && isHex( uuid.charAt( 31 ) ) && isHex( uuid.charAt( 32 ) )
&& isHex( uuid.charAt( 33 ) ) && isHex( uuid.charAt( 34 ) ) && isHex( uuid.charAt( 35 ) ) )
{
// There is not that much more we can check.
if ( LOG.isDebugEnabled() )
{
LOG.debug( I18n.msg( I18n.MSG_17007_SYNTAX_VALID, uuid ) );
}
return true;
}
if ( LOG.isDebugEnabled() )
{
LOG.debug( I18n.msg( I18n.MSG_17008_SYNTAX_INVALID, uuid ) );
}
return false;
}
/**
* converts the bytes of a UUID to string
*
* @param bytes bytes of a UUID
* @return UUID in string format
*/
public static String uuidToString( byte[] bytes )
{
if ( ( bytes == null ) || ( bytes.length != 16 ) )
{
return "Invalid UUID";
}
char[] hex = encodeHex( bytes );
StringBuilder sb = new StringBuilder();
sb.append( hex, 0, 8 );
sb.append( '-' );
sb.append( hex, 8, 4 );
sb.append( '-' );
sb.append( hex, 12, 4 );
sb.append( '-' );
sb.append( hex, 16, 4 );
sb.append( '-' );
sb.append( hex, 20, 12 );
return Strings.toLowerCaseAscii( sb.toString() );
}
/**
* converts the string representation of an UUID to bytes
*
* @param string the string representation of an UUID
* @return the bytes, null if the the syntax is not valid
*/
public static byte[] uuidToBytes( String string )
{
if ( !isValidUuid( string ) )
{
return null;
}
char[] chars = string.toCharArray();
byte[] bytes = new byte[16];
bytes[0] = getHexValue( chars[0], chars[1] );
bytes[1] = getHexValue( chars[2], chars[3] );
bytes[2] = getHexValue( chars[4], chars[5] );
bytes[3] = getHexValue( chars[6], chars[7] );
bytes[4] = getHexValue( chars[9], chars[10] );
bytes[5] = getHexValue( chars[11], chars[12] );
bytes[6] = getHexValue( chars[14], chars[15] );
bytes[7] = getHexValue( chars[16], chars[17] );
bytes[8] = getHexValue( chars[19], chars[20] );
bytes[9] = getHexValue( chars[21], chars[22] );
bytes[10] = getHexValue( chars[24], chars[25] );
bytes[11] = getHexValue( chars[26], chars[27] );
bytes[12] = getHexValue( chars[28], chars[29] );
bytes[13] = getHexValue( chars[30], chars[31] );
bytes[14] = getHexValue( chars[32], chars[33] );
bytes[15] = getHexValue( chars[34], chars[35] );
return bytes;
}
/**
* Copy a byte array into a new byte array
*
* @param value the byte array to copy
* @return The copied byte array
*/
public static byte[] copy( byte[] value )
{
if ( isEmpty( value ) )
{
return EMPTY_BYTES;
}
byte[] copy = new byte[value.length];
System.arraycopy( value, 0, copy, 0, value.length );
return copy;
}
/**
* From commons-httpclients. Converts the byte array of HTTP content
* characters to a string. If the specified charset is not supported,
* default system encoding is used.
*
* @param data the byte array to be encoded
* @param offset the index of the first byte to encode
* @param length the number of bytes to encode
* @param charset the desired character encoding
* @return The result of the conversion.
* @since 3.0
*/
public static String getString( final byte[] data, int offset, int length, String charset )
{
if ( data == null )
{
throw new IllegalArgumentException( I18n.err( I18n.ERR_17028_PARAMETER_CANT_BE_NULL ) );
}
if ( ( charset == null ) || ( charset.length() == 0 ) )
{
throw new IllegalArgumentException( I18n.err( I18n.ERR_17029_CHARSET_CANT_BE_NULL ) );
}
try
{
return new String( data, offset, length, charset );
}
catch ( UnsupportedEncodingException e )
{
return new String( data, offset, length, Charset.defaultCharset() );
}
}
/**
* From commons-httpclients. Converts the byte array of HTTP content
* characters to a string. If the specified charset is not supported,
* default system encoding is used.
*
* @param data the byte array to be encoded
* @param offset the index of the first byte to encode
* @param length the number of bytes to encode
* @param charset the desired character encoding
* @return The result of the conversion.
* @since 3.0
*/
public static String getString( final byte[] data, int offset, int length, Charset charset )
{
if ( data == null )
{
throw new IllegalArgumentException( I18n.err( I18n.ERR_17028_PARAMETER_CANT_BE_NULL ) );
}
if ( charset == null )
{
throw new IllegalArgumentException( I18n.err( I18n.ERR_17029_CHARSET_CANT_BE_NULL ) );
}
return new String( data, offset, length, charset );
}
/**
* From commons-httpclients. Converts the byte array of HTTP content
* characters to a string. If the specified charset is not supported,
* default system encoding is used.
*
* @param data the byte array to be encoded
* @param charset the desired character encoding
* @return The result of the conversion.
* @since 3.0
*/
public static String getString( final byte[] data, String charset )
{
return getString( data, 0, data.length, charset );
}
/**
* From commons-httpclients. Converts the byte array of HTTP content
* characters to a string. If the specified charset is not supported,
* default system encoding is used.
*
* @param data the byte array to be encoded
* @param charset the desired character encoding
* @return The result of the conversion.
* @since 3.0
*/
public static String getString( final byte[] data, Charset charset )
{
return getString( data, 0, data.length, charset );
}
/**
* Create a new UUID using a long as the least significant bits
*
* @param value The least significant bits.
* @return The created UUID
*/
public static String getUUID( long value )
{
return new UUID( 0, value ).toString();
}
/**
* Past an ASCII String to a number
*
* @param value The string to parse
* @return the parsed value.
*/
public static int parseInt( String value )
{
long res = 0;
for ( char c : value.toCharArray() )
{
if ( ( c >= '0' ) && ( c <= '9' ) )
{
res = res * 10 + ( c - '0' );
if ( res > Integer.MAX_VALUE )
{
throw new NumberFormatException( I18n.err( I18n.ERR_17002_INTEGER_TOO_BIG, value ) );
}
}
else
{
throw new NumberFormatException( I18n.err( I18n.ERR_17003_INTEGER_INVALID, value ) );
}
}
return ( int ) res;
}
/**
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
* @param b1 The first byte[] to compare
* @param b2 The second byte[] to compare
* @return -1 if the first byte[] is inferior to the second one, 1 if teh first byte[]
* is superior to the second one, 0 if they are equal.
*/
public static int compare( byte[] b1, byte[] b2 )
{
if ( LOG.isDebugEnabled() )
{
LOG.debug( I18n.msg( I18n.MSG_17006_COMPARING_OBJECTSTRING,
Strings.dumpBytes( b1 ), Strings.dumpBytes( b2 ) ) );
}
// -------------------------------------------------------------------
// Handle some basis cases
// -------------------------------------------------------------------
if ( b1 == null )
{
return ( b2 == null ) ? 0 : -1;
}
if ( b2 == null )
{
return 1;
}
if ( b1.length == b2.length )
{
for ( int i = 0; i < b1.length; i++ )
{
if ( b1[i] > b2[i] )
{
return 1;
}
else if ( b1[i] < b2[i] )
{
return -1;
}
}
return 0;
}
int minLength = Math.min( b1.length, b2.length );
for ( int i = 0; i < minLength; i++ )
{
if ( b1[i] > b2[i] )
{
return 1;
}
else if ( b1[i] < b2[i] )
{
return -1;
}
}
// b2 is longer w/ b1 as prefix
if ( b1.length == minLength )
{
return -1;
}
// b1 is longer w/ b2 as prefix
if ( b2.length == minLength )
{
return 1;
}
return 0;
}
}