org.eclipse.jetty.util.StringUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jetty-util Show documentation
Show all versions of jetty-util Show documentation
Utility classes for Jetty
//
// ========================================================================
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/** Fast String Utilities.
*
* These string utilities provide both convenience methods and
* performance improvements over most standard library versions. The
* main aim of the optimizations is to avoid object creation unless
* absolutely required.
*
*
*/
public class StringUtil
{
private static final Logger LOG = Log.getLogger(StringUtil.class);
private final static Trie CHARSETS= new ArrayTrie<>(256);
public static final String ALL_INTERFACES="0.0.0.0";
public static final String CRLF="\015\012";
public static final String __LINE_SEPARATOR=
System.getProperty("line.separator","\n");
public static final String __ISO_8859_1="iso-8859-1";
public final static String __UTF8="utf-8";
public final static String __UTF16="utf-16";
static
{
CHARSETS.put("utf-8",__UTF8);
CHARSETS.put("utf8",__UTF8);
CHARSETS.put("utf-16",__UTF16);
CHARSETS.put("utf16",__UTF16);
CHARSETS.put("iso-8859-1",__ISO_8859_1);
CHARSETS.put("iso_8859_1",__ISO_8859_1);
}
/* ------------------------------------------------------------ */
/** Convert alternate charset names (eg utf8) to normalized
* name (eg UTF-8).
*/
public static String normalizeCharset(String s)
{
String n=CHARSETS.get(s);
return (n==null)?s:n;
}
/* ------------------------------------------------------------ */
/** Convert alternate charset names (eg utf8) to normalized
* name (eg UTF-8).
*/
public static String normalizeCharset(String s,int offset,int length)
{
String n=CHARSETS.get(s,offset,length);
return (n==null)?s.substring(offset,offset+length):n;
}
/* ------------------------------------------------------------ */
public static final char[] lowercases = {
'\000','\001','\002','\003','\004','\005','\006','\007',
'\010','\011','\012','\013','\014','\015','\016','\017',
'\020','\021','\022','\023','\024','\025','\026','\027',
'\030','\031','\032','\033','\034','\035','\036','\037',
'\040','\041','\042','\043','\044','\045','\046','\047',
'\050','\051','\052','\053','\054','\055','\056','\057',
'\060','\061','\062','\063','\064','\065','\066','\067',
'\070','\071','\072','\073','\074','\075','\076','\077',
'\100','\141','\142','\143','\144','\145','\146','\147',
'\150','\151','\152','\153','\154','\155','\156','\157',
'\160','\161','\162','\163','\164','\165','\166','\167',
'\170','\171','\172','\133','\134','\135','\136','\137',
'\140','\141','\142','\143','\144','\145','\146','\147',
'\150','\151','\152','\153','\154','\155','\156','\157',
'\160','\161','\162','\163','\164','\165','\166','\167',
'\170','\171','\172','\173','\174','\175','\176','\177' };
/* ------------------------------------------------------------ */
/**
* fast lower case conversion. Only works on ascii (not unicode)
* @param s the string to convert
* @return a lower case version of s
*/
public static String asciiToLowerCase(String s)
{
char[] c = null;
int i=s.length();
// look for first conversion
while (i-->0)
{
char c1=s.charAt(i);
if (c1<=127)
{
char c2=lowercases[c1];
if (c1!=c2)
{
c=s.toCharArray();
c[i]=c2;
break;
}
}
}
while (i-->0)
{
if(c[i]<=127)
c[i] = lowercases[c[i]];
}
return c==null?s:new String(c);
}
/* ------------------------------------------------------------ */
public static boolean startsWithIgnoreCase(String s,String w)
{
if (w==null)
return true;
if (s==null || s.length()0;)
{
char c1=s.charAt(--sl);
char c2=w.charAt(i);
if (c1!=c2)
{
if (c1<=127)
c1=lowercases[c1];
if (c2<=127)
c2=lowercases[c2];
if (c1!=c2)
return false;
}
}
return true;
}
/* ------------------------------------------------------------ */
/**
* returns the next index of a character from the chars string
*/
public static int indexFrom(String s,String chars)
{
for (int i=0;i=0)
return i;
return -1;
}
/* ------------------------------------------------------------ */
/**
* replace substrings within string.
*/
public static String replace(String s, String sub, String with)
{
int c=0;
int i=s.indexOf(sub,c);
if (i == -1)
return s;
StringBuilder buf = new StringBuilder(s.length()+with.length());
do
{
buf.append(s.substring(c,i));
buf.append(with);
c=i+sub.length();
} while ((i=s.indexOf(sub,c))!=-1);
if (c=s.length())
break;
buf.append(s.charAt(i));
}
}
}
/* ------------------------------------------------------------ */
/**
* append hex digit
*
*/
public static void append(StringBuilder buf,byte b,int base)
{
int bi=0xff&b;
int c='0'+(bi/base)%base;
if (c>'9')
c= 'a'+(c-'0'-10);
buf.append((char)c);
c='0'+bi%base;
if (c>'9')
c= 'a'+(c-'0'-10);
buf.append((char)c);
}
/* ------------------------------------------------------------ */
public static void append2digits(StringBuffer buf,int i)
{
if (i<100)
{
buf.append((char)(i/10+'0'));
buf.append((char)(i%10+'0'));
}
}
/* ------------------------------------------------------------ */
public static void append2digits(StringBuilder buf,int i)
{
if (i<100)
{
buf.append((char)(i/10+'0'));
buf.append((char)(i%10+'0'));
}
}
/* ------------------------------------------------------------ */
/** Return a non null string.
* @param s String
* @return The string passed in or empty string if it is null.
*/
public static String nonNull(String s)
{
if (s==null)
return "";
return s;
}
/* ------------------------------------------------------------ */
public static boolean equals(String s,char[] buf, int offset, int length)
{
if (s.length()!=length)
return false;
for (int i=0;i
* Note: uses codepoint version of {@link Character#isWhitespace(int)} to support Unicode better.
*
*
* isBlank(null) == true
* isBlank("") == true
* isBlank("\r\n") == true
* isBlank("\t") == true
* isBlank(" ") == true
* isBlank("a") == false
* isBlank(".") == false
* isBlank(";\n") == false
*
*
* @param str
* the string to test.
* @return true if string is null or only whitespace characters, false if non-whitespace characters encountered.
*/
public static boolean isBlank(String str)
{
if (str == null)
{
return true;
}
int len = str.length();
for (int i = 0; i < len; i++)
{
if (!Character.isWhitespace(str.codePointAt(i)))
{
// found a non-whitespace, we can stop searching now
return false;
}
}
// only whitespace
return true;
}
/* ------------------------------------------------------------ */
/**
* Test if a string is not null and contains at least 1 non-whitespace characters in it.
*
* Note: uses codepoint version of {@link Character#isWhitespace(int)} to support Unicode better.
*
*
* isNotBlank(null) == false
* isNotBlank("") == false
* isNotBlank("\r\n") == false
* isNotBlank("\t") == false
* isNotBlank(" ") == false
* isNotBlank("a") == true
* isNotBlank(".") == true
* isNotBlank(";\n") == true
*
*
* @param str
* the string to test.
* @return true if string is not null and has at least 1 non-whitespace character, false if null or all-whitespace characters.
*/
public static boolean isNotBlank(String str)
{
if (str == null)
{
return false;
}
int len = str.length();
for (int i = 0; i < len; i++)
{
if (!Character.isWhitespace(str.codePointAt(i)))
{
// found a non-whitespace, we can stop searching now
return true;
}
}
// only whitespace
return false;
}
/* ------------------------------------------------------------ */
public static boolean isUTF8(String charset)
{
return __UTF8.equalsIgnoreCase(charset)||__UTF8.equalsIgnoreCase(normalizeCharset(charset));
}
/* ------------------------------------------------------------ */
public static String printable(String name)
{
if (name==null)
return null;
StringBuilder buf = new StringBuilder(name.length());
for (int i=0;i' ' && c<0x7f)
buf.append(c);
else
{
buf.append("0x");
TypeUtil.toHex(b[i],buf);
}
}
return buf.toString();
}
public static byte[] getBytes(String s)
{
return s.getBytes(StandardCharsets.ISO_8859_1);
}
public static byte[] getUtf8Bytes(String s)
{
return s.getBytes(StandardCharsets.UTF_8);
}
public static byte[] getBytes(String s,String charset)
{
try
{
return s.getBytes(charset);
}
catch(Exception e)
{
LOG.warn(e);
return s.getBytes();
}
}
/**
* Converts a binary SID to a string SID
*
* http://en.wikipedia.org/wiki/Security_Identifier
*
* S-1-IdentifierAuthority-SubAuthority1-SubAuthority2-...-SubAuthorityn
*/
public static String sidBytesToString(byte[] sidBytes)
{
StringBuilder sidString = new StringBuilder();
// Identify this as a SID
sidString.append("S-");
// Add SID revision level (expect 1 but may change someday)
sidString.append(Byte.toString(sidBytes[0])).append('-');
StringBuilder tmpBuilder = new StringBuilder();
// crunch the six bytes of issuing authority value
for (int i = 2; i <= 7; ++i)
{
tmpBuilder.append(Integer.toHexString(sidBytes[i] & 0xFF));
}
sidString.append(Long.parseLong(tmpBuilder.toString(), 16)); // '-' is in the subauth loop
// the number of subAuthorities we need to attach
int subAuthorityCount = sidBytes[1];
// attach each of the subAuthorities
for (int i = 0; i < subAuthorityCount; ++i)
{
int offset = i * 4;
tmpBuilder.setLength(0);
// these need to be zero padded hex and little endian
tmpBuilder.append(String.format("%02X%02X%02X%02X",
(sidBytes[11 + offset] & 0xFF),
(sidBytes[10 + offset] & 0xFF),
(sidBytes[9 + offset] & 0xFF),
(sidBytes[8 + offset] & 0xFF)));
sidString.append('-').append(Long.parseLong(tmpBuilder.toString(), 16));
}
return sidString.toString();
}
/**
* Converts a string SID to a binary SID
*
* http://en.wikipedia.org/wiki/Security_Identifier
*
* S-1-IdentifierAuthority-SubAuthority1-SubAuthority2-...-SubAuthorityn
*/
public static byte[] sidStringToBytes( String sidString )
{
String[] sidTokens = sidString.split("-");
int subAuthorityCount = sidTokens.length - 3; // S-Rev-IdAuth-
int byteCount = 0;
byte[] sidBytes = new byte[1 + 1 + 6 + (4 * subAuthorityCount)];
// the revision byte
sidBytes[byteCount++] = (byte)Integer.parseInt(sidTokens[1]);
// the # of sub authorities byte
sidBytes[byteCount++] = (byte)subAuthorityCount;
// the certAuthority
String hexStr = Long.toHexString(Long.parseLong(sidTokens[2]));
while( hexStr.length() < 12) // pad to 12 characters
{
hexStr = "0" + hexStr;
}
// place the certAuthority 6 bytes
for ( int i = 0 ; i < hexStr.length(); i = i + 2)
{
sidBytes[byteCount++] = (byte)Integer.parseInt(hexStr.substring(i, i + 2),16);
}
for ( int i = 3; i < sidTokens.length ; ++i)
{
hexStr = Long.toHexString(Long.parseLong(sidTokens[i]));
while( hexStr.length() < 8) // pad to 8 characters
{
hexStr = "0" + hexStr;
}
// place the inverted sub authorities, 4 bytes each
for ( int j = hexStr.length(); j > 0; j = j - 2)
{
sidBytes[byteCount++] = (byte)Integer.parseInt(hexStr.substring(j-2, j),16);
}
}
return sidBytes;
}
/**
* Convert String to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
*
* @param string A String containing an integer.
* @param from The index to start parsing from
* @return an int
*/
public static int toInt(String string,int from)
{
int val = 0;
boolean started = false;
boolean minus = false;
for (int i = from; i < string.length(); i++)
{
char b = string.charAt(i);
if (b <= ' ')
{
if (started)
break;
}
else if (b >= '0' && b <= '9')
{
val = val * 10 + (b - '0');
started = true;
}
else if (b == '-' && !started)
{
minus = true;
}
else
break;
}
if (started)
return minus?(-val):val;
throw new NumberFormatException(string);
}
/**
* Convert String to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
*
* @param string
* A String containing an integer.
* @return an int
*/
public static long toLong(String string)
{
long val = 0;
boolean started = false;
boolean minus = false;
for (int i = 0; i < string.length(); i++)
{
char b = string.charAt(i);
if (b <= ' ')
{
if (started)
break;
}
else if (b >= '0' && b <= '9')
{
val = val * 10L + (b - '0');
started = true;
}
else if (b == '-' && !started)
{
minus = true;
}
else
break;
}
if (started)
return minus?(-val):val;
throw new NumberFormatException(string);
}
/**
* Truncate a string to a max size.
*
* @param str the string to possibly truncate
* @param maxSize the maximum size of the string
* @return the truncated string. if str
param is null, then the returned string will also be null.
*/
public static String truncate(String str, int maxSize)
{
if (str == null)
{
return null;
}
if (str.length() <= maxSize)
{
return str;
}
return str.substring(0,maxSize);
}
public static String[] arrayFromString(String s)
{
if (s==null)
return new String[]{};
if (!s.startsWith("[") || !s.endsWith("]"))
throw new IllegalArgumentException();
if (s.length()==2)
return new String[]{};
return s.substring(1,s.length()-1).split(" *, *");
}
}