001: // ========================================================================
002: // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
003: // ------------------------------------------------------------------------
004: // Licensed under the Apache License, Version 2.0 (the "License");
005: // you may not use this file except in compliance with the License.
006: // You may obtain a copy of the License at
007: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014:
015: package org.mortbay.util;
016:
017: import java.io.UnsupportedEncodingException;
018:
019: // ====================================================================
020: /** Fast String Utilities.
021: *
022: * These string utilities provide both conveniance methods and
023: * performance improvements over most standard library versions. The
024: * main aim of the optimizations is to avoid object creation unless
025: * absolutely required.
026: *
027: * @author Greg Wilkins (gregw)
028: */
029: public class StringUtil {
030: public static final String CRLF = "\015\012";
031: public static final String __LINE_SEPARATOR = System.getProperty(
032: "line.separator", "\n");
033:
034: public static String __ISO_8859_1;
035: static {
036: String iso = System.getProperty("ISO_8859_1");
037: if (iso != null)
038: __ISO_8859_1 = iso;
039: else {
040: try {
041: new String(new byte[] { (byte) 20 }, "ISO-8859-1");
042: __ISO_8859_1 = "ISO-8859-1";
043: } catch (java.io.UnsupportedEncodingException e) {
044: __ISO_8859_1 = "ISO8859_1";
045: }
046: }
047: }
048:
049: public final static String __UTF8 = "UTF-8";
050:
051: private static char[] lowercases = { '\000', '\001', '\002',
052: '\003', '\004', '\005', '\006', '\007', '\010', '\011',
053: '\012', '\013', '\014', '\015', '\016', '\017', '\020',
054: '\021', '\022', '\023', '\024', '\025', '\026', '\027',
055: '\030', '\031', '\032', '\033', '\034', '\035', '\036',
056: '\037', '\040', '\041', '\042', '\043', '\044', '\045',
057: '\046', '\047', '\050', '\051', '\052', '\053', '\054',
058: '\055', '\056', '\057', '\060', '\061', '\062', '\063',
059: '\064', '\065', '\066', '\067', '\070', '\071', '\072',
060: '\073', '\074', '\075', '\076', '\077', '\100', '\141',
061: '\142', '\143', '\144', '\145', '\146', '\147', '\150',
062: '\151', '\152', '\153', '\154', '\155', '\156', '\157',
063: '\160', '\161', '\162', '\163', '\164', '\165', '\166',
064: '\167', '\170', '\171', '\172', '\133', '\134', '\135',
065: '\136', '\137', '\140', '\141', '\142', '\143', '\144',
066: '\145', '\146', '\147', '\150', '\151', '\152', '\153',
067: '\154', '\155', '\156', '\157', '\160', '\161', '\162',
068: '\163', '\164', '\165', '\166', '\167', '\170', '\171',
069: '\172', '\173', '\174', '\175', '\176', '\177' };
070:
071: /* ------------------------------------------------------------ */
072: /**
073: * fast lower case conversion. Only works on ascii (not unicode)
074: * @param s the string to convert
075: * @return a lower case version of s
076: */
077: public static String asciiToLowerCase(String s) {
078: char[] c = null;
079: int i = s.length();
080:
081: // look for first conversion
082: while (i-- > 0) {
083: char c1 = s.charAt(i);
084: if (c1 <= 127) {
085: char c2 = lowercases[c1];
086: if (c1 != c2) {
087: c = s.toCharArray();
088: c[i] = c2;
089: break;
090: }
091: }
092: }
093:
094: while (i-- > 0) {
095: if (c[i] <= 127)
096: c[i] = lowercases[c[i]];
097: }
098:
099: return c == null ? s : new String(c);
100: }
101:
102: /* ------------------------------------------------------------ */
103: public static boolean startsWithIgnoreCase(String s, String w) {
104: if (w == null)
105: return true;
106:
107: if (s == null || s.length() < w.length())
108: return false;
109:
110: for (int i = 0; i < w.length(); i++) {
111: char c1 = s.charAt(i);
112: char c2 = w.charAt(i);
113: if (c1 != c2) {
114: if (c1 <= 127)
115: c1 = lowercases[c1];
116: if (c2 <= 127)
117: c2 = lowercases[c2];
118: if (c1 != c2)
119: return false;
120: }
121: }
122: return true;
123: }
124:
125: /* ------------------------------------------------------------ */
126: public static boolean endsWithIgnoreCase(String s, String w) {
127: if (w == null)
128: return true;
129:
130: if (s == null)
131: return false;
132:
133: int sl = s.length();
134: int wl = w.length();
135:
136: if (sl < wl)
137: return false;
138:
139: for (int i = wl; i-- > 0;) {
140: char c1 = s.charAt(--sl);
141: char c2 = w.charAt(i);
142: if (c1 != c2) {
143: if (c1 <= 127)
144: c1 = lowercases[c1];
145: if (c2 <= 127)
146: c2 = lowercases[c2];
147: if (c1 != c2)
148: return false;
149: }
150: }
151: return true;
152: }
153:
154: /* ------------------------------------------------------------ */
155: /**
156: * returns the next index of a character from the chars string
157: */
158: public static int indexFrom(String s, String chars) {
159: for (int i = 0; i < s.length(); i++)
160: if (chars.indexOf(s.charAt(i)) >= 0)
161: return i;
162: return -1;
163: }
164:
165: /* ------------------------------------------------------------ */
166: /**
167: * replace substrings within string.
168: */
169: public static String replace(String s, String sub, String with) {
170: int c = 0;
171: int i = s.indexOf(sub, c);
172: if (i == -1)
173: return s;
174:
175: StringBuffer buf = new StringBuffer(s.length() + with.length());
176:
177: synchronized (buf) {
178: do {
179: buf.append(s.substring(c, i));
180: buf.append(with);
181: c = i + sub.length();
182: } while ((i = s.indexOf(sub, c)) != -1);
183:
184: if (c < s.length())
185: buf.append(s.substring(c, s.length()));
186:
187: return buf.toString();
188: }
189: }
190:
191: /* ------------------------------------------------------------ */
192: /** Remove single or double quotes.
193: */
194: public static String unquote(String s) {
195: return QuotedStringTokenizer.unquote(s);
196: }
197:
198: /* ------------------------------------------------------------ */
199: /** Append substring to StringBuffer
200: * @param buf StringBuffer to append to
201: * @param s String to append from
202: * @param offset The offset of the substring
203: * @param length The length of the substring
204: */
205: public static void append(StringBuffer buf, String s, int offset,
206: int length) {
207: synchronized (buf) {
208: int end = offset + length;
209: for (int i = offset; i < end; i++) {
210: if (i >= s.length())
211: break;
212: buf.append(s.charAt(i));
213: }
214: }
215: }
216:
217: /* ------------------------------------------------------------ */
218: /**
219: * append hex digit
220: *
221: */
222: public static void append(StringBuffer buf, byte b, int base) {
223: int bi = 0xff & b;
224: int c = '0' + (bi / base) % base;
225: if (c > '9')
226: c = 'a' + (c - '0' - 10);
227: buf.append((char) c);
228: c = '0' + bi % base;
229: if (c > '9')
230: c = 'a' + (c - '0' - 10);
231: buf.append((char) c);
232: }
233:
234: /* ------------------------------------------------------------ */
235: public static void append2digits(StringBuffer buf, int i) {
236: if (i < 100) {
237: buf.append((char) (i / 10 + '0'));
238: buf.append((char) (i % 10 + '0'));
239: }
240: }
241:
242: /* ------------------------------------------------------------ */
243: /** Return a non null string.
244: * @param s String
245: * @return The string passed in or empty string if it is null.
246: */
247: public static String nonNull(String s) {
248: if (s == null)
249: return "";
250: return s;
251: }
252:
253: /* ------------------------------------------------------------ */
254: public static boolean equals(String s, char[] buf, int offset,
255: int length) {
256: if (s.length() != length)
257: return false;
258: for (int i = 0; i < length; i++)
259: if (buf[offset + i] != s.charAt(i))
260: return false;
261: return true;
262: }
263:
264: /* ------------------------------------------------------------ */
265: public static String toUTF8String(byte[] b, int offset, int length) {
266: try {
267: if (length < 32) {
268: Utf8StringBuffer buffer = new Utf8StringBuffer(length);
269: buffer.append(b, offset, length);
270: return buffer.toString();
271: }
272:
273: return new String(b, offset, length, __UTF8);
274: } catch (UnsupportedEncodingException e) {
275: e.printStackTrace();
276: return null;
277: }
278: }
279:
280: /* ------------------------------------------------------------ */
281: public static String toString(byte[] b, int offset, int length,
282: String charset) {
283: if (charset == null || StringUtil.isUTF8(charset))
284: return toUTF8String(b, offset, length);
285:
286: try {
287: return new String(b, offset, length, charset);
288: } catch (UnsupportedEncodingException e) {
289: e.printStackTrace();
290: return null;
291: }
292: }
293:
294: /* ------------------------------------------------------------ */
295: public static boolean isUTF8(String charset) {
296: return charset == __UTF8 || __UTF8.equalsIgnoreCase(charset);
297: }
298:
299: }
|