3 *******************************************************************************
4 * Copyright (C) 1996-2009, International Business Machines Corporation and *
5 * others. All Rights Reserved. *
6 *******************************************************************************
8 package com.ibm.icu.impl;
10 import java.util.ArrayList;
12 import com.ibm.icu.lang.*;
13 import com.ibm.icu.text.*;
14 import com.ibm.icu.impl.UCharacterProperty;
16 public final class Utility {
18 private static final char APOSTROPHE = '\'';
19 private static final char BACKSLASH = '\\';
20 private static final int MAGIC_UNSIGNED = 0x80000000;
23 * Convenience utility to compare two Object[]s.
24 * Ought to be in System
26 public final static boolean arrayEquals(Object[] source, Object target) {
27 if (source == null) return (target == null);
28 if (!(target instanceof Object[])) return false;
29 Object[] targ = (Object[]) target;
30 return (source.length == targ.length
31 && arrayRegionMatches(source, 0, targ, 0, source.length));
35 * Convenience utility to compare two int[]s
36 * Ought to be in System
38 public final static boolean arrayEquals(int[] source, Object target) {
39 if (source == null) return (target == null);
40 if (!(target instanceof int[])) return false;
41 int[] targ = (int[]) target;
42 return (source.length == targ.length
43 && arrayRegionMatches(source, 0, targ, 0, source.length));
47 * Convenience utility to compare two double[]s
48 * Ought to be in System
50 public final static boolean arrayEquals(double[] source, Object target) {
51 if (source == null) return (target == null);
52 if (!(target instanceof double[])) return false;
53 double[] targ = (double[]) target;
54 return (source.length == targ.length
55 && arrayRegionMatches(source, 0, targ, 0, source.length));
57 public final static boolean arrayEquals(byte[] source, Object target) {
58 if (source == null) return (target == null);
59 if (!(target instanceof byte[])) return false;
60 byte[] targ = (byte[]) target;
61 return (source.length == targ.length
62 && arrayRegionMatches(source, 0, targ, 0, source.length));
66 * Convenience utility to compare two Object[]s
67 * Ought to be in System
69 public final static boolean arrayEquals(Object source, Object target) {
70 if (source == null) return (target == null);
71 // for some reason, the correct arrayEquals is not being called
72 // so do it by hand for now.
73 if (source instanceof Object[])
74 return(arrayEquals((Object[]) source,target));
75 if (source instanceof int[])
76 return(arrayEquals((int[]) source,target));
77 if (source instanceof double[])
78 return(arrayEquals((int[]) source,target));
79 if (source instanceof byte[])
80 return(arrayEquals((byte[]) source,target));
81 return source.equals(target);
85 * Convenience utility to compare two Object[]s
86 * Ought to be in System.
87 * @param len the length to compare.
88 * The start indices and start+len must be valid.
90 public final static boolean arrayRegionMatches(Object[] source, int sourceStart,
91 Object[] target, int targetStart,
94 int sourceEnd = sourceStart + len;
95 int delta = targetStart - sourceStart;
96 for (int i = sourceStart; i < sourceEnd; i++) {
97 if (!arrayEquals(source[i],target[i + delta]))
104 * Convenience utility to compare two Object[]s
105 * Ought to be in System.
106 * @param len the length to compare.
107 * The start indices and start+len must be valid.
109 public final static boolean arrayRegionMatches(char[] source, int sourceStart,
110 char[] target, int targetStart,
113 int sourceEnd = sourceStart + len;
114 int delta = targetStart - sourceStart;
115 for (int i = sourceStart; i < sourceEnd; i++) {
116 if (source[i]!=target[i + delta])
123 * Convenience utility to compare two int[]s.
124 * @param len the length to compare.
125 * The start indices and start+len must be valid.
126 * Ought to be in System
128 public final static boolean arrayRegionMatches(int[] source, int sourceStart,
129 int[] target, int targetStart,
132 int sourceEnd = sourceStart + len;
133 int delta = targetStart - sourceStart;
134 for (int i = sourceStart; i < sourceEnd; i++) {
135 if (source[i] != target[i + delta])
142 * Convenience utility to compare two arrays of doubles.
143 * @param len the length to compare.
144 * The start indices and start+len must be valid.
145 * Ought to be in System
147 public final static boolean arrayRegionMatches(double[] source, int sourceStart,
148 double[] target, int targetStart,
151 int sourceEnd = sourceStart + len;
152 int delta = targetStart - sourceStart;
153 for (int i = sourceStart; i < sourceEnd; i++) {
154 if (source[i] != target[i + delta])
159 public final static boolean arrayRegionMatches(byte[] source, int sourceStart,
160 byte[] target, int targetStart, int len){
161 int sourceEnd = sourceStart + len;
162 int delta = targetStart - sourceStart;
163 for (int i = sourceStart; i < sourceEnd; i++) {
164 if (source[i] != target[i + delta])
171 * Convenience utility. Does null checks on objects, then calls equals.
173 public final static boolean objectEquals(Object source, Object target) {
175 return (target == null);
177 return source.equals(target);
181 * The ESCAPE character is used during run-length encoding. It signals
182 * a run of identical chars.
184 private static final char ESCAPE = '\uA5A5';
187 * The ESCAPE_BYTE character is used during run-length encoding. It signals
188 * a run of identical bytes.
190 static final byte ESCAPE_BYTE = (byte)0xA5;
193 * Construct a string representing an int array. Use run-length encoding.
194 * A character represents itself, unless it is the ESCAPE character. Then
195 * the following notations are possible:
196 * ESCAPE ESCAPE ESCAPE literal
197 * ESCAPE n c n instances of character c
198 * Since an encoded run occupies 3 characters, we only encode runs of 4 or
199 * more characters. Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF.
200 * If we encounter a run where n == ESCAPE, we represent this as:
202 * The ESCAPE value is chosen so as not to collide with commonly
205 static public final String arrayToRLEString(int[] a) {
206 StringBuffer buffer = new StringBuffer();
208 appendInt(buffer, a.length);
211 for (int i=1; i<a.length; ++i) {
213 if (s == runValue && runLength < 0xFFFF) {
216 encodeRun(buffer, runValue, runLength);
221 encodeRun(buffer, runValue, runLength);
222 return buffer.toString();
226 * Construct a string representing a short array. Use run-length encoding.
227 * A character represents itself, unless it is the ESCAPE character. Then
228 * the following notations are possible:
229 * ESCAPE ESCAPE ESCAPE literal
230 * ESCAPE n c n instances of character c
231 * Since an encoded run occupies 3 characters, we only encode runs of 4 or
232 * more characters. Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF.
233 * If we encounter a run where n == ESCAPE, we represent this as:
235 * The ESCAPE value is chosen so as not to collide with commonly
238 static public final String arrayToRLEString(short[] a) {
239 StringBuffer buffer = new StringBuffer();
240 // for (int i=0; i<a.length; ++i) buffer.append((char) a[i]);
241 buffer.append((char) (a.length >> 16));
242 buffer.append((char) a.length);
243 short runValue = a[0];
245 for (int i=1; i<a.length; ++i) {
247 if (s == runValue && runLength < 0xFFFF) ++runLength;
249 encodeRun(buffer, runValue, runLength);
254 encodeRun(buffer, runValue, runLength);
255 return buffer.toString();
259 * Construct a string representing a char array. Use run-length encoding.
260 * A character represents itself, unless it is the ESCAPE character. Then
261 * the following notations are possible:
262 * ESCAPE ESCAPE ESCAPE literal
263 * ESCAPE n c n instances of character c
264 * Since an encoded run occupies 3 characters, we only encode runs of 4 or
265 * more characters. Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF.
266 * If we encounter a run where n == ESCAPE, we represent this as:
268 * The ESCAPE value is chosen so as not to collide with commonly
271 static public final String arrayToRLEString(char[] a) {
272 StringBuffer buffer = new StringBuffer();
273 buffer.append((char) (a.length >> 16));
274 buffer.append((char) a.length);
275 char runValue = a[0];
277 for (int i=1; i<a.length; ++i) {
279 if (s == runValue && runLength < 0xFFFF) ++runLength;
281 encodeRun(buffer, (short)runValue, runLength);
286 encodeRun(buffer, (short)runValue, runLength);
287 return buffer.toString();
291 * Construct a string representing a byte array. Use run-length encoding.
292 * Two bytes are packed into a single char, with a single extra zero byte at
293 * the end if needed. A byte represents itself, unless it is the
294 * ESCAPE_BYTE. Then the following notations are possible:
295 * ESCAPE_BYTE ESCAPE_BYTE ESCAPE_BYTE literal
296 * ESCAPE_BYTE n b n instances of byte b
297 * Since an encoded run occupies 3 bytes, we only encode runs of 4 or
298 * more bytes. Thus we have n > 0 and n != ESCAPE_BYTE and n <= 0xFF.
299 * If we encounter a run where n == ESCAPE_BYTE, we represent this as:
300 * b ESCAPE_BYTE n-1 b
301 * The ESCAPE_BYTE value is chosen so as not to collide with commonly
304 static public final String arrayToRLEString(byte[] a) {
305 StringBuffer buffer = new StringBuffer();
306 buffer.append((char) (a.length >> 16));
307 buffer.append((char) a.length);
308 byte runValue = a[0];
310 byte[] state = new byte[2];
311 for (int i=1; i<a.length; ++i) {
313 if (b == runValue && runLength < 0xFF) ++runLength;
315 encodeRun(buffer, runValue, runLength, state);
320 encodeRun(buffer, runValue, runLength, state);
322 // We must save the final byte, if there is one, by padding
324 if (state[0] != 0) appendEncodedByte(buffer, (byte)0, state);
326 return buffer.toString();
330 * Encode a run, possibly a degenerate run (of < 4 values).
331 * @param length The length of the run; must be > 0 && <= 0xFFFF.
333 private static final void encodeRun(StringBuffer buffer, int value, int length) {
335 for (int j=0; j<length; ++j) {
336 if (value == ESCAPE) {
337 appendInt(buffer, value);
339 appendInt(buffer, value);
343 if (length == (int) ESCAPE) {
344 if (value == (int) ESCAPE) {
345 appendInt(buffer, ESCAPE);
347 appendInt(buffer, value);
350 appendInt(buffer, ESCAPE);
351 appendInt(buffer, length);
352 appendInt(buffer, value); // Don't need to escape this value
356 private static final void appendInt(StringBuffer buffer, int value) {
357 buffer.append((char)(value >>> 16));
358 buffer.append((char)(value & 0xFFFF));
362 * Encode a run, possibly a degenerate run (of < 4 values).
363 * @param length The length of the run; must be > 0 && <= 0xFFFF.
365 private static final void encodeRun(StringBuffer buffer, short value, int length) {
367 for (int j=0; j<length; ++j) {
368 if (value == (int) ESCAPE) buffer.append(ESCAPE);
369 buffer.append((char) value);
373 if (length == (int) ESCAPE) {
374 if (value == (int) ESCAPE) buffer.append(ESCAPE);
375 buffer.append((char) value);
378 buffer.append(ESCAPE);
379 buffer.append((char) length);
380 buffer.append((char) value); // Don't need to escape this value
385 * Encode a run, possibly a degenerate run (of < 4 values).
386 * @param length The length of the run; must be > 0 && <= 0xFF.
388 private static final void encodeRun(StringBuffer buffer, byte value, int length,
391 for (int j=0; j<length; ++j) {
392 if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
393 appendEncodedByte(buffer, value, state);
397 if (length == ESCAPE_BYTE) {
398 if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
399 appendEncodedByte(buffer, value, state);
402 appendEncodedByte(buffer, ESCAPE_BYTE, state);
403 appendEncodedByte(buffer, (byte)length, state);
404 appendEncodedByte(buffer, value, state); // Don't need to escape this value
409 * Append a byte to the given StringBuffer, packing two bytes into each
410 * character. The state parameter maintains intermediary data between
412 * @param state A two-element array, with state[0] == 0 if this is the
413 * first byte of a pair, or state[0] != 0 if this is the second byte
414 * of a pair, in which case state[1] is the first byte.
416 private static final void appendEncodedByte(StringBuffer buffer, byte value,
419 char c = (char) ((state[1] << 8) | (((int) value) & 0xFF));
430 * Construct an array of ints from a run-length encoded string.
432 static public final int[] RLEStringToIntArray(String s) {
433 int length = getInt(s, 0);
434 int[] array = new int[length];
437 int maxI = s.length() / 2;
438 while (ai < length && i < maxI) {
439 int c = getInt(s, i++);
447 int runValue = getInt(s, i++);
448 for (int j=0; j<runLength; ++j) {
449 array[ai++] = runValue;
458 if (ai != length || i != maxI) {
459 throw new IllegalStateException("Bad run-length encoded int array");
464 static final int getInt(String s, int i) {
465 return (((int) s.charAt(2*i)) << 16) | (int) s.charAt(2*i+1);
469 * Construct an array of shorts from a run-length encoded string.
471 static public final short[] RLEStringToShortArray(String s) {
472 int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
473 short[] array = new short[length];
475 for (int i=2; i<s.length(); ++i) {
476 char c = s.charAt(i);
480 array[ai++] = (short) c;
482 int runLength = (int) c;
483 short runValue = (short) s.charAt(++i);
484 for (int j=0; j<runLength; ++j) array[ai++] = runValue;
488 array[ai++] = (short) c;
493 throw new IllegalStateException("Bad run-length encoded short array");
499 * Construct an array of shorts from a run-length encoded string.
501 static public final char[] RLEStringToCharArray(String s) {
502 int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
503 char[] array = new char[length];
505 for (int i=2; i<s.length(); ++i) {
506 char c = s.charAt(i);
512 int runLength = (int) c;
513 char runValue = s.charAt(++i);
514 for (int j=0; j<runLength; ++j) array[ai++] = runValue;
523 throw new IllegalStateException("Bad run-length encoded short array");
529 * Construct an array of bytes from a run-length encoded string.
531 static public final byte[] RLEStringToByteArray(String s) {
532 int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
533 byte[] array = new byte[length];
534 boolean nextChar = true;
539 for (int ai=0; ai<length; ) {
540 // This part of the loop places the next byte into the local
541 // variable 'b' each time through the loop. It keeps the
542 // current character in 'c' and uses the boolean 'nextChar'
543 // to see if we've taken both bytes out of 'c' yet.
551 b = (byte) (c & 0xFF);
555 // This part of the loop is a tiny state machine which handles
556 // the parsing of the run-length encoding. This would be simpler
557 // if we could look ahead, but we can't, so we use 'node' to
558 // move between three nodes in the state machine.
562 if (b == ESCAPE_BYTE) {
570 // We have seen one ESCAPE_BYTE; we expect either a second
571 // one, or a run length and value.
572 if (b == ESCAPE_BYTE) {
573 array[ai++] = ESCAPE_BYTE;
578 // Interpret signed byte as unsigned
579 if (runLength < 0) runLength += 0x100;
584 // We have seen an ESCAPE_BYTE and length byte. We interpret
585 // the next byte as the value to be repeated.
586 for (int j=0; j<runLength; ++j) array[ai++] = b;
593 throw new IllegalStateException("Bad run-length encoded byte array");
596 throw new IllegalStateException("Excess data in RLE byte array string");
601 static public String LINE_SEPARATOR = System.getProperty("line.separator");
604 * Format a String for representation in a source file. This includes
605 * breaking it into lines and escaping characters using octal notation
606 * when necessary (control characters and double quotes).
608 static public final String formatForSource(String s) {
609 StringBuffer buffer = new StringBuffer();
610 for (int i=0; i<s.length();) {
611 if (i > 0) buffer.append('+').append(LINE_SEPARATOR);
612 buffer.append(" \"");
614 while (i<s.length() && count<80) {
615 char c = s.charAt(i++);
616 if (c < '\u0020' || c == '"' || c == '\\') {
618 buffer.append("\\n");
620 } else if (c == '\t') {
621 buffer.append("\\t");
623 } else if (c == '\r') {
624 buffer.append("\\r");
627 // Represent control characters, backslash and double quote
628 // using octal notation; otherwise the string we form
629 // won't compile, since Unicode escape sequences are
630 // processed before tokenization.
632 buffer.append(HEX_DIGIT[(c & 0700) >> 6]); // HEX_DIGIT works for octal
633 buffer.append(HEX_DIGIT[(c & 0070) >> 3]);
634 buffer.append(HEX_DIGIT[(c & 0007)]);
638 else if (c <= '\u007E') {
643 buffer.append("\\u");
644 buffer.append(HEX_DIGIT[(c & 0xF000) >> 12]);
645 buffer.append(HEX_DIGIT[(c & 0x0F00) >> 8]);
646 buffer.append(HEX_DIGIT[(c & 0x00F0) >> 4]);
647 buffer.append(HEX_DIGIT[(c & 0x000F)]);
653 return buffer.toString();
656 static final char[] HEX_DIGIT = {'0','1','2','3','4','5','6','7',
657 '8','9','A','B','C','D','E','F'};
660 * Format a String for representation in a source file. Like
661 * formatForSource but does not do line breaking.
663 static public final String format1ForSource(String s) {
664 StringBuffer buffer = new StringBuffer();
666 for (int i=0; i<s.length();) {
667 char c = s.charAt(i++);
668 if (c < '\u0020' || c == '"' || c == '\\') {
670 buffer.append("\\n");
671 } else if (c == '\t') {
672 buffer.append("\\t");
673 } else if (c == '\r') {
674 buffer.append("\\r");
676 // Represent control characters, backslash and double quote
677 // using octal notation; otherwise the string we form
678 // won't compile, since Unicode escape sequences are
679 // processed before tokenization.
681 buffer.append(HEX_DIGIT[(c & 0700) >> 6]); // HEX_DIGIT works for octal
682 buffer.append(HEX_DIGIT[(c & 0070) >> 3]);
683 buffer.append(HEX_DIGIT[(c & 0007)]);
686 else if (c <= '\u007E') {
690 buffer.append("\\u");
691 buffer.append(HEX_DIGIT[(c & 0xF000) >> 12]);
692 buffer.append(HEX_DIGIT[(c & 0x0F00) >> 8]);
693 buffer.append(HEX_DIGIT[(c & 0x00F0) >> 4]);
694 buffer.append(HEX_DIGIT[(c & 0x000F)]);
698 return buffer.toString();
702 * Convert characters outside the range U+0020 to U+007F to
703 * Unicode escapes, and convert backslash to a double backslash.
705 public static final String escape(String s) {
706 StringBuffer buf = new StringBuffer();
707 for (int i=0; i<s.length(); ) {
708 int c = UTF16.charAt(s, i);
709 i += UTF16.getCharCount(c);
710 if (c >= ' ' && c <= 0x007F) {
712 buf.append("\\\\"); // That is, "\\"
717 boolean four = c <= 0xFFFF;
718 buf.append(four ? "\\u" : "\\U");
719 hex(c, four ? 4 : 8, buf);
722 return buf.toString();
725 /* This map must be in ASCENDING ORDER OF THE ESCAPE CODE */
726 static private final char[] UNESCAPE_MAP = {
742 * Convert an escape to a 32-bit code point value. We attempt
743 * to parallel the icu4c unescapeAt() function.
744 * @param offset16 an array containing offset to the character
745 * <em>after</em> the backslash. Upon return offset16[0] will
746 * be updated to point after the escape sequence.
747 * @return character value from 0 to 10FFFF, or -1 on error.
749 public static int unescapeAt(String s, int[] offset16) {
755 int bitsPerDigit = 4;
758 boolean braces = false;
760 /* Check that offset is in range */
761 int offset = offset16[0];
762 int length = s.length();
763 if (offset < 0 || offset >= length) {
767 /* Fetch first UChar after '\\' */
768 c = UTF16.charAt(s, offset);
769 offset += UTF16.getCharCount(c);
771 /* Convert hexadecimal and octal escapes */
781 if (offset < length && UTF16.charAt(s, offset) == 0x7B /*{*/) {
790 dig = UCharacter.digit(c, 8);
794 n = 1; /* Already have first octal digit */
801 while (offset < length && n < maxDig) {
802 c = UTF16.charAt(s, offset);
803 dig = UCharacter.digit(c, (bitsPerDigit == 3) ? 8 : 16);
807 result = (result << bitsPerDigit) | dig;
808 offset += UTF16.getCharCount(c);
815 if (c != 0x7D /*}*/) {
820 if (result < 0 || result >= 0x110000) {
823 // If an escape sequence specifies a lead surrogate, see
824 // if there is a trail surrogate after it, either as an
825 // escape or as a literal. If so, join them up into a
827 if (offset < length &&
828 UTF16.isLeadSurrogate((char) result)) {
829 int ahead = offset+1;
830 c = s.charAt(offset); // [sic] get 16-bit code unit
831 if (c == '\\' && ahead < length) {
832 int o[] = new int[] { ahead };
833 c = unescapeAt(s, o);
836 if (UTF16.isTrailSurrogate((char) c)) {
838 result = UCharacterProperty.getRawSupplementary(
839 (char) result, (char) c);
842 offset16[0] = offset;
846 /* Convert C-style escapes in table */
847 for (i=0; i<UNESCAPE_MAP.length; i+=2) {
848 if (c == UNESCAPE_MAP[i]) {
849 offset16[0] = offset;
850 return UNESCAPE_MAP[i+1];
851 } else if (c < UNESCAPE_MAP[i]) {
856 /* Map \cX to control-X: X & 0x1F */
857 if (c == 'c' && offset < length) {
858 c = UTF16.charAt(s, offset);
859 offset16[0] = offset + UTF16.getCharCount(c);
863 /* If no special forms are recognized, then consider
864 * the backslash to generically escape the next character. */
865 offset16[0] = offset;
870 * Convert all escapes in a given string using unescapeAt().
871 * @exception IllegalArgumentException if an invalid escape is
874 public static String unescape(String s) {
875 StringBuffer buf = new StringBuffer();
876 int[] pos = new int[1];
877 for (int i=0; i<s.length(); ) {
878 char c = s.charAt(i++);
881 int e = unescapeAt(s, pos);
883 throw new IllegalArgumentException("Invalid escape sequence " +
884 s.substring(i-1, Math.min(i+8, s.length())));
886 UTF16.append(buf, e);
892 return buf.toString();
896 * Convert all escapes in a given string using unescapeAt().
897 * Leave invalid escape sequences unchanged.
899 public static String unescapeLeniently(String s) {
900 StringBuffer buf = new StringBuffer();
901 int[] pos = new int[1];
902 for (int i=0; i<s.length(); ) {
903 char c = s.charAt(i++);
906 int e = unescapeAt(s, pos);
910 UTF16.append(buf, e);
917 return buf.toString();
921 * Convert a char to 4 hex uppercase digits. E.g., hex('a') =>
924 public static String hex(char ch) {
925 StringBuffer temp = new StringBuffer();
926 return hex(ch, temp).toString();
930 * Convert a string to comma-separated groups of 4 hex uppercase
931 * digits. E.g., hex('ab') => "0041,0042".
933 public static String hex(String s) {
934 StringBuffer temp = new StringBuffer();
935 return hex(s, temp).toString();
939 * Convert a string to comma-separated groups of 4 hex uppercase
940 * digits. E.g., hex('ab') => "0041,0042".
942 public static String hex(StringBuffer s) {
943 return hex(s.toString());
947 * Convert a char to 4 hex uppercase digits. E.g., hex('a') =>
948 * "0041". Append the output to the given StringBuffer.
950 public static StringBuffer hex(char ch, StringBuffer output) {
951 return appendNumber(output, ch, 16, 4);
955 * Convert a integer to size width hex uppercase digits.
956 * E.g., hex('a', 4, str) => "0041".
957 * Append the output to the given StringBuffer.
958 * If width is too small to fit, nothing will be appended to output.
960 public static StringBuffer hex(int ch, int width, StringBuffer output) {
961 return appendNumber(output, ch, 16, width);
965 * Convert a integer to size width (minimum) hex uppercase digits.
966 * E.g., hex('a', 4, str) => "0041". If the integer requires more
967 * than width digits, more will be used.
969 public static String hex(int ch, int width) {
970 StringBuffer buf = new StringBuffer();
971 return appendNumber(buf, ch, 16, width).toString();
974 * Supplies a zero-padded hex representation of an integer (without 0x)
976 static public String hex(long i, int places) {
977 if (i == Long.MIN_VALUE) return "-8000000000000000";
978 boolean negative = i < 0;
982 String result = Long.toString(i, 16).toUpperCase();
983 if (result.length() < places) {
984 result = "0000000000000000".substring(result.length(),places) + result;
992 public static String hex(long ch) {
997 * Convert a string to comma-separated groups of 4 hex uppercase
998 * digits. E.g., hex('ab') => "0041,0042". Append the output
999 * to the given StringBuffer.
1001 public static StringBuffer hex(String s, StringBuffer result) {
1002 for (int i = 0; i < s.length(); ++i) {
1003 if (i != 0) result.append(',');
1004 hex(s.charAt(i), result);
1010 * Split a string into pieces based on the given divider character
1011 * @param s the string to split
1012 * @param divider the character on which to split. Occurrences of
1013 * this character are not included in the output
1014 * @param output an array to receive the substrings between
1015 * instances of divider. It must be large enough on entry to
1016 * accomodate all output. Adjacent instances of the divider
1017 * character will place empty strings into output. Before
1018 * returning, output is padded out with empty strings.
1020 public static void split(String s, char divider, String[] output) {
1024 for (i = 0; i < s.length(); ++i) {
1025 if (s.charAt(i) == divider) {
1026 output[current++] = s.substring(last,i);
1030 output[current++] = s.substring(last,i);
1031 while (current < output.length) {
1032 output[current++] = "";
1037 * Split a string into pieces based on the given divider character
1038 * @param s the string to split
1039 * @param divider the character on which to split. Occurrences of
1040 * this character are not included in the output
1041 * @return output an array to receive the substrings between
1042 * instances of divider. Adjacent instances of the divider
1043 * character will place empty strings into output.
1045 public static String[] split(String s, char divider) {
1048 ArrayList output = new ArrayList();
1049 for (i = 0; i < s.length(); ++i) {
1050 if (s.charAt(i) == divider) {
1051 output.add(s.substring(last,i));
1055 output.add( s.substring(last,i));
1056 return (String[]) output.toArray(new String[output.size()]);
1060 * Look up a given string in a string array. Returns the index at
1061 * which the first occurrence of the string was found in the
1062 * array, or -1 if it was not found.
1063 * @param source the string to search for
1064 * @param target the array of zero or more strings in which to
1066 * @return the index of target at which source first occurs, or -1
1069 public static int lookup(String source, String[] target) {
1070 for (int i = 0; i < target.length; ++i) {
1071 if (source.equals(target[i])) return i;
1077 * Skip over a sequence of zero or more white space characters
1078 * at pos. Return the index of the first non-white-space character
1079 * at or after pos, or str.length(), if there is none.
1081 public static int skipWhitespace(String str, int pos) {
1082 while (pos < str.length()) {
1083 int c = UTF16.charAt(str, pos);
1084 if (!UCharacterProperty.isRuleWhiteSpace(c)) {
1087 pos += UTF16.getCharCount(c);
1093 * Skip over a sequence of zero or more white space characters
1094 * at pos[0], advancing it.
1096 public static void skipWhitespace(String str, int[] pos) {
1097 pos[0] = skipWhitespace(str, pos[0]);
1101 * Remove all rule white space from a string.
1103 public static String deleteRuleWhiteSpace(String str) {
1104 StringBuffer buf = new StringBuffer();
1105 for (int i=0; i<str.length(); ) {
1106 int ch = UTF16.charAt(str, i);
1107 i += UTF16.getCharCount(ch);
1108 if (UCharacterProperty.isRuleWhiteSpace(ch)) {
1111 UTF16.append(buf, ch);
1113 return buf.toString();
1117 * Parse a single non-whitespace character 'ch', optionally
1118 * preceded by whitespace.
1119 * @param id the string to be parsed
1120 * @param pos INPUT-OUTPUT parameter. On input, pos[0] is the
1121 * offset of the first character to be parsed. On output, pos[0]
1122 * is the index after the last parsed character. If the parse
1123 * fails, pos[0] will be unchanged.
1124 * @param ch the non-whitespace character to be parsed.
1125 * @return true if 'ch' is seen preceded by zero or more
1126 * whitespace characters.
1128 public static boolean parseChar(String id, int[] pos, char ch) {
1130 skipWhitespace(id, pos);
1131 if (pos[0] == id.length() ||
1132 id.charAt(pos[0]) != ch) {
1141 * Parse a pattern string starting at offset pos. Keywords are
1142 * matched case-insensitively. Spaces may be skipped and may be
1143 * optional or required. Integer values may be parsed, and if
1144 * they are, they will be returned in the given array. If
1145 * successful, the offset of the next non-space character is
1146 * returned. On failure, -1 is returned.
1147 * @param pattern must only contain lowercase characters, which
1148 * will match their uppercase equivalents as well. A space
1149 * character matches one or more required spaces. A '~' character
1150 * matches zero or more optional spaces. A '#' character matches
1151 * an integer and stores it in parsedInts, which the caller must
1152 * ensure has enough capacity.
1153 * @param parsedInts array to receive parsed integers. Caller
1154 * must ensure that parsedInts.length is >= the number of '#'
1155 * signs in 'pattern'.
1156 * @return the position after the last character parsed, or -1 if
1159 public static int parsePattern(String rule, int pos, int limit,
1160 String pattern, int[] parsedInts) {
1161 // TODO Update this to handle surrogates
1162 int[] p = new int[1];
1163 int intCount = 0; // number of integers parsed
1164 for (int i=0; i<pattern.length(); ++i) {
1165 char cpat = pattern.charAt(i);
1172 c = rule.charAt(pos++);
1173 if (!UCharacterProperty.isRuleWhiteSpace(c)) {
1176 // FALL THROUGH to skipWhitespace
1178 pos = skipWhitespace(rule, pos);
1182 parsedInts[intCount++] = parseInteger(rule, p, limit);
1184 // Syntax error; failed to parse integer
1193 c = (char) UCharacter.toLowerCase(rule.charAt(pos++));
1204 * Parse a pattern string within the given Replaceable and a parsing
1205 * pattern. Characters are matched literally and case-sensitively
1206 * except for the following special characters:
1208 * ~ zero or more uprv_isRuleWhiteSpace chars
1210 * If end of pattern is reached with all matches along the way,
1211 * pos is advanced to the first unparsed index and returned.
1212 * Otherwise -1 is returned.
1213 * @param pat pattern that controls parsing
1214 * @param text text to be parsed, starting at index
1215 * @param index offset to first character to parse
1216 * @param limit offset after last character to parse
1217 * @return index after last parsed character, or -1 on parse failure.
1219 public static int parsePattern(String pat,
1225 // empty pattern matches immediately
1226 if (ipat == pat.length()) {
1230 int cpat = UTF16.charAt(pat, ipat);
1232 while (index < limit) {
1233 int c = text.char32At(index);
1237 if (UCharacterProperty.isRuleWhiteSpace(c)) {
1238 index += UTF16.getCharCount(c);
1241 if (++ipat == pat.length()) {
1242 return index; // success; c unparsed
1244 // fall thru; process c again with next cpat
1249 else if (c == cpat) {
1250 int n = UTF16.getCharCount(c);
1253 if (ipat == pat.length()) {
1254 return index; // success; c parsed
1256 // fall thru; get next cpat
1259 // match failure of literal
1264 cpat = UTF16.charAt(pat, ipat);
1267 return -1; // text ended before end of pat
1271 * Parse an integer at pos, either of the form \d+ or of the form
1272 * 0x[0-9A-Fa-f]+ or 0[0-7]+, that is, in standard decimal, hex,
1274 * @param pos INPUT-OUTPUT parameter. On input, the first
1275 * character to parse. On output, the character after the last
1278 public static int parseInteger(String rule, int[] pos, int limit) {
1284 if (rule.regionMatches(true, p, "0x", 0, 2)) {
1287 } else if (p < limit && rule.charAt(p) == '0') {
1294 int d = UCharacter.digit(rule.charAt(p++), radix);
1300 int v = (value * radix) + d;
1302 // If there are too many input digits, at some point
1303 // the value will go negative, e.g., if we have seen
1304 // "0x8000000" already and there is another '0', when
1305 // we parse the next 0 the value will go negative.
1317 * Parse a Unicode identifier from the given string at the given
1318 * position. Return the identifier, or null if there is no
1320 * @param str the string to parse
1321 * @param pos INPUT-OUPUT parameter. On INPUT, pos[0] is the
1322 * first character to examine. It must be less than str.length(),
1323 * and it must not point to a whitespace character. That is, must
1324 * have pos[0] < str.length() and
1325 * !UCharacterProperty.isRuleWhiteSpace(UTF16.charAt(str, pos[0])). On
1326 * OUTPUT, the position after the last parsed character.
1327 * @return the Unicode identifier, or null if there is no valid
1328 * identifier at pos[0].
1330 public static String parseUnicodeIdentifier(String str, int[] pos) {
1331 // assert(pos[0] < str.length());
1332 // assert(!UCharacterProperty.isRuleWhiteSpace(UTF16.charAt(str, pos[0])));
1333 StringBuffer buf = new StringBuffer();
1335 while (p < str.length()) {
1336 int ch = UTF16.charAt(str, p);
1337 if (buf.length() == 0) {
1338 if (UCharacter.isUnicodeIdentifierStart(ch)) {
1339 UTF16.append(buf, ch);
1344 if (UCharacter.isUnicodeIdentifierPart(ch)) {
1345 UTF16.append(buf, ch);
1350 p += UTF16.getCharCount(ch);
1353 return buf.toString();
1357 * Trim whitespace from ends of a StringBuffer.
1359 public static StringBuffer trim(StringBuffer b) {
1360 // TODO update to handle surrogates
1362 for (i=0; i<b.length() && UCharacter.isWhitespace(b.charAt(i)); ++i) {}
1364 for (i=b.length()-1; i>=0 && UCharacter.isWhitespace(b.charAt(i)); --i) {}
1365 return b.delete(i+1, b.length());
1368 static final char DIGITS[] = {
1369 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1370 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
1371 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
1372 'U', 'V', 'W', 'X', 'Y', 'Z'
1376 * Append a number to the given StringBuffer in the radix 10
1377 * generating at least one digit.
1379 public static StringBuffer appendNumber(StringBuffer result, int n) {
1380 return appendNumber(result, n, 10, 1);
1384 * Append the digits of a positive integer to the given
1385 * <code>StringBuffer</code> in the given radix. This is
1386 * done recursively since it is easiest to generate the low-
1387 * order digit first, but it must be appended last.
1389 * @param result is the <code>StringBuffer</code> to append to
1390 * @param n is the positive integer
1391 * @param radix is the radix, from 2 to 36 inclusive
1392 * @param minDigits is the minimum number of digits to append.
1394 private static void recursiveAppendNumber(StringBuffer result, int n,
1395 int radix, int minDigits)
1397 int digit = n % radix;
1399 if (n >= radix || minDigits > 1) {
1400 recursiveAppendNumber(result, n / radix, radix, minDigits - 1);
1403 result.append(DIGITS[digit]);
1407 * Append a number to the given StringBuffer in the given radix.
1408 * Standard digits '0'-'9' are used and letters 'A'-'Z' for
1409 * radices 11 through 36.
1410 * @param result the digits of the number are appended here
1411 * @param n the number to be converted to digits; may be negative.
1412 * If negative, a '-' is prepended to the digits.
1413 * @param radix a radix from 2 to 36 inclusive.
1414 * @param minDigits the minimum number of digits, not including
1415 * any '-', to produce. Values less than 2 have no effect. One
1416 * digit is always emitted regardless of this parameter.
1417 * @return a reference to result
1419 public static StringBuffer appendNumber(StringBuffer result, int n,
1420 int radix, int minDigits)
1421 throws IllegalArgumentException
1423 if (radix < 2 || radix > 36) {
1424 throw new IllegalArgumentException("Illegal radix " + radix);
1435 recursiveAppendNumber(result, abs, radix, minDigits);
1441 * Parse an unsigned 31-bit integer at the given offset. Use
1442 * UCharacter.digit() to parse individual characters into digits.
1443 * @param text the text to be parsed
1444 * @param pos INPUT-OUTPUT parameter. On entry, pos[0] is the
1445 * offset within text at which to start parsing; it should point
1446 * to a valid digit. On exit, pos[0] is the offset after the last
1447 * parsed character. If the parse failed, it will be unchanged on
1448 * exit. Must be >= 0 on entry.
1449 * @param radix the radix in which to parse; must be >= 2 and <=
1451 * @return a non-negative parsed number, or -1 upon parse failure.
1452 * Parse fails if there are no digits, that is, if pos[0] does not
1453 * point to a valid digit on entry, or if the number to be parsed
1454 * does not fit into a 31-bit unsigned integer.
1456 public static int parseNumber(String text, int[] pos, int radix) {
1457 // assert(pos[0] >= 0);
1458 // assert(radix >= 2);
1459 // assert(radix <= 36);
1462 while (p < text.length()) {
1463 int ch = UTF16.charAt(text, p);
1464 int d = UCharacter.digit(ch, radix);
1469 // ASSUME that when a 32-bit integer overflows it becomes
1470 // negative. E.g., 214748364 * 10 + 8 => negative value.
1484 * Return true if the character is NOT printable ASCII. The tab,
1485 * newline and linefeed characters are considered unprintable.
1487 public static boolean isUnprintable(int c) {
1488 return !(c >= 0x20 && c <= 0x7E);
1492 * Escape unprintable characters using <backslash>uxxxx notation
1493 * for U+0000 to U+FFFF and <backslash>Uxxxxxxxx for U+10000 and
1494 * above. If the character is printable ASCII, then do nothing
1495 * and return FALSE. Otherwise, append the escaped notation and
1498 public static boolean escapeUnprintable(StringBuffer result, int c) {
1499 if (isUnprintable(c)) {
1500 result.append('\\');
1501 if ((c & ~0xFFFF) != 0) {
1503 result.append(DIGITS[0xF&(c>>28)]);
1504 result.append(DIGITS[0xF&(c>>24)]);
1505 result.append(DIGITS[0xF&(c>>20)]);
1506 result.append(DIGITS[0xF&(c>>16)]);
1510 result.append(DIGITS[0xF&(c>>12)]);
1511 result.append(DIGITS[0xF&(c>>8)]);
1512 result.append(DIGITS[0xF&(c>>4)]);
1513 result.append(DIGITS[0xF&c]);
1520 * Returns the index of the first character in a set, ignoring quoted text.
1521 * For example, in the string "abc'hide'h", the 'h' in "hide" will not be
1522 * found by a search for "h". Unlike String.indexOf(), this method searches
1523 * not for a single character, but for any character of the string
1524 * <code>setOfChars</code>.
1525 * @param text text to be searched
1526 * @param start the beginning index, inclusive; <code>0 <= start
1528 * @param limit the ending index, exclusive; <code>start <= limit
1529 * <= text.length()</code>.
1530 * @param setOfChars string with one or more distinct characters
1531 * @return Offset of the first character in <code>setOfChars</code>
1532 * found, or -1 if not found.
1533 * @see String#indexOf
1535 public static int quotedIndexOf(String text, int start, int limit,
1536 String setOfChars) {
1537 for (int i=start; i<limit; ++i) {
1538 char c = text.charAt(i);
1539 if (c == BACKSLASH) {
1541 } else if (c == APOSTROPHE) {
1543 && text.charAt(i) != APOSTROPHE) {}
1544 } else if (setOfChars.indexOf(c) >= 0) {
1552 * Similar to StringBuffer.getChars, version 1.3.
1553 * Since JDK 1.2 implements StringBuffer.getChars differently, this method
1554 * is here to provide consistent results.
1555 * To be removed after JDK 1.2 ceased to be the reference platform.
1556 * @param src source string buffer
1557 * @param srcBegin offset to the start of the src to retrieve from
1558 * @param srcEnd offset to the end of the src to retrieve from
1559 * @param dst char array to store the retrieved chars
1560 * @param dstBegin offset to the start of the destination char array to
1561 * store the retrieved chars
1563 public static void getChars(StringBuffer src, int srcBegin, int srcEnd,
1564 char dst[], int dstBegin)
1566 if (srcBegin == srcEnd) {
1569 src.getChars(srcBegin, srcEnd, dst, dstBegin);
1573 * Append a character to a rule that is being built up. To flush
1574 * the quoteBuf to rule, make one final call with isLiteral == true.
1575 * If there is no final character, pass in (int)-1 as c.
1576 * @param rule the string to append the character to
1577 * @param c the character to append, or (int)-1 if none.
1578 * @param isLiteral if true, then the given character should not be
1579 * quoted or escaped. Usually this means it is a syntactic element
1581 * @param escapeUnprintable if true, then unprintable characters
1582 * should be escaped using escapeUnprintable(). These escapes will
1583 * appear outside of quotes.
1584 * @param quoteBuf a buffer which is used to build up quoted
1585 * substrings. The caller should initially supply an empty buffer,
1586 * and thereafter should not modify the buffer. The buffer should be
1587 * cleared out by, at the end, calling this method with a literal
1588 * character (which may be -1).
1590 public static void appendToRule(StringBuffer rule,
1593 boolean escapeUnprintable,
1594 StringBuffer quoteBuf) {
1595 // If we are escaping unprintables, then escape them outside
1596 // quotes. \\u and \\U are not recognized within quotes. The same
1597 // logic applies to literals, but literals are never escaped.
1599 (escapeUnprintable && Utility.isUnprintable(c))) {
1600 if (quoteBuf.length() > 0) {
1601 // We prefer backslash APOSTROPHE to double APOSTROPHE
1602 // (more readable, less similar to ") so if there are
1603 // double APOSTROPHEs at the ends, we pull them outside
1606 // If the first thing in the quoteBuf is APOSTROPHE
1607 // (doubled) then pull it out.
1608 while (quoteBuf.length() >= 2 &&
1609 quoteBuf.charAt(0) == APOSTROPHE &&
1610 quoteBuf.charAt(1) == APOSTROPHE) {
1611 rule.append(BACKSLASH).append(APOSTROPHE);
1612 quoteBuf.delete(0, 2);
1614 // If the last thing in the quoteBuf is APOSTROPHE
1615 // (doubled) then remove and count it and add it after.
1616 int trailingCount = 0;
1617 while (quoteBuf.length() >= 2 &&
1618 quoteBuf.charAt(quoteBuf.length()-2) == APOSTROPHE &&
1619 quoteBuf.charAt(quoteBuf.length()-1) == APOSTROPHE) {
1620 quoteBuf.setLength(quoteBuf.length()-2);
1623 if (quoteBuf.length() > 0) {
1624 rule.append(APOSTROPHE);
1625 // jdk 1.3.1 does not have append(StringBuffer) yet
1626 if(ICUDebug.isJDK14OrHigher){
1627 rule.append(quoteBuf);
1629 rule.append(quoteBuf.toString());
1631 rule.append(APOSTROPHE);
1632 quoteBuf.setLength(0);
1634 while (trailingCount-- > 0) {
1635 rule.append(BACKSLASH).append(APOSTROPHE);
1639 /* Since spaces are ignored during parsing, they are
1640 * emitted only for readability. We emit one here
1641 * only if there isn't already one at the end of the
1645 int len = rule.length();
1646 if (len > 0 && rule.charAt(len-1) != ' ') {
1649 } else if (!escapeUnprintable || !Utility.escapeUnprintable(rule, c)) {
1650 UTF16.append(rule, c);
1655 // Escape ' and '\' and don't begin a quote just for them
1656 else if (quoteBuf.length() == 0 &&
1657 (c == APOSTROPHE || c == BACKSLASH)) {
1658 rule.append(BACKSLASH).append((char)c);
1661 // Specials (printable ascii that isn't [0-9a-zA-Z]) and
1662 // whitespace need quoting. Also append stuff to quotes if we are
1663 // building up a quoted substring already.
1664 else if (quoteBuf.length() > 0 ||
1665 (c >= 0x0021 && c <= 0x007E &&
1666 !((c >= 0x0030/*'0'*/ && c <= 0x0039/*'9'*/) ||
1667 (c >= 0x0041/*'A'*/ && c <= 0x005A/*'Z'*/) ||
1668 (c >= 0x0061/*'a'*/ && c <= 0x007A/*'z'*/))) ||
1669 UCharacterProperty.isRuleWhiteSpace(c)) {
1670 UTF16.append(quoteBuf, c);
1671 // Double ' within a quote
1672 if (c == APOSTROPHE) {
1673 quoteBuf.append((char)c);
1677 // Otherwise just append
1679 UTF16.append(rule, c);
1684 * Append the given string to the rule. Calls the single-character
1685 * version of appendToRule for each character.
1687 public static void appendToRule(StringBuffer rule,
1690 boolean escapeUnprintable,
1691 StringBuffer quoteBuf) {
1692 for (int i=0; i<text.length(); ++i) {
1693 // Okay to process in 16-bit code units here
1694 appendToRule(rule, text.charAt(i), isLiteral, escapeUnprintable, quoteBuf);
1699 * Given a matcher reference, which may be null, append its
1700 * pattern as a literal to the given rule.
1702 public static void appendToRule(StringBuffer rule,
1703 UnicodeMatcher matcher,
1704 boolean escapeUnprintable,
1705 StringBuffer quoteBuf) {
1706 if (matcher != null) {
1707 appendToRule(rule, matcher.toPattern(escapeUnprintable),
1708 true, escapeUnprintable, quoteBuf);
1713 * Compares 2 unsigned integers
1714 * @param source 32 bit unsigned integer
1715 * @param target 32 bit unsigned integer
1716 * @return 0 if equals, 1 if source is greater than target and -1
1719 public static final int compareUnsigned(int source, int target)
1721 source += MAGIC_UNSIGNED;
1722 target += MAGIC_UNSIGNED;
1723 if (source < target) {
1726 else if (source > target) {
1733 * Find the highest bit in a positive integer. This is done
1734 * by doing a binary search through the bits.
1736 * @param n is the integer
1738 * @return the bit number of the highest bit, with 0 being
1739 * the low order bit, or -1 if <code>n</code> is not positive
1741 public static final byte highBit(int n)
1777 * Utility method to take a int[] containing codepoints and return
1778 * a string representation with code units.
1780 public static String valueOf(int[]source){
1781 // TODO: Investigate why this method is not on UTF16 class
1782 StringBuffer result = new StringBuffer(source.length);
1783 for(int i=0; i<source.length; i++){
1784 UTF16.append(result,source[i]);
1786 return result.toString();
1791 * Utility to duplicate a string count times
1795 public static String repeat(String s, int count) {
1796 if (count <= 0) return "";
1797 if (count == 1) return s;
1798 StringBuffer result = new StringBuffer();
1799 for (int i = 0; i < count; ++i) {
1802 return result.toString();
1806 // !!! 1.3 compatibility
1807 public static int indexOf(StringBuffer buf, String s) {
1808 //#if defined(FOUNDATION10) || defined(J2SE13)
1809 //## return buf.toString().indexOf(s);
1811 return buf.indexOf(s);
1815 // !!! 1.3 compatibility
1816 public static int lastIndexOf(StringBuffer buf, String s) {
1817 //#if defined(FOUNDATION10) || defined(J2SE13)
1818 //## return buf.toString().lastIndexOf(s);
1820 return buf.lastIndexOf(s);
1824 // !!! 1.3 compatibility
1825 public static int indexOf(StringBuffer buf, String s, int i) {
1826 //#if defined(FOUNDATION10) || defined(J2SE13)
1827 //## return buf.toString().indexOf(s, i);
1829 return buf.indexOf(s, i);
1833 // !!! 1.3 compatibility
1834 public static int lastIndexOf(StringBuffer buf, String s, int i) {
1835 //#if defined(FOUNDATION10) || defined(J2SE13)
1836 //## return buf.toString().lastIndexOf(s, i);
1838 return buf.lastIndexOf(s, i);
1842 // !!! 1.3/1.4 compatibility
1843 public static String replace(String src, String target, String replacement) {
1844 //#if defined(FOUNDATION10) || defined(J2SE13) || defined(J2SE14)
1845 //## int i = src.indexOf(target);
1849 //## StringBuffer buf = new StringBuffer();
1852 //## buf.append(src.substring(n, i));
1853 //## buf.append(replacement);
1854 //## n = i + target.length();
1855 //## i = src.indexOf(target, n);
1856 //## } while (i != -1);
1857 //## if (n < src.length()) {
1858 //## buf.append(src.substring(n));
1860 //## return buf.toString();
1862 return src.replace(target, replacement);
1866 // !!! 1.3 compatibility
1867 public static String replaceAll(String src, String target, String replacement) {
1868 //#if defined(FOUNDATION10) || defined(J2SE13)
1869 //## return replace(src, target, replacement);
1871 return src.replaceAll(target, replacement);
1875 //private static final String REGEX_SPECIALS = ".^$[]*+?|()";
1877 // !!! 1.3 compatibility
1878 // Note: target is not a string literal, not a regular expression.
1879 public static String[] splitString(String src, String target) {
1880 //#if defined(FOUNDATION10) || defined(J2SE13)
1881 //## int i = src.indexOf(target);
1883 //## return new String[] { src };
1885 //## ArrayList output = new ArrayList();
1888 //## output.add(src.substring(n, i));
1889 //## n = i + target.length();
1890 //## i = src.indexOf(target, n);
1891 //## } while (i != -1);
1892 //## if (n < src.length()) {
1893 //## output.add(src.substring(n));
1895 //## return (String[]) output.toArray(new String[output.size()]);
1897 return src.split("\\Q" + target + "\\E");
1901 // !!! 1.3 compatibility
1903 * Split the string at runs of ascii whitespace characters.
1905 public static String[] splitWhitespace(String src) {
1906 //#if defined(FOUNDATION10) || defined(J2SE13)
1907 //## char ws[] = "\u0020\u0009\n\u000b\u000c\r".toCharArray();
1908 //## ArrayList output = new ArrayList();
1909 //## boolean inWhitespace = true;
1912 //## for (int i = 0; i < src.length(); ++i) {
1913 //## char c = src.charAt(i);
1914 //## for (int j = 0; j < ws.length; ++j) {
1915 //## if (ws[j] == c) {
1916 //## if (!inWhitespace) {
1917 //## output.add(src.substring(n, i));
1918 //## inWhitespace = true;
1923 //## if (inWhitespace) {
1925 //## inWhitespace = false;
1928 //## if (n < src.length()) {
1929 //## output.add(src.substring(n));
1931 //## return (String[]) output.toArray(new String[output.size()]);
1933 return src.split("\\s+");
1937 // !!! 1.3/1.4 compatibility
1938 // Integer constants - Integer.valueOf(int) is not supported in JDK 1.3/1.4
1939 private static final int MAX_INT_CONST = 64;
1940 private static final Integer[] INT_CONST = new Integer[MAX_INT_CONST];
1943 for (int i = 0; i < MAX_INT_CONST; i++) {
1944 INT_CONST[i] = new Integer(i);
1948 public static Integer integerValueOf(int val) {
1949 if (0 <= val && val < MAX_INT_CONST) {
1950 return INT_CONST[val];
1952 return new Integer(val);
1955 // !!! 1.3/1.4 compatibility
1956 // Arrays.toString(Object[])
1957 public static String arrayToString(Object[] a) {
1958 StringBuffer buf = new StringBuffer("[");
1959 for (int i = 0; i < a.length; i++) {
1966 buf.append(a[i].toString());
1970 return buf.toString();