0001: /*
0002: * StringUtil.java
0003: *
0004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
0005: *
0006: * Copyright 2002-2008, Thomas Kellerer
0007: * No part of this code maybe reused without the permission of the author
0008: *
0009: * To contact the author please send an email to: support@sql-workbench.net
0010: *
0011: */
0012: package workbench.util;
0013:
0014: import java.text.SimpleDateFormat;
0015: import java.util.ArrayList;
0016: import java.util.Collection;
0017: import java.util.Iterator;
0018: import java.util.LinkedList;
0019: import java.util.List;
0020: import java.util.regex.Matcher;
0021: import java.util.regex.Pattern;
0022:
0023: /**
0024: *
0025: * @author support@sql-workbench.net
0026: */
0027: public class StringUtil {
0028: public static final String REGEX_CRLF = "(\r\n|\n\r|\r|\n)";
0029: public static final Pattern PATTERN_CRLF = Pattern
0030: .compile(REGEX_CRLF);
0031: public static final Pattern PATTERN_NON_LF = Pattern
0032: .compile("(\r\n|\n\r|\r)");
0033:
0034: public static final String LINE_TERMINATOR = System
0035: .getProperty("line.separator");
0036: public static final String EMPTY_STRING = "";
0037:
0038: public static final String ISO_DATE_FORMAT = "yyyy-MM-dd";
0039: public static final String ISO_TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
0040: public static final String ISO_TZ_TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS z";
0041:
0042: public static final SimpleDateFormat ISO_TIMESTAMP_FORMATTER = new SimpleDateFormat(
0043: ISO_TIMESTAMP_FORMAT);
0044: public static final SimpleDateFormat ISO_TZ_TIMESTAMP_FORMATTER = new SimpleDateFormat(
0045: ISO_TZ_TIMESTAMP_FORMAT);
0046:
0047: public static final StringBuilder emptyBuffer() {
0048: return new StringBuilder(0);
0049: }
0050:
0051: public static final String getCurrentTimestampWithTZString() {
0052: return ISO_TZ_TIMESTAMP_FORMATTER.format(now());
0053: }
0054:
0055: private static final java.util.Date now() {
0056: return new java.util.Date(System.currentTimeMillis());
0057: }
0058:
0059: public static String getPathSeparator() {
0060: return System.getProperty("path.separator");
0061: }
0062:
0063: public static int hashCode(CharSequence val) {
0064: int len = val.length();
0065: int hash = 0;
0066:
0067: for (int i = 0; i < len; i++) {
0068: hash = 31 * hash + val.charAt(i);
0069: }
0070: return hash;
0071: }
0072:
0073: /**
0074: * Replace various combinations of linefeeds in the input string with \n.
0075: *
0076: * @param input
0077: * @return input string with only \n linefeeds
0078: * @see #PATTERN_NON_LF
0079: */
0080: public static String makePlainLinefeed(String input) {
0081: Matcher m = PATTERN_NON_LF.matcher(input);
0082: return m.replaceAll("\n");
0083: }
0084:
0085: public static boolean endsWith(CharSequence s, String end) {
0086: if (s == null)
0087: return false;
0088: if (isEmptyString(end))
0089: return false;
0090: int len = s.length();
0091: if (len == 0)
0092: return false;
0093: if (len < end.length())
0094: return false;
0095: String last = s.subSequence(len - end.length(), len).toString();
0096: return end.equals(last);
0097: }
0098:
0099: public static boolean endsWith(CharSequence s, char c) {
0100: if (s == null)
0101: return false;
0102: int len = s.length();
0103: if (len == 0)
0104: return false;
0105: return s.charAt(len - 1) == c;
0106: }
0107:
0108: public static boolean lineStartsWith(CharSequence text,
0109: int lineStartPos, String compareTo) {
0110: if (isWhitespaceOrEmpty(compareTo))
0111: return false;
0112: int textLength = text.length();
0113:
0114: int len = compareTo.length();
0115: for (int i = 0; i < len; i++) {
0116: char this Char = 0;
0117: char otherChar = compareTo.charAt(i);
0118: if (lineStartPos + i < textLength) {
0119: this Char = text.charAt(lineStartPos + i);
0120: }
0121: if (this Char != otherChar)
0122: return false;
0123: }
0124: return true;
0125: }
0126:
0127: /**
0128: * Returns the length of the line without any line ending characters
0129: */
0130: public static int getRealLineLength(String line) {
0131: int len = line.length();
0132: if (len == 0)
0133: return 0;
0134:
0135: char c = line.charAt(len - 1);
0136:
0137: while ((len > 0) && (c == '\r' || c == '\n')) {
0138: len--;
0139: if (len > 0)
0140: c = line.charAt(len - 1);
0141: }
0142: return len;
0143: }
0144:
0145: public static boolean isWhitespace(CharSequence s) {
0146: if (s == null)
0147: return false;
0148: int len = s.length();
0149: if (len == 0)
0150: return false;
0151: int pos = 0;
0152: while (pos < len) {
0153: char c = s.charAt(pos);
0154: if (!Character.isWhitespace(c))
0155: return false;
0156: pos++;
0157: }
0158: return true;
0159: }
0160:
0161: public static String rtrim(String s) {
0162: if (s == null)
0163: return s;
0164: int pos = s.length();
0165: if (pos == 0)
0166: return s;
0167:
0168: while (pos > 0 && Character.isWhitespace(s.charAt(pos - 1))) {
0169: pos--;
0170: }
0171:
0172: return s.substring(0, pos);
0173: }
0174:
0175: public static int indexOf(CharSequence value, char c) {
0176: return indexOf(value, c, 1);
0177: }
0178:
0179: public static int indexOf(CharSequence value, char c, int occurance) {
0180: if (value == null)
0181: return -1;
0182: if (occurance <= 0)
0183: occurance = 1;
0184: int numFound = 0;
0185:
0186: for (int i = 0; i < value.length(); i++) {
0187: if (value.charAt(i) == c) {
0188: numFound++;
0189: if (numFound == occurance)
0190: return i;
0191: }
0192: }
0193: return -1;
0194: }
0195:
0196: public static void trimTrailingWhitespace(StringBuilder value) {
0197: if (value == null || value.length() == 0)
0198: return;
0199: int len = value.length();
0200: int pos = len - 1;
0201: char c = value.charAt(pos);
0202: if (!Character.isWhitespace(c))
0203: return;
0204:
0205: while (Character.isWhitespace(c)) {
0206: pos--;
0207: c = value.charAt(pos);
0208: }
0209: value.delete(pos + 1, len);
0210: }
0211:
0212: public static boolean isMixedCase(String s) {
0213: return !isUpperCase(s) && !isLowerCase(s);
0214: }
0215:
0216: public static boolean isLowerCase(String s) {
0217: if (s == null)
0218: return false;
0219: int l = s.length();
0220: for (int i = 0; i < l; i++) {
0221: char c = s.charAt(i);
0222: if (Character.isUpperCase(c))
0223: return false;
0224: }
0225: return true;
0226: }
0227:
0228: public static boolean isUpperCase(String s) {
0229: if (s == null)
0230: return false;
0231: int l = s.length();
0232: for (int i = 0; i < l; i++) {
0233: char c = s.charAt(i);
0234: if (Character.isLowerCase(c))
0235: return false;
0236: }
0237: return true;
0238: }
0239:
0240: public static final boolean arraysEqual(String[] one, String[] other) {
0241: if (one == null && other != null)
0242: return false;
0243: if (one != null && other == null)
0244: return false;
0245: if (one.length != other.length)
0246: return false;
0247: for (int i = 0; i < one.length; i++) {
0248: if (!equalString(one[i], other[i]))
0249: return false;
0250: }
0251: return true;
0252: }
0253:
0254: public static final boolean hasOpenQuotes(String data,
0255: char quoteChar) {
0256: if (isEmptyString(data))
0257: return false;
0258: int chars = data.length();
0259: boolean inQuotes = false;
0260: for (int i = 0; i < chars; i++) {
0261: if (data.charAt(i) == quoteChar)
0262: inQuotes = !inQuotes;
0263: }
0264: return inQuotes;
0265: }
0266:
0267: /**
0268: * Capitalize the first word of the passed String.
0269: * (write the first character in uppercase, the rest in lower case)
0270: * This does not loop through the entire string to capitalize every word.
0271: */
0272: public static final String capitalize(String word) {
0273: if (word == null)
0274: return null;
0275: if (word.length() == 0)
0276: return word;
0277: StringBuilder s = new StringBuilder(word.toLowerCase());
0278: char c = s.charAt(0);
0279: s.setCharAt(0, Character.toUpperCase(c));
0280: return s.toString();
0281: }
0282:
0283: /**
0284: * Remove all characters that might not be allowed in a filename from the input string.
0285: * @param input the value to be used as a filename
0286: * @return input value without any characters that might not be allowed for a filename converted to lowercase
0287: */
0288: public static final String makeFilename(String input) {
0289: if (input == null)
0290: return null;
0291: if (input.equals(".."))
0292: return "__";
0293: if (input.equals("."))
0294: return "_";
0295: return input.replaceAll(
0296: "[\t\\:\\\\/\\?\\*\\|<>\"'%\u00A7\\^\\&\u0000]", "")
0297: .toLowerCase();
0298: }
0299:
0300: /**
0301: * Replaces all occurances of needle in haystack with replacement and appends the resulting
0302: * String to the passed target.
0303: * @param target the buffer to append the result to. If target is null a new StringBuilder will be created
0304: * @param haystack the String in which to search the value
0305: * @param needle the value to search for
0306: * @param replacement the value with which needle is replaced
0307: * @return the resulting buffer
0308: */
0309: public static final StringBuilder replaceToBuffer(
0310: StringBuilder target, String haystack, String needle,
0311: String replacement) {
0312: if (target == null) {
0313: target = new StringBuilder((int) (haystack.length() * 1.1));
0314: }
0315:
0316: int pos = haystack.indexOf(needle);
0317: if (pos == -1) {
0318: target.append(haystack);
0319: return target;
0320: }
0321:
0322: int lastpos = 0;
0323: int len = needle.length();
0324: while (pos != -1) {
0325: target.append(haystack.substring(lastpos, pos));
0326: if (replacement != null)
0327: target.append(replacement);
0328: lastpos = pos + len;
0329: pos = haystack.indexOf(needle, lastpos);
0330: }
0331: if (lastpos < haystack.length()) {
0332: target.append(haystack.substring(lastpos));
0333: }
0334: return target;
0335: }
0336:
0337: /**
0338: * Replacement for StringBuilder.lastIndexOf() which does
0339: * a lot of object creation and copying to achieve this.
0340: * This implementation should be a lot faster for StringBuilder
0341: * and StringBuffer, and will basically be the same for String
0342: * objects.
0343: *
0344: * @param s the string to search in
0345: * @param c the character to look for
0346: * @return -1 if c was not found, the position of c in s otherwise
0347: */
0348: public static final int lastIndexOf(CharSequence s, char c) {
0349: int len = s.length();
0350: if (s == null || len == 0)
0351: return -1;
0352:
0353: for (int i = (len - 1); i > 0; i--) {
0354: if (s.charAt(i) == c)
0355: return i;
0356: }
0357: return -1;
0358: }
0359:
0360: public static final String replace(String haystack, String needle,
0361: String replacement) {
0362: if (replacement == null)
0363: return haystack;
0364: if (needle == null)
0365: return haystack;
0366: if (haystack == null)
0367: return null;
0368:
0369: int pos = haystack.indexOf(needle);
0370: if (pos == -1)
0371: return haystack;
0372:
0373: StringBuilder temp = replaceToBuffer(null, haystack, needle,
0374: replacement);
0375:
0376: return temp.toString();
0377: }
0378:
0379: private static final int[] limits = { 9, 99, 999, 9999, 99999,
0380: 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE };
0381:
0382: /**
0383: * Returns the number of Digits of the value
0384: *
0385: * @param x the value to check
0386: * @return the number of digits that x consists of
0387: */
0388: public static int numDigits(int x) {
0389: for (int i = 0; i < limits.length; i++) {
0390: if (x <= limits[i]) {
0391: return i + 1;
0392: }
0393: }
0394: return limits.length + 1;
0395: }
0396:
0397: public static boolean isInteger(String value) {
0398: if (isEmptyString(value))
0399: return false;
0400: String s = value.trim();
0401: int l = s.length();
0402: for (int i = 0; i < l; i++) {
0403: if (!Character.isDigit(s.charAt(i)))
0404: return false;
0405: }
0406: return true;
0407: }
0408:
0409: public static boolean isNumber(String value) {
0410: try {
0411: Double.parseDouble(value);
0412: return true;
0413: } catch (Exception e) {
0414: return false;
0415: }
0416: }
0417:
0418: /**
0419: * Checks if the given parameter is "empty",
0420: * i.e: either null, length == 0 or contains only whitespace
0421: */
0422: public static final boolean isWhitespaceOrEmpty(CharSequence value) {
0423: if (isEmptyString(value))
0424: return true;
0425: return isWhitespace(value);
0426: }
0427:
0428: /**
0429: * Checks if the given String is null or has a zero length.
0430: * A String containing only whitespaces is not considered empty.
0431: *
0432: * @param value the String to test
0433: * @return
0434: */
0435: public static final boolean isEmptyString(CharSequence value) {
0436: if (value == null)
0437: return true;
0438: if (value.length() == 0)
0439: return true;
0440: return false;
0441: }
0442:
0443: public static final String getStartingWhiteSpace(final String aLine) {
0444: if (aLine == null)
0445: return null;
0446: int pos = 0;
0447: int len = aLine.length();
0448: if (len == 0)
0449: return "";
0450:
0451: char c = aLine.charAt(pos);
0452: while (c <= ' ' && pos < len - 1) {
0453: pos++;
0454: c = aLine.charAt(pos);
0455: }
0456: String result = aLine.substring(0, pos);
0457: return result;
0458: }
0459:
0460: public static double getDoubleValue(String aValue, double aDefault) {
0461: if (aValue == null)
0462: return aDefault;
0463:
0464: double result = aDefault;
0465: try {
0466: result = Double.parseDouble(aValue.trim());
0467: } catch (NumberFormatException e) {
0468: // Ignore
0469: }
0470: return result;
0471: }
0472:
0473: public static int getIntValue(String aValue) {
0474: return getIntValue(aValue, 0);
0475: }
0476:
0477: public static int getIntValue(String aValue, int aDefault) {
0478: if (aValue == null)
0479: return aDefault;
0480:
0481: int result = aDefault;
0482: try {
0483: result = Integer.parseInt(aValue.trim());
0484: } catch (NumberFormatException e) {
0485: // Ignore
0486: }
0487: return result;
0488: }
0489:
0490: public static long getLongValue(String aValue, long aDefault) {
0491: if (aValue == null)
0492: return aDefault;
0493:
0494: long result = aDefault;
0495: try {
0496: result = Long.parseLong(aValue.trim());
0497: } catch (NumberFormatException e) {
0498: // Ignore
0499: }
0500: return result;
0501: }
0502:
0503: /**
0504: * Checks if both Strings are equal considering null values.
0505: * A null String and an empty String (length==0 or all whitespace) are
0506: * considered equal as well (because both are "empty")
0507: * @see #isWhitespaceOrEmpty(CharSequence)
0508: */
0509: public static final boolean equalStringOrEmpty(String one,
0510: String other) {
0511: if (isWhitespaceOrEmpty(one) && isWhitespaceOrEmpty(other))
0512: return true;
0513: return equalString(one, other);
0514: }
0515:
0516: public static final boolean equalString(String one, String other) {
0517: return compareStrings(one, other, false) == 0;
0518: }
0519:
0520: /**
0521: * @param value1 the first String, maybe null
0522: * @param value2 the second String, maybe null
0523: * @return 0 if both are null
0524: */
0525: public static int compareStrings(String value1, String value2,
0526: boolean ignoreCase) {
0527: if (value1 == null && value2 == null)
0528: return 0;
0529: if (value1 == null)
0530: return -1;
0531: if (value2 == null)
0532: return 1;
0533: if (ignoreCase)
0534: return value1.compareToIgnoreCase(value2);
0535: return value1.compareTo(value2);
0536: }
0537:
0538: public static final boolean equalStringIgnoreCase(String one,
0539: String other) {
0540: if (one == null && other == null)
0541: return true;
0542: if (one == null || other == null)
0543: return false;
0544: return one.equalsIgnoreCase(other);
0545: }
0546:
0547: public static final List<String> stringToList(String aString) {
0548: return stringToList(aString, ",");
0549: }
0550:
0551: public static final List<String> stringToList(String aString,
0552: String aDelimiter) {
0553: return stringToList(aString, aDelimiter, false, false);
0554: }
0555:
0556: public static final List<String> stringToList(String aString,
0557: String aDelimiter, boolean removeEmpty) {
0558: return stringToList(aString, aDelimiter, removeEmpty, false);
0559: }
0560:
0561: public static final List<String> stringToList(String aString,
0562: String aDelimiter, boolean removeEmpty, boolean trimEntries) {
0563: return stringToList(aString, aDelimiter, removeEmpty,
0564: trimEntries, false);
0565: }
0566:
0567: /**
0568: * Parses the given String and creates a List containing the elements
0569: * of the string that are separated by <tt>aDelimiter</aa>
0570: *
0571: * @param aString the value to be parsed
0572: * @param aDelimiter the delimiter to user
0573: * @param removeEmpty flag to remove empty entries
0574: * @param trimEntries flag to trim entries (will be applied beore checking for empty entries)
0575: * @param checkBrackets flag to check for opening and closing brackets (delimiter inside brackets will not be taken into account)
0576: * @return A List of Strings
0577: */
0578: public static final List<String> stringToList(String aString,
0579: String aDelimiter, boolean removeEmpty,
0580: boolean trimEntries, boolean checkBrackets) {
0581: if (isEmptyString(aString))
0582: return new ArrayList<String>();
0583: WbStringTokenizer tok = new WbStringTokenizer(aString,
0584: aDelimiter);
0585: tok.setDelimiterNeedsWhitspace(false);
0586: tok.setCheckBrackets(checkBrackets);
0587: List<String> result = new LinkedList<String>();
0588: while (tok.hasMoreTokens()) {
0589: String element = tok.nextToken();
0590: if (element == null)
0591: continue;
0592: if (trimEntries)
0593: element = element.trim();
0594: if (removeEmpty && isEmptyString(element))
0595: continue;
0596: result.add(element);
0597: }
0598: return result;
0599: }
0600:
0601: public static final String[] toArray(Collection<String> strings) {
0602: if (strings == null)
0603: return null;
0604: if (strings.size() == 0)
0605: return new String[0];
0606:
0607: int i = 0;
0608: String[] result = new String[strings.size()];
0609: for (String s : strings) {
0610: result[i++] = s;
0611: }
0612: return result;
0613: }
0614:
0615: /**
0616: * Create a String from the given Collection, where the elements are delimited
0617: * with the supplied delimiter
0618: *
0619: * @return The elements of the Collection as a String
0620: * @param aList The list to process
0621: * @param aDelimiter The delimiter to use
0622: */
0623: public static final String listToString(Collection aList,
0624: char aDelimiter) {
0625: return listToString(aList, aDelimiter, false);
0626: }
0627:
0628: /**
0629: * Create a String from the given list, where the elements are delimited
0630: * with the supplied delimiter
0631: *
0632: * @return The elements of the Collection as a String
0633: * @param aList The list to process
0634: * @param aDelimiter The delimiter to use
0635: * @param quoteEntries if true, all entries are quoted with a double quote
0636: */
0637: public static final String listToString(Collection aList,
0638: char aDelimiter, boolean quoteEntries) {
0639: if (aList == null || aList.size() == 0)
0640: return "";
0641: int numElements = 0;
0642: StringBuilder result = new StringBuilder(aList.size() * 50);
0643: Iterator itr = aList.iterator();
0644: for (Object o : aList) {
0645: if (o == null)
0646: continue;
0647: if (numElements > 0) {
0648: result.append(aDelimiter);
0649: }
0650: if (quoteEntries)
0651: result.append('"');
0652: result.append(o.toString());
0653: if (quoteEntries)
0654: result.append('"');
0655: numElements++;
0656: }
0657: return result.toString();
0658: }
0659:
0660: public static final String trimQuotes(String input) {
0661: if (input == null)
0662: return null;
0663: if (input.length() == 0)
0664: return EMPTY_STRING;
0665: if (input.length() == 1)
0666: return input;
0667:
0668: String result = input.trim();
0669: int len = result.length();
0670: if (len == 0)
0671: return EMPTY_STRING;
0672: if (len == 1)
0673: return input;
0674:
0675: char firstChar = result.charAt(0);
0676: char lastChar = result.charAt(len - 1);
0677:
0678: if ((firstChar == '"' && lastChar == '"')
0679: || (firstChar == '\'' && lastChar == '\'')) {
0680: return result.substring(1, len - 1);
0681: }
0682: return input;
0683: }
0684:
0685: public static boolean stringToBool(String aString) {
0686: if (aString == null)
0687: return false;
0688: return ("true".equalsIgnoreCase(aString) || "1".equals(aString)
0689: || "y".equalsIgnoreCase(aString) || "yes"
0690: .equalsIgnoreCase(aString));
0691: }
0692:
0693: public static final String getMaxSubstring(String s, int maxLen,
0694: String add) {
0695: if (maxLen < 1)
0696: return s;
0697: if (s == null)
0698: return null;
0699: if (s.length() < maxLen)
0700: return s;
0701: if (add == null) {
0702: return s.substring(0, maxLen);
0703: } else {
0704: return s.substring(0, maxLen) + add;
0705: }
0706: }
0707:
0708: public static final String getMaxSubstring(String s, int maxLen) {
0709: return getMaxSubstring(s, maxLen, "...");
0710: }
0711:
0712: public static final String REGEX_SPECIAL_CHARS = "\\[](){}.*+?$^|";
0713:
0714: /**
0715: * Quote the characters in a String that have a special meaning
0716: * in regular expression.
0717: */
0718: public static String quoteRegexMeta(String str) {
0719: if (str == null)
0720: return null;
0721: if (str.length() == 0) {
0722: return "";
0723: }
0724: int len = str.length();
0725: StringBuilder buf = new StringBuilder(len + 5);
0726: for (int i = 0; i < len; i++) {
0727: char c = str.charAt(i);
0728: if (REGEX_SPECIAL_CHARS.indexOf(c) != -1) {
0729: buf.append('\\');
0730: }
0731: buf.append(c);
0732: }
0733: return buf.toString();
0734: }
0735:
0736: public static int findPreviousWhitespace(String data, int pos) {
0737: if (data == null)
0738: return -1;
0739: int count = data.length();
0740: if (pos > count || pos <= 1)
0741: return -1;
0742: for (int i = pos; i > 0; i--) {
0743: if (Character.isWhitespace(data.charAt(i)))
0744: return i;
0745: }
0746: return -1;
0747: }
0748:
0749: public static int findWordBoundary(String data, int pos,
0750: String wordBoundaries) {
0751: if (wordBoundaries == null)
0752: return findPreviousWhitespace(data, pos);
0753: if (data == null)
0754: return -1;
0755: int count = data.length();
0756: if (pos > count || pos <= 1)
0757: return -1;
0758: for (int i = pos; i > 0; i--) {
0759: char c = data.charAt(i);
0760: if (wordBoundaries.indexOf(c) > -1
0761: || Character.isWhitespace(c))
0762: return i;
0763: }
0764: return -1;
0765: }
0766:
0767: /**
0768: * Find the first non-quoted whitespace in the given String.
0769: *
0770: * @param data the data in which to search
0771: * @return the position of the first whitespace or -1 if no whitespace was found.
0772: */
0773: public static int findFirstWhiteSpace(CharSequence data) {
0774: if (data == null)
0775: return -1;
0776: int count = data.length();
0777: boolean inQuotes = false;
0778: for (int i = 0; i < count; i++) {
0779: char c = data.charAt(i);
0780: if (c == '"') {
0781: inQuotes = !inQuotes;
0782: }
0783: if (!inQuotes) {
0784: if (Character.isWhitespace(data.charAt(i)))
0785: return i;
0786: }
0787: }
0788: return -1;
0789: }
0790:
0791: public static final String getWordLeftOfCursor(String text,
0792: int pos, String wordBoundaries) {
0793: try {
0794: if (pos < 0)
0795: return null;
0796: int len = text.length();
0797: int testPos = -1;
0798: if (pos >= len) {
0799: testPos = len - 1;
0800: } else {
0801: testPos = pos - 1;
0802: }
0803: if (testPos < 1)
0804: return null;
0805:
0806: if (Character.isWhitespace(text.charAt(testPos)))
0807: return null;
0808:
0809: String word = null;
0810: int startOfWord = findWordBoundary(text, testPos,
0811: wordBoundaries);
0812: if (startOfWord > 0) {
0813: word = text.substring(startOfWord + 1, Math.min(pos,
0814: len));
0815: }
0816: return word;
0817: } catch (Exception e) {
0818: e.printStackTrace();
0819: return null;
0820: }
0821: }
0822:
0823: public static int findPattern(String regex, String data, int startAt) {
0824: Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
0825: return findPattern(p, data, startAt);
0826: }
0827:
0828: public static int findPattern(Pattern p, String data, int startAt) {
0829: if (startAt < 0)
0830: return -1;
0831: Matcher m = p.matcher(data);
0832: int result = -1;
0833: if (m.find(startAt))
0834: result = m.start();
0835: return result;
0836: }
0837:
0838: public static String decodeUnicode(String theString) {
0839: if (theString == null)
0840: return null;
0841:
0842: char aChar;
0843: int len = theString.length();
0844: if (len == 0)
0845: return theString;
0846: StringBuilder outBuffer = new StringBuilder(len);
0847:
0848: for (int x = 0; x < len;) {
0849: aChar = theString.charAt(x++);
0850: if (aChar == '\\' && x < len) {
0851: aChar = theString.charAt(x++);
0852:
0853: if (aChar == 'u') {
0854: // Read the xxxx
0855: int value = -1;
0856: int i = 0;
0857: for (i = 0; i < 4; i++) {
0858: if (x + i >= len) {
0859: value = -1;
0860: break;
0861: }
0862:
0863: aChar = theString.charAt(x + i);
0864: switch (aChar) {
0865: case '0':
0866: case '1':
0867: case '2':
0868: case '3':
0869: case '4':
0870: case '5':
0871: case '6':
0872: case '7':
0873: case '8':
0874: case '9':
0875: value = (value << 4) + aChar - '0';
0876: break;
0877: case 'a':
0878: case 'b':
0879: case 'c':
0880: case 'd':
0881: case 'e':
0882: case 'f':
0883: value = (value << 4) + 10 + aChar - 'a';
0884: break;
0885: case 'A':
0886: case 'B':
0887: case 'C':
0888: case 'D':
0889: case 'E':
0890: case 'F':
0891: value = (value << 4) + 10 + aChar - 'A';
0892: break;
0893: default:
0894: // Invalid ecape sequence
0895: value = -1;
0896: break;
0897: }
0898: if (value == -1)
0899: break;
0900: }
0901:
0902: if (value != -1) {
0903: outBuffer.append((char) value);
0904: } else {
0905: // Invalid encoded unicode character
0906: // do not convert the stuff, but copy the
0907: // characters into the result buffer
0908: outBuffer.append("\\u");
0909: if (i == 0 && x < len) {
0910: outBuffer.append(aChar);
0911: } else {
0912: for (int k = 0; k < i; k++)
0913: outBuffer.append(theString
0914: .charAt(x + k));
0915: }
0916: x++;
0917: }
0918: x += i;
0919: } else {
0920: // The character after the backslash was not a 'u'
0921: // so we are not dealing with a uXXXX value
0922: // This applies popular "encodings" for non-printable characters
0923: if (aChar == 't')
0924: aChar = '\t';
0925: else if (aChar == 'r')
0926: aChar = '\r';
0927: else if (aChar == 'n')
0928: aChar = '\n';
0929: else if (aChar == 'f')
0930: aChar = '\f';
0931: else if (aChar == '\\')
0932: aChar = '\\';
0933: else
0934: outBuffer.append('\\');
0935: outBuffer.append(aChar);
0936: }
0937: } else {
0938: outBuffer.append(aChar);
0939: }
0940:
0941: }
0942: return outBuffer.toString();
0943: }
0944:
0945: public static void dump(String value) {
0946: int size = value.length();
0947: for (int i = 0; i < size; i++) {
0948: int c = value.charAt(i);
0949: String s = Integer.toHexString(c);
0950: if (s.length() == 1)
0951: System.out.print("0");
0952: System.out.print(s);
0953: System.out.print(" ");
0954: }
0955: System.out.println("");
0956: }
0957:
0958: public static String escapeUnicode(String value,
0959: CharacterRange range) {
0960: return escapeUnicode(value, null, range, false);
0961: }
0962:
0963: /*
0964: * Converts unicodes to encoded \uxxxx
0965: * and writes out any of the characters in specialSaveChars
0966: * with a preceding slash.
0967: * This has partially been "borrowed" from the Properties class, because the code
0968: * there is not usable from the outside.
0969: * Backslash, CR, LF, Tab and FormFeed (\f) will always be replaced.
0970: */
0971: public static String escapeUnicode(String value,
0972: String specialSaveChars, CharacterRange range) {
0973: return escapeUnicode(value, specialSaveChars, range, false);
0974: }
0975:
0976: public static String escapeUnicode(String value,
0977: String specialSaveChars, CharacterRange range,
0978: boolean alwaysUnicode) {
0979: if (value == null)
0980: return null;
0981: // if (range == null || range == CharacterRange.RANGE_NONE) return value;
0982:
0983: int len = value.length();
0984: StringBuilder outBuffer = new StringBuilder(len * 2);
0985:
0986: for (int x = 0; x < len; x++) {
0987: char aChar = value.charAt(x);
0988: boolean replaced = false;
0989: if (!alwaysUnicode) {
0990: switch (aChar) {
0991: case '\\':
0992: outBuffer.append('\\');
0993: outBuffer.append('\\');
0994: replaced = true;
0995: break;
0996: case '\t':
0997: outBuffer.append('\\');
0998: outBuffer.append('t');
0999: replaced = true;
1000: break;
1001: case '\n':
1002: outBuffer.append('\\');
1003: outBuffer.append('n');
1004: replaced = true;
1005: break;
1006: case '\r':
1007: outBuffer.append('\\');
1008: outBuffer.append('r');
1009: replaced = true;
1010: break;
1011: case '\f':
1012: outBuffer.append('\\');
1013: outBuffer.append('f');
1014: replaced = true;
1015: break;
1016: default:
1017: replaced = false;
1018: }
1019: }
1020:
1021: if (!replaced) {
1022: if ((range != null && range.isOutsideRange(aChar))
1023: || (specialSaveChars != null && specialSaveChars
1024: .indexOf(aChar) > -1)) {
1025: outBuffer.append('\\');
1026: outBuffer.append('u');
1027: appendUnicode(outBuffer, aChar);
1028: } else {
1029: outBuffer.append(aChar);
1030: }
1031: }
1032: }
1033: return outBuffer.toString();
1034: }
1035:
1036: public static CharSequence getOctalString(int input) {
1037: StringBuilder result = new StringBuilder(3);
1038: String s = Integer.toOctalString(input);
1039:
1040: if (s.length() == 1) {
1041: result.append('0');
1042: result.append('0');
1043: } else if (s.length() == 2) {
1044: result.append('0');
1045: }
1046: result.append(s);
1047: return result;
1048: }
1049:
1050: public static String padRight(String input, int length) {
1051: if (input == null)
1052: return null;
1053: if (input.length() >= length)
1054: return input;
1055: StringBuilder result = new StringBuilder(length);
1056: result.append(input);
1057: while (result.length() < length) {
1058: result.append(' ');
1059: }
1060: return result.toString();
1061: }
1062:
1063: public static String formatNumber(int value, int length,
1064: boolean fillRight) {
1065: String s = NumberStringCache.getNumberString(value);
1066: int l = s.length();
1067: if (l >= length)
1068: return s;
1069: StringBuilder result = new StringBuilder(length);
1070: if (fillRight) {
1071: result.append(s);
1072: }
1073: for (int k = l; k < length; k++) {
1074: result.append(' ');
1075: }
1076: if (!fillRight) {
1077: result.append(s);
1078: }
1079: return result.toString();
1080: }
1081:
1082: private static void appendUnicode(StringBuilder buffer, char c) {
1083: buffer.append(hexDigit(c >> 12));
1084: buffer.append(hexDigit(c >> 8));
1085: buffer.append(hexDigit(c >> 4));
1086: buffer.append(hexDigit(c));
1087: }
1088:
1089: private static char hexDigit(int nibble) {
1090: return hexDigit[(nibble & 0xF)];
1091: }
1092:
1093: private static final char[] hexDigit = { '0', '1', '2', '3', '4',
1094: '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
1095:
1096: }
|