0001: /* ====================================================================
0002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
0003: *
0004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * 1. Redistributions of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * 2. Redistributions in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * 3. The end-user documentation included with the redistribution,
0019: * if any, must include the following acknowledgment:
0020: * "This product includes software developed by Jcorporate Ltd.
0021: * (http://www.jcorporate.com/)."
0022: * Alternately, this acknowledgment may appear in the software itself,
0023: * if and wherever such third-party acknowledgments normally appear.
0024: *
0025: * 4. "Jcorporate" and product names such as "Expresso" must
0026: * not be used to endorse or promote products derived from this
0027: * software without prior written permission. For written permission,
0028: * please contact info@jcorporate.com.
0029: *
0030: * 5. Products derived from this software may not be called "Expresso",
0031: * or other Jcorporate product names; nor may "Expresso" or other
0032: * Jcorporate product names appear in their name, without prior
0033: * written permission of Jcorporate Ltd.
0034: *
0035: * 6. No product derived from this software may compete in the same
0036: * market space, i.e. framework, without prior written permission
0037: * of Jcorporate Ltd. For written permission, please contact
0038: * partners@jcorporate.com.
0039: *
0040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
0044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
0046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0051: * SUCH DAMAGE.
0052: * ====================================================================
0053: *
0054: * This software consists of voluntary contributions made by many
0055: * individuals on behalf of the Jcorporate Ltd. Contributions back
0056: * to the project(s) are encouraged when you make modifications.
0057: * Please send them to support@jcorporate.com. For more information
0058: * on Jcorporate Ltd. and its products, please see
0059: * <http://www.jcorporate.com/>.
0060: *
0061: * Portions of this software are based upon other open source
0062: * products and are subject to their respective licenses.
0063: */
0064:
0065: package com.jcorporate.expresso.core.misc;
0066:
0067: import com.jcorporate.expresso.kernel.util.FastStringBuffer;
0068:
0069: import java.io.PrintWriter;
0070: import java.io.StringWriter;
0071: import java.math.BigDecimal;
0072: import java.math.BigInteger;
0073: import java.util.Hashtable;
0074: import java.util.List;
0075: import java.util.Random;
0076: import java.util.StringTokenizer;
0077: import java.util.Vector;
0078:
0079: /**
0080: * This is class that consists of static methods, utilities for
0081: * manipulations of <code>java.lang.String</code>s.
0082: *
0083: * @author Michael Nash, Peter Pilgrim, Henri Yves AMAIZO
0084: */
0085: public final class StringUtil {
0086: public static final String EMPTY_STRING = "";
0087:
0088: /**
0089: * Make sure a string is not null. This is a convenience method, but it
0090: * is not necessarily recommended if you do a lot of processing for theMessage
0091: * parameter. It is recommended that you assertNotBlank, catch IllegalArgumentException
0092: * and then throw an appropriate exception with your message.
0093: *
0094: * @param theString Any string, possibly null
0095: * @param theMessage The error message to use if the argument is not null.
0096: */
0097: public static final void assertNotBlank(String theString,
0098: String theMessage) {
0099: if (theString == null) {
0100: throw new IllegalArgumentException(
0101: "Null argument not allowed: " + theMessage);
0102: }
0103: if (theString.trim().equals(EMPTY_STRING)) {
0104: throw new IllegalArgumentException(
0105: "Blank argument not allowed: " + theMessage);
0106: }
0107: } /* assertNotBlank(String, String) */
0108:
0109: /**
0110: * Make sure a string is not null.
0111: *
0112: * @param theString Any string, possibly null
0113: * @return An empty string if the original was null, else the original
0114: */
0115: public static final String notNull(String theString) {
0116: if (theString == null) {
0117: return EMPTY_STRING;
0118: }
0119:
0120: return theString;
0121: } /* notNull(String) */
0122:
0123: /**
0124: * Throws an exception if theString can't be mapped to a boolean value.
0125: *
0126: * @param theString the string to check
0127: * @param theMessage the message to have in the IllegalArgumentException
0128: * if the conditions aren't met.
0129: */
0130: public static final void assertBoolean(String theString,
0131: String theMessage) {
0132: assertNotBlank(theString, theMessage);
0133:
0134: if (!(theString.equalsIgnoreCase("yes")
0135: || theString.equalsIgnoreCase("true")
0136: || theString.equalsIgnoreCase("no")
0137: || theString.equalsIgnoreCase("false")
0138: || theString.equals("1") || theString.equals("0")
0139: || theString.equalsIgnoreCase("y") || theString
0140: .equalsIgnoreCase("n"))) {
0141: throw new IllegalArgumentException(theMessage);
0142: }
0143: }
0144:
0145: /**
0146: * parse a boolean value
0147: *
0148: * @param theString the string to parse
0149: * @return a boolean value parse from input; if input cannot be parsed, return false
0150: */
0151: public static final boolean toBoolean(String theString) {
0152: boolean result = false;
0153: if (theString != null) {
0154: // Rearranged with commons conditions first
0155: result = theString.equalsIgnoreCase("true")
0156: || theString.equals("1")
0157: || theString.equalsIgnoreCase("yes")
0158: || theString.equalsIgnoreCase("y")
0159: || theString.equalsIgnoreCase("on")
0160: || theString.equalsIgnoreCase("set");
0161: }
0162:
0163: return result;
0164: }
0165:
0166: /**
0167: * Same thing but using a serializable string as the parameter instead
0168: *
0169: * @param theString The string to check against null
0170: * @return theString or an empty string if it is null
0171: */
0172: public static String notNull(SerializableString theString) {
0173: if (theString == null) {
0174: return EMPTY_STRING;
0175: }
0176:
0177: return theString.toString();
0178: }
0179:
0180: /**
0181: * This method is useful for creating lists that use letters instead of
0182: * numbers, such as a, b, c, d...instead of 1, 2, 3, 4.
0183: * Valid numbers are from 1 to 26, corresponding to the 26 letters of the alphabet.
0184: * By default, the letter is returned as a lowercase, but if the boolean
0185: * upperCaseFlag is true, the letter will be returned as an uppercase.
0186: * Creation date: (5/11/00 12:52:23 PM)
0187: * author: Adam Rossi
0188: *
0189: * @param number The number to convert
0190: * @param upperCaseFlag True if you want the final data to be uppercase
0191: * @return java.lang.String
0192: */
0193: public static String numberToLetter(int number,
0194: boolean upperCaseFlag) throws IllegalArgumentException {
0195:
0196: //add nine to bring the numbers into the right range (in java, a= 10, z = 35)
0197: if (number < 1 || number > 26) {
0198: throw new IllegalArgumentException(
0199: "The number is out of the proper range (1 to "
0200: + "26) to be converted to a letter.");
0201: }
0202:
0203: int modnumber = number + 9;
0204: char thechar = Character.forDigit(modnumber, 36);
0205:
0206: if (upperCaseFlag) {
0207: thechar = Character.toUpperCase(thechar);
0208: }
0209:
0210: return "" + thechar;
0211: } /* numberToLetter(int, boolean) */
0212:
0213: /**
0214: * replace substrings within string.
0215: *
0216: * @param s The string to work with
0217: * @param sub The string to substitude the occurances of
0218: * @param with The string to replace with
0219: * @return A processed java.util.String
0220: */
0221: public static String replace(String s, String sub, String with) {
0222: if (s == null) {
0223: return null;
0224: }
0225: int c = 0;
0226: int i = s.indexOf(sub, c);
0227:
0228: if (i == -1) {
0229: return s;
0230: }
0231:
0232: FastStringBuffer buf = new FastStringBuffer(s.length()
0233: + with.length());
0234:
0235: do {
0236: buf.append(s.substring(c, i));
0237: buf.append(with);
0238: c = i + sub.length();
0239: } while ((i = s.indexOf(sub, c)) != -1);
0240:
0241: if (c < s.length()) {
0242: buf.append(s.substring(c, s.length()));
0243: }
0244:
0245: return buf.toString();
0246: } /* replace(String, String, String) */
0247:
0248: /**
0249: * Formats the string to an XML/XHTML escaped character. Useful for &'s, etc
0250: *
0251: * @param s the String to format
0252: * @return The escaped formatted String.
0253: * @see org.apache.xml.serialize.BaseMarkupSerializer for example of original
0254: * code.
0255: */
0256: public static String xmlEscape(String s) {
0257: int length = s.length();
0258: FastStringBuffer fsb = new FastStringBuffer(length);
0259:
0260: for (int i = 0; i < length; i++) {
0261: fsb = printEscaped(s.charAt(i), fsb);
0262: }
0263:
0264: return fsb.toString();
0265: }
0266:
0267: /**
0268: * Formats a particular character to something workable in xml Helper to xmlEscape()
0269: *
0270: * @param ch the character to print.
0271: * @param fsb The FastStringBuffer to add this to.
0272: * @return a FastStringBuffer that is modified
0273: */
0274: protected static FastStringBuffer printEscaped(char ch,
0275: FastStringBuffer fsb) {
0276: String charRef;
0277:
0278: // If there is a suitable entity reference for this
0279: // character, print it. The list of available entity
0280: // references is almost but not identical between
0281: // XML and HTML.
0282: charRef = getEntityRef(ch);
0283:
0284: if (charRef != null) {
0285: fsb.append('&');
0286: fsb.append(charRef);
0287: fsb.append(';');
0288:
0289: //ch<0xFF == isPrintable()
0290: } else if ((ch >= ' ' && ch < 0xFF && ch != 0xF7) || ch == '\n'
0291: || ch == '\r' || ch == '\t') {
0292:
0293: // If the character is not printable, print as character reference.
0294: // Non printables are below ASCII space but not tab or line
0295: // terminator, ASCII delete, or above a certain Unicode threshold.
0296: if (ch < 0x10000) {
0297: fsb.append(ch);
0298: } else {
0299: fsb
0300: .append((char) ((((int) ch - 0x10000) >> 10) + 0xd800));
0301: fsb
0302: .append((char) ((((int) ch - 0x10000) & 0x3ff) + 0xdc00));
0303: }
0304: } else {
0305: fsb.append("&#x");
0306: fsb.append(Integer.toHexString(ch));
0307: fsb.append(';');
0308: }
0309:
0310: return fsb;
0311: }
0312:
0313: /**
0314: * Helper to xmlEscape()
0315: *
0316: * @param ch the character to escape
0317: * @return A modified string representing the tanlation of the character
0318: * or null if there is no translation for it.
0319: */
0320: protected static String getEntityRef(int ch) {
0321:
0322: // Encode special XML characters into the equivalent character references.
0323: // These five are defined by default for all XML documents.
0324: switch (ch) {
0325: case '<':
0326: return "lt";
0327:
0328: case '>':
0329: return "gt";
0330:
0331: case '"':
0332: return "quot";
0333:
0334: case '\'':
0335: return "apos";
0336:
0337: case '&':
0338: return "amp";
0339: }
0340:
0341: return null;
0342: }
0343:
0344: /**
0345: * HTML code for ellipses (3 dots, like '...' as one character)
0346: * used for appending to a truncate() line if necessary
0347: */
0348: public static final String ELLIPSES = "…";
0349:
0350: /**
0351: * truncate a string at the given length if necessary,
0352: * adding an ellipses at the end if truncation occurred;
0353: * uses ELLIPSES static String from this class
0354: *
0355: * @param str The string to process
0356: * @param len The maximum length to process the string to.
0357: * @return the appropriately trimmed string.
0358: */
0359: public static String truncate(String str, int len) {
0360: String result = str;
0361: if (str.length() > len) {
0362: result = str.substring(0, len) + ELLIPSES;
0363: }
0364: return result;
0365: }
0366:
0367: /**
0368: * Map accent characters with equivalent without accent.
0369: * <p/>
0370: * author Henri Yves AMAIZO
0371: *
0372: * @return Hashtable Character mapping table.
0373: */
0374: public static Hashtable characterMap() {
0375: Hashtable characterMap = new Hashtable();
0376:
0377: characterMap.put(new Character('à'), new Character('a'));
0378: characterMap.put(new Character('â'), new Character('a'));
0379: characterMap.put(new Character('ä'), new Character('a'));
0380: characterMap.put(new Character('á'), new Character('a'));
0381: characterMap.put(new Character('À'), new Character('A'));
0382: characterMap.put(new Character('Á'), new Character('A'));
0383: characterMap.put(new Character('Â'), new Character('A'));
0384: characterMap.put(new Character('Ä'), new Character('A'));
0385: characterMap.put(new Character('è'), new Character('e'));
0386: characterMap.put(new Character('é'), new Character('e'));
0387: characterMap.put(new Character('ê'), new Character('e'));
0388: characterMap.put(new Character('ë'), new Character('e'));
0389: characterMap.put(new Character('È'), new Character('E'));
0390: characterMap.put(new Character('É'), new Character('E'));
0391: characterMap.put(new Character('Ê'), new Character('E'));
0392: characterMap.put(new Character('Ë'), new Character('E'));
0393: characterMap.put(new Character('î'), new Character('i'));
0394: characterMap.put(new Character('ï'), new Character('i'));
0395: characterMap.put(new Character('Î'), new Character('I'));
0396: characterMap.put(new Character('Ï'), new Character('I'));
0397: characterMap.put(new Character('ô'), new Character('o'));
0398: characterMap.put(new Character('ö'), new Character('o'));
0399: characterMap.put(new Character('Ô'), new Character('O'));
0400: characterMap.put(new Character('Ö'), new Character('O'));
0401: characterMap.put(new Character('û'), new Character('u'));
0402: characterMap.put(new Character('ü'), new Character('u'));
0403: characterMap.put(new Character('Û'), new Character('U'));
0404: characterMap.put(new Character('Ü'), new Character('U'));
0405: characterMap.put(new Character('ç'), new Character('c'));
0406: characterMap.put(new Character('Ç'), new Character('C'));
0407:
0408: return characterMap;
0409: }
0410:
0411: /**
0412: * Remove from the parameter the accent characters and
0413: * return the remain string or null if empty
0414: * <p/>
0415: * author Henri Yves AMAIZO
0416: *
0417: * @param s the string to remove the accent characters
0418: * @return String
0419: */
0420: public static String removeAccents(String s) {
0421: String out = null;
0422: if (s != null) {
0423: Hashtable charRemove = characterMap();
0424: StringBuffer sb = new StringBuffer();
0425: for (int i = 0; i < s.length(); i++) {
0426: Character c = new Character(s.charAt(i));
0427: if (charRemove.containsKey(c)) {
0428: c = (Character) charRemove.get(c);
0429: }
0430: sb.append(c.charValue());
0431: }
0432: out = sb.toString();
0433: }
0434: return out;
0435: }
0436:
0437: /**
0438: * Replace all comma by dot
0439: * <p/>
0440: * author Henri Yves AMAIZO
0441: *
0442: * @param str String to change
0443: * @return String The result of substitution
0444: */
0445: public static String convertCommaToDot(String str) {
0446: if (str == null) {
0447: return null;
0448: }
0449:
0450: return str.replace(',', '.');
0451: }
0452:
0453: /**
0454: * Compare 2 decimals string
0455: * <p/>
0456: * author Henri Yves AMAIZO
0457: *
0458: * @param decim1 First string to compare
0459: * @param decim2 Second string to compare
0460: * @return int return 1 if decim1 > decim2<BR> retourne 0 if decim1 == decim2<BR> return -1 if decim1 < decim2
0461: */
0462: public static int compareDecimals(String decim1, String decim2) {
0463: BigDecimal dec1 = new BigDecimal(decim1);
0464: BigDecimal dec2 = new BigDecimal(decim2);
0465: return dec1.compareTo(dec2);
0466: }
0467:
0468: /**
0469: * Compare 2 integers string.
0470: * <p/>
0471: * author Henri Yves AMAIZO
0472: *
0473: * @param int1 first string to compare
0474: * @param int2 second string to compare
0475: * @return int return 1 if decim1 > decim2<BR> return 0 if decim1 == decim2<BR> return -1 if decim1 < decim2
0476: */
0477: public static int compareIntegers(String int1, String int2) {
0478: BigInteger dec1 = new BigInteger(int1);
0479: BigInteger dec2 = new BigInteger(int2);
0480: return dec1.compareTo(dec2);
0481: }
0482:
0483: /**
0484: * Check if string is alphanumeric or not.
0485: * <p/>
0486: * author Henri Yves AMAIZO
0487: *
0488: * @param s String to check.
0489: * @return boolean true if alphanumeric, false if not.
0490: */
0491: public static boolean isAlphaNumeric(String s) {
0492: return isAlphaNumeric(s, "");
0493: }
0494:
0495: /**
0496: * Check if string is alphanumeric with addons chararcters or not.
0497: * <p/>
0498: * author Henri Yves AMAIZO
0499: *
0500: * @param str string to check
0501: * @param otherChars extra characters to check with
0502: * @return boolean true if parameter string contains only alpha numerics,<BR> plus addons characters and false if not.
0503: */
0504: public static boolean isAlphaNumeric(String str, String otherChars) {
0505: String alphaNum = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
0506: + otherChars;
0507: for (int i = 0; i < str.length(); i++) {
0508: if (alphaNum.indexOf(str.charAt(i)) == -1) {
0509: return false;
0510: }
0511: }
0512: return true;
0513: }
0514:
0515: /**
0516: * Check if an input string is an empty string, just contains
0517: * whitespace characters, or is <code>null</code>. If it is then
0518: * return <code>true</code>
0519: *
0520: * @param str the input string
0521: * @return boolean true if the string is blank or null
0522: */
0523: public static boolean isBlankOrNull(String str) {
0524: if (str == null) {
0525: return true;
0526: }
0527: if (str.trim().length() < 1) {
0528: return true;
0529: } else {
0530: return false;
0531: }
0532: }
0533:
0534: /**
0535: * Check if decimal number
0536: * <p/>
0537: * author Henri Yves AMAIZO
0538: *
0539: * @param s string to check.
0540: * @return boolean true if the value is decimal number false if not
0541: */
0542: public static boolean isDecimal(String s) {
0543: try {
0544: new BigDecimal(s);
0545: return true;
0546: } catch (NumberFormatException e) {
0547: return false;
0548: }
0549: }
0550:
0551: /**
0552: * Check if string pass is a vlaid email address
0553: * <p/>
0554: * author Henri Yves AMAIZO
0555: *
0556: * @param email string to check
0557: * @return int 0 if valid address, 1 more than 2 tokens (".", "@")<BR> and 2 if the second token is not "." .
0558: */
0559: public static int isEmail(String email) {
0560: StringTokenizer st = new StringTokenizer(email, "@");
0561:
0562: if (st.countTokens() != 2) {
0563: return 1;
0564: }
0565:
0566: st.nextToken();
0567: if (st.nextToken().indexOf(".") == -1) {
0568: return 2;
0569: }
0570:
0571: return 0;
0572: }
0573:
0574: /**
0575: * Check if integer string
0576: * <p/>
0577: * author Henri Yves AMAIZO
0578: *
0579: * @param str string to check
0580: * @return boolean true if all characters is digit
0581: */
0582: public static boolean isInteger(String str) {
0583: try {
0584: new BigInteger(str);
0585: return true;
0586: } catch (NumberFormatException e) {
0587: return false;
0588: }
0589: }
0590:
0591: /**
0592: * Check if number
0593: * author Henri Yves AMAIZO
0594: *
0595: * @param str to check
0596: * @return boolean
0597: */
0598: public static boolean isNumber(String str) {
0599: try {
0600: Double.parseDouble(str);
0601: return true;
0602: } catch (NumberFormatException ex) {
0603: return false;
0604: }
0605: }
0606:
0607: /**
0608: * Check French company siren number.
0609: * <p/>
0610: * author Henri Yves AMAIZO
0611: *
0612: * @param siren the company number
0613: * @return boolean true if ok.
0614: */
0615: public static boolean isSiren(String siren) {
0616: StringBuffer temp = new StringBuffer("");
0617: int value = 0;
0618:
0619: // Check if numeric digit.
0620: try {
0621: Double.parseDouble(siren);
0622: } catch (NumberFormatException nbe) {
0623: return false;
0624: }
0625:
0626: // string length must be 9
0627: if (siren.length() != 9) {
0628: return false;
0629: }
0630:
0631: //
0632: for (int i = 0; i < 9; i++) {
0633: int n = Integer.parseInt(siren.substring(i, i + 1))
0634: * (((i % 2) != 0) ? 2 : 1);
0635: temp.append(n);
0636: }
0637:
0638: // sum of all digits
0639: for (int i = 0; i < (temp.length()); i++) {
0640: value += Integer.parseInt(temp.substring(i, i + 1));
0641: }
0642:
0643: //value must divide by 10
0644: if ((value % 10) != 0) {
0645: return false;
0646: }
0647:
0648: return true;
0649: }
0650:
0651: /**
0652: * Check French company siret number
0653: * <p/>
0654: * author Henri Yves AMAIZO
0655: *
0656: * @param siret The siret number
0657: * @return boolean true if equivalent to siret number false if not.
0658: */
0659: public static boolean isSiret(String siret) {
0660: // Check the length
0661: if (siret.length() != 14) {
0662: return false;
0663: }
0664:
0665: //
0666: try {
0667: Double.parseDouble(siret);
0668: return isSiren(siret.substring(0, 9));
0669: } catch (NumberFormatException nfe) {
0670: return false;
0671: }
0672: }
0673:
0674: /**
0675: * Return empty string if parameter is null
0676: * <p/>
0677: * author Henri Yves AMAIZO
0678: *
0679: * @param s the parameter to check
0680: * @return String return the parameter if empty or if the string == null
0681: */
0682: public static String nullToEmpty(String s) {
0683: if (s == null) {
0684: return "";
0685: } else {
0686: return s;
0687: }
0688: }
0689:
0690: /**
0691: * Reformat string by converting "," by "."
0692: * <p/>
0693: * author Henri Yves AMAIZO
0694: *
0695: * @param str string to reformat
0696: * @return String return reformatted string.
0697: */
0698: public static String reformatDecimalString(String str) {
0699: if (str == null) {
0700: return null;
0701: }
0702:
0703: // replace all ',' by '.'
0704: str = str.replace(',', '.');
0705: try {
0706: Double.parseDouble(str);
0707: return str;
0708: } catch (NumberFormatException nbe) {
0709: return "";
0710: }
0711: }
0712:
0713: /**
0714: * Replace all dots byt comma
0715: * <p/>
0716: * author Henri Yves AMAIZO
0717: *
0718: * @param str string to change
0719: * @return String reformatted
0720: */
0721: public static String convertDotToComma(String str) {
0722: return str.replace('.', ',');
0723: }
0724:
0725: /**
0726: * Replace all occurences of key by value in text.
0727: * <p/>
0728: * author Henri Yves AMAIZO
0729: *
0730: * @param text string in
0731: * @param key occurence to replace
0732: * @param value string to use
0733: * @return String with the replace value
0734: */
0735: public static String replaceAll(String text, String key,
0736: String value) {
0737: if (text == null) {
0738: return null;
0739: }
0740:
0741: String buffer = text;
0742: if (buffer != null && key != null && value != null) {
0743: int length = key.length();
0744: for (int start = buffer.indexOf(key); start != -1; start = buffer
0745: .indexOf(key, start + value.length())) {
0746: buffer = buffer.substring(0, start) + value
0747: + buffer.substring(start + length);
0748: }
0749: }
0750: return buffer;
0751: }
0752:
0753: /**
0754: * Substituate once str1 by str2 in text
0755: * Commentaire Anglais
0756: * <p/>
0757: * author Henri Yves AMAIZO
0758: *
0759: * @param text search and replace in
0760: * @param str1 to search for
0761: * @param str2 to replace with
0762: * @return String replaced
0763: */
0764: static public String replaceStringOnce(String text, String str1,
0765: String str2) {
0766: return replaceString(text, str1, str2, 1);
0767: }
0768:
0769: /**
0770: * Substituate all occurence of str1 by str2 in text
0771: * <p/>
0772: * author Henri Yves AMAIZO
0773: *
0774: * @param text search and replace in
0775: * @param str1 search for
0776: * @param str2 replace with
0777: * @return String with all values replaced
0778: */
0779: static public String replaceString(String text, String str1,
0780: String str2) {
0781: return replaceString(text, str1, str2, -1);
0782: }
0783:
0784: /**
0785: * Replace n occurences of str1 in text by str2.
0786: * if n = -1 all occurrences are replaced
0787: * <p/>
0788: * author Henri Yves AMAIZO
0789: *
0790: * @param text search and replace in
0791: * @param str1 search for
0792: * @param str2 replace with
0793: * @param max int values of occrrences to replace
0794: * @return String replaced
0795: */
0796: static public String replaceString(String text, String str1,
0797: String str2, int max) {
0798: if (text == null) {
0799: return null;
0800: }
0801:
0802: StringBuffer buffer = new StringBuffer(text.length());
0803: int start = 0;
0804: int end = 0;
0805: while ((end = text.indexOf(str1, start)) != -1) {
0806: buffer.append(text.substring(start, end)).append(str2);
0807: start = end + str1.length();
0808: if (--max == 0) {
0809: break;
0810: }
0811: }
0812: buffer.append(text.substring(start));
0813: return buffer.toString();
0814: }
0815:
0816: /**
0817: * Convert string to list
0818: * <p/>
0819: * author Henri Yves AMAIZO
0820: *
0821: * @param s String comma delimited string to format
0822: * @return List
0823: */
0824: public static List string2List(String s) {
0825: return string2List(s, ",");
0826: }
0827:
0828: /**
0829: * Convert string to list using sep separator to divide
0830: * <p/>
0831: * author Henri Yves AMAIZO
0832: *
0833: * @param s String comma delimited string to format
0834: * @param sep a string containing the seprator characters
0835: * @return List
0836: */
0837: public static List string2List(String s, String sep) {
0838: return string2List(s, sep, s != null ? s.length()
0839: : Integer.MAX_VALUE);
0840: }
0841:
0842: /**
0843: * Convert string to list using sep separator to divide
0844: * <p/>
0845: * author Henri Yves AMAIZO
0846: *
0847: * @param s String comma delimited string to format
0848: * @param sep a string containing the seprator characters
0849: * @param maxSize the maximum size of the list
0850: * @return List
0851: */
0852: public static List string2List(String s, String sep, int maxSize) {
0853: List l = null;
0854: if (s != null) {
0855: l = new Vector();
0856: for (int i = 0; i < maxSize;) {
0857: int index = s.indexOf(sep, i);
0858: String token;
0859: if (index != -1) {
0860: token = s.substring(i, index);
0861: } else {
0862: token = s.substring(i);
0863: }
0864: if (token.length() > 0 && !token.equals(sep)) {
0865: l.add(token.trim());
0866: }
0867: i += token.length() + sep.length();
0868: }
0869: }
0870: return l;
0871: }
0872:
0873: /**
0874: * convert the first character of string in lower case
0875: * <p/>
0876: * author Henri Yves AMAIZO
0877: *
0878: * @param str String to un-upper case the first character
0879: * @return String
0880: */
0881: static public String unUpperFirstChar(String str) {
0882: if (str == null) {
0883: return null;
0884: }
0885:
0886: FastStringBuffer fsb = null;
0887: ;
0888: try {
0889: fsb = FastStringBuffer.getInstance();
0890: fsb.append(Character.toLowerCase(str.charAt(0)));
0891: fsb.append(str.substring(1));
0892: return fsb.toString();
0893: } finally {
0894: if (fsb != null) {
0895: fsb.release();
0896: }
0897: }
0898: }
0899:
0900: /**
0901: * convert the first character of the string upper case
0902: * <p/>
0903: * author Henri Yves AMAIZO
0904: *
0905: * @param str String to make the first character upper.
0906: * @return String
0907: */
0908: static public String upperFirstChar(String str) {
0909: if (str == null) {
0910: return null;
0911: }
0912:
0913: FastStringBuffer fsb = FastStringBuffer.getInstance();
0914: try {
0915: fsb.append(Character.toTitleCase(str.charAt(0)));
0916: fsb.append(str.substring(1));
0917: return fsb.toString();
0918: } finally {
0919: fsb.release();
0920: }
0921:
0922: // return "" + Character.toTitleCase(str.charAt(0)) + str.substring(1);
0923: }
0924:
0925: /**
0926: * Repeat str n time to format another string.
0927: * <p/>
0928: * author Henri Yves AMAIZO
0929: *
0930: * @param str String to repeat
0931: * @param n int n repeat
0932: * @return String
0933: */
0934: static public String repeatString(String str, int n) {
0935: if (str == null) {
0936: return null;
0937: }
0938:
0939: FastStringBuffer buffer = FastStringBuffer.getInstance();
0940: try {
0941: //FastStringBuffer is preallocated for 1K, so we may not
0942: //need to do any memory allocation here.
0943: int val = n * str.length();
0944: if (val > buffer.capacity()) {
0945: buffer.ensureCapacity(val);
0946: }
0947: // StringBuffer buffer = new StringBuffer(n * str.length());
0948: for (int i = 0; i < n; i++) {
0949: buffer.append(str);
0950: }
0951: return buffer.toString();
0952: } finally {
0953: buffer.release();
0954: }
0955: }
0956:
0957: /**
0958: * enclosed the string with padding character.
0959: * Space is padding character
0960: * <p/>
0961: * author Henri Yves AMAIZO
0962: *
0963: * @param str String str string to center padding
0964: * @param n int n size of the new string
0965: * @return String Result
0966: */
0967: static public String centerPad(String str, int n) {
0968: return centerPad(str, n, " ");
0969: }
0970:
0971: /**
0972: * Enclosed the string with padding character
0973: * <p/>
0974: * author Henri Yves AMAIZO
0975: *
0976: * @param str String str string to pad with
0977: * @param n int n size of the final string
0978: * @param delim String delim padding character
0979: * @return String result of the center padding
0980: */
0981: static public String centerPad(String str, int n, String delim) {
0982: if (str == null) {
0983: return null;
0984: }
0985:
0986: int sz = str.length();
0987: int p = n - sz;
0988: if (p < 1) {
0989: return str;
0990: }
0991: str = leftPad(str, sz + p / 2, delim);
0992: str = rightPad(str, n, delim);
0993: return str;
0994: }
0995:
0996: /**
0997: * Right padding with delimiter
0998: * <p/>
0999: * author Henri Yves AMAIZO
1000: *
1001: * @param str String
1002: * @param n int size of the final string
1003: * @param delim padding character
1004: * @return String padding string
1005: */
1006: static public String rightPad(String str, int n, String delim) {
1007: if (str == null) {
1008: return null;
1009: }
1010:
1011: int sz = str.length();
1012: n = (n - sz) / delim.length();
1013: if (n > 0) {
1014: str += repeatString(delim, n);
1015: }
1016: return str;
1017: }
1018:
1019: /**
1020: * Right padding
1021: * delimiter is space
1022: * <p/>
1023: * author Henri Yves AMAIZO
1024: *
1025: * @param str String
1026: * @param n int size of the new string
1027: * @return String
1028: */
1029: static public String rightPad(String str, int n) {
1030: return rightPad(str, n, " ");
1031: }
1032:
1033: /**
1034: * Left padding
1035: * padding character is space
1036: * <p/>
1037: * author Henri Yves AMAIZO
1038: *
1039: * @param str String
1040: * @param n int size of the new string
1041: * @return String
1042: */
1043: static public String leftPad(String str, int n) {
1044: return leftPad(str, n, " ");
1045: }
1046:
1047: /**
1048: * Left padding
1049: * <p/>
1050: * author Henri Yves AMAIZO
1051: *
1052: * @param str String
1053: * @param n int size of the new string
1054: * @param delim padding character
1055: * @return String result
1056: */
1057: static public String leftPad(String str, int n, String delim) {
1058: if (str == null) {
1059: return null;
1060: }
1061: int sz = str.length();
1062: n = (n - sz) / delim.length();
1063: if (n > 0) {
1064: str = repeatString(delim, n) + str;
1065: }
1066: return str;
1067: }
1068:
1069: /**
1070: * Reverse the String.
1071: *
1072: * @param str the String to reverse.
1073: * @return a reversed string
1074: */
1075: static public String reverseString(String str) {
1076: if (str == null) {
1077: return null;
1078: }
1079: FastStringBuffer fsb = FastStringBuffer.getInstance();
1080: try {
1081: fsb.append(str);
1082: return fsb.reverse().toString();
1083: } finally {
1084: fsb.release();
1085: }
1086: }
1087:
1088: /**
1089: * Reverse the character case in the string
1090: * <p/>
1091: * author Henri Yves AMAIZO
1092: *
1093: * @param str String
1094: * @return String
1095: */
1096: static public String swapCase(String str) {
1097: if (str == null) {
1098: return null;
1099: }
1100:
1101: int sz = str.length();
1102: FastStringBuffer buffer = FastStringBuffer.getInstance();
1103: // StringBuffer buffer = new StringBuffer(sz);
1104: try {
1105: if (sz > buffer.capacity()) {
1106: buffer.ensureCapacity(sz);
1107: }
1108: boolean whiteSpace = false;
1109: char ch = 0;
1110: char tmp = 0;
1111: for (int i = 0; i < sz; i++) {
1112: ch = str.charAt(i);
1113: if (Character.isUpperCase(ch)) {
1114: tmp = Character.toLowerCase(ch);
1115: } else if (Character.isTitleCase(ch)) {
1116: tmp = Character.toLowerCase(ch);
1117: } else if (Character.isLowerCase(ch)) {
1118: if (whiteSpace) {
1119: tmp = Character.toTitleCase(ch);
1120: } else {
1121: tmp = Character.toUpperCase(ch);
1122: }
1123: }
1124: buffer.append(tmp);
1125: whiteSpace = Character.isWhitespace(ch);
1126: }
1127: return buffer.toString();
1128: } finally {
1129: buffer.release();
1130: }
1131: }
1132:
1133: /**
1134: * Create a random string
1135: * author Henri Yves AMAIZO
1136: *
1137: * @param count size of string.
1138: * @return randomly generated string of size count
1139: */
1140: static public String random(int count) {
1141: return random(count, false, false);
1142: }
1143:
1144: /**
1145: * Create a random Ascii String
1146: * author Henri Yves AMAIZO
1147: *
1148: * @param count the size of the string
1149: * @return randomly generated string of size count
1150: */
1151: static public String randomAscii(int count) {
1152: return random(count, 32, 127, false, false);
1153: }
1154:
1155: /**
1156: * Create a random character only string
1157: * author Henri Yves AMAIZO
1158: *
1159: * @param count size of string
1160: * @return randomly generated string of size count
1161: */
1162: static public String randomAlphabetic(int count) {
1163: return random(count, true, false);
1164: }
1165:
1166: /**
1167: * Create a random alpha numeric string
1168: * author Henri Yves AMAIZO
1169: *
1170: * @param count the size of the string
1171: * @return randomly generated string of size count
1172: */
1173: static public String randomAlphanumeric(int count) {
1174: return random(count, true, true);
1175: }
1176:
1177: /**
1178: * Create a random numeric string
1179: * author Henri Yves AMAIZO
1180: *
1181: * @param count the size of the final string
1182: * @return randomly generated string of size count
1183: */
1184: static public String randomNumeric(int count) {
1185: return random(count, false, true);
1186: }
1187:
1188: /**
1189: * Create a random numeric string where you have control over size, and
1190: * whether you want letters, numbers, or both.
1191: * <p/>
1192: * author Henri Yves AMAIZO
1193: *
1194: * @param count the size of the string
1195: * @param letters true if you want letters included
1196: * @param numbers true if you want numbers included
1197: * @return randomly generated string of size count
1198: */
1199: static public String random(int count, boolean letters,
1200: boolean numbers) {
1201: return random(count, 0, 0, letters, numbers);
1202: }
1203:
1204: /**
1205: * Create a random numeric string where you have control over size, and
1206: * whether you want letters, numbers, as well as ANSI minimum and maximum values
1207: * of the characters.
1208: * author Henri Yves AMAIZO
1209: *
1210: * @param count the size of the string
1211: * @param start int minimum 'value' of the character
1212: * @param end maximum 'value' of the character
1213: * @param letters true if you want letters included
1214: * @param numbers true if you want numbers included
1215: * @return randomly generated string of size count
1216: */
1217: static public String random(int count, int start, int end,
1218: boolean letters, boolean numbers) {
1219: return random(count, start, end, letters, numbers, null);
1220: }
1221:
1222: /**
1223: * Create a random numeric string where you have control over size, and
1224: * whether you want letters, numbers, as well as ANSI minimum and maximum values
1225: * of the characters.
1226: * author Henri Yves AMAIZO
1227: *
1228: * @param count the size of the string
1229: * @param start int minimum 'value' of the character
1230: * @param end maximum 'value' of the character
1231: * @param letters true if you want letters included
1232: * @param numbers true if you want numbers included
1233: * @param set the set of possible characters that you're willing to let
1234: * the string contain. may be null if all values are open.
1235: * @return randomly generated string of size count
1236: * @todo make this cryptographically string
1237: */
1238: static public String random(int count, int start, int end,
1239: boolean letters, boolean numbers, char[] set) {
1240: if ((start == 0) && (end == 0)) {
1241: end = (int) 'z';
1242: start = (int) ' ';
1243: if (!letters && !numbers) {
1244: start = 0;
1245: end = Integer.MAX_VALUE;
1246: }
1247: }
1248: Random rnd = new Random();
1249: // StringBuffer buffer = new StringBuffer();
1250: FastStringBuffer buffer = FastStringBuffer.getInstance();
1251: try {
1252: int gap = end - start;
1253: while (count-- != 0) {
1254: char ch;
1255: if (set == null) {
1256: ch = (char) (rnd.nextInt(gap) + start);
1257: } else {
1258: ch = set[rnd.nextInt(gap) + start];
1259: }
1260: if ((letters && numbers && Character
1261: .isLetterOrDigit(ch))
1262: || (letters && Character.isLetter(ch))
1263: || (numbers && Character.isDigit(ch))
1264: || (!letters && !numbers)) {
1265: buffer.append(ch);
1266: } else {
1267: count++;
1268: }
1269: }
1270: return buffer.toString();
1271: } finally {
1272: buffer.release();
1273: }
1274: }
1275:
1276: /**
1277: * Create a random string
1278: * author Henri Yves AMAIZO
1279: *
1280: * @param count the size of the string
1281: * @param set the set of characters that are allowed
1282: * @return randomly generated string of size count
1283: */
1284: static public String random(int count, String set) {
1285: return random(count, set.toCharArray());
1286: }
1287:
1288: /**
1289: * Create a random string
1290: * author Henri Yves AMAIZO
1291: *
1292: * @param count the size of the string
1293: * @param set the set of characters that are allowed
1294: * @return randomly generated string of size count
1295: */
1296: static public String random(int count, char[] set) {
1297: return random(count, 0, set.length - 1, false, false, set);
1298: }
1299:
1300: /**
1301: * return empty string the string is null
1302: * <p/>
1303: * author Henri Yves AMAIZO
1304: *
1305: * @param str The string to split String
1306: * @param lg the length to subgstring
1307: * @return a substring of parameter str.
1308: */
1309: public static String substring(String str, int lg) {
1310: return substring(str, 0, lg);
1311: }
1312:
1313: /**
1314: * return empty string the string is null
1315: * <p/>
1316: * author Henri Yves AMAIZO
1317: *
1318: * @param str The string to split String
1319: * @param start the location to start
1320: * @param end the end location of the substring
1321: * @return a substring of parameter str.
1322: */
1323: public static String substring(String str, int start, int end) {
1324: if (str == null || str.length() <= start) {
1325: return null;
1326: } else if (str.length() >= end) {
1327: return str.substring(start, end);
1328: } else {
1329: return str.substring(start);
1330: }
1331: }
1332:
1333: /**
1334: * utility to get just name of class
1335: *
1336: * @param obj the object of the given class, the name of which will be returned
1337: * @return name of class, less any package prefix
1338: */
1339: public static String omitPackages(Object obj) {
1340: int i = obj.getClass().getPackage().getName().length();
1341: if (i > 0) {
1342: i++;
1343: }
1344: return obj.getClass().getName().substring(i);
1345: }
1346:
1347: /**
1348: * utility to get just name of class
1349: *
1350: * @param theclass the given class, the name of which will be returned
1351: * @return name of class, less any package prefix
1352: */
1353: public static String omitPackages(Class theclass) {
1354: int i = theclass.getPackage().getName().length();
1355: if (i > 0) {
1356: i++;
1357: }
1358: return theclass.getName().substring(i);
1359: }
1360:
1361: /**
1362: * A utility method to return an exception stacktrace as a String
1363: * <p/>
1364: * <p><small>Written by Peter Pilgrim Mon Mar 15 23:12:15 GMT 2004</small></p>
1365: */
1366: public static String getStackTraceAsString(Throwable t) {
1367: StringWriter swriter = new StringWriter();
1368: PrintWriter pwriter = new PrintWriter(swriter);
1369: t.printStackTrace(pwriter);
1370: pwriter.flush();
1371: return swriter.toString();
1372: }
1373:
1374: /**
1375: * Concatenate array of string into one string with constant delimiter <code>", "</code>
1376: * <p/>
1377: * <p><small>Written by Peter Pilgrim Mon Mar 15 23:12:15 GMT 2004</small></p>
1378: *
1379: * @param input the input array string
1380: * @return the joined string
1381: */
1382: public static String join(String[] input) {
1383: return join(input, ", ");
1384: }
1385:
1386: /**
1387: * Concatenate array of string into one string with delimiter
1388: * <p/>
1389: * <p><small>Written by Peter Pilgrim Mon Mar 15 23:12:15 GMT 2004</small></p>
1390: *
1391: * @param input the input array string
1392: * @param delimiter the delimiter
1393: * @return the joined string
1394: */
1395: public static String join(String[] input, String delimiter) {
1396: if (input == null) {
1397: return "";
1398: }
1399:
1400: StringBuffer buf = new StringBuffer();
1401: for (int q = 0; q < input.length; ++q) {
1402: if (q > 0) {
1403: buf.append(delimiter);
1404: }
1405:
1406: buf.append(input[q]);
1407: }
1408:
1409: return buf.toString();
1410: }
1411:
1412: /**
1413: * Take an input string S, break the string into parts of N up to
1414: * 72 characters long which word wrapped with respective to blank
1415: * space characters and separated with the newline
1416: * characters. This static call has parameters set up for
1417: * electronic mail standards.
1418: * <p/>
1419: * <p><small>Written by Peter Pilgrim Mon Mar 15 23:12:15 GMT 2004</small></p>
1420: *
1421: * @param input the input string
1422: * @return wrapped broken string
1423: * @see #createWordWrappedString( String input, int fixedLength, String delimiter )
1424: */
1425: public static String createWordWrappedString(String input) {
1426: return createWordWrappedString(input, 72, "\n");
1427: }
1428:
1429: /**
1430: * Take an input string S, break the string into parts of N up to
1431: * F characters long which word wrapped with respective to blank
1432: * space characters and separated with the supplied delimiter D.
1433: * <p/>
1434: * <p><small>Written by Peter Pilgrim Mon Mar 15 23:12:15 GMT 2004</small></p>
1435: *
1436: * @param input the input string
1437: * @param fixedLength the maximum fixed length
1438: * @param delimiter the delimiter
1439: * @return wrapped broken string
1440: */
1441: public static String createWordWrappedString(String input,
1442: int fixedLength, String delimiter) {
1443: int inputLength = input.length();
1444: char c;
1445:
1446: // Case #1 Initial string is smaller than the fixed length
1447: if (inputLength < fixedLength) {
1448: return input;
1449: }
1450:
1451: // Case #2 Word wrapping is required
1452: StringBuffer buf = new StringBuffer(1024);
1453: int pos = 0; // current cursor position
1454: int lineLength = 0; // the line length
1455: while (pos < inputLength) {
1456: // System.out.println( "start:"+start+" end:"+end+" buf:["+buf.toString()+"]" );
1457:
1458: // Read the white space
1459: c = input.charAt(pos);
1460: while (pos < inputLength && Character.isWhitespace(c)) {
1461: buf.append(c);
1462: if (c == '\t')
1463: // If current character is a tab increase the line length
1464: {
1465: lineLength += 8;
1466: } else if (c == '\n')
1467: // If current character is a new line, reset the line length
1468: {
1469: lineLength = 0;
1470: } else
1471: // Increase line space by one
1472: {
1473: ++lineLength;
1474: }
1475:
1476: ++pos; /*1*/
1477: if (pos < inputLength) {
1478: c = input.charAt(pos); /*2*/
1479: }
1480: }
1481:
1482: // Read the word
1483: StringBuffer word = new StringBuffer(64);
1484: if (pos < inputLength) {
1485: c = input.charAt(pos);
1486: }
1487: while (pos < inputLength && !Character.isWhitespace(c)) {
1488: word.append(c);
1489: ++pos; /*1*/
1490: if (pos < inputLength) {
1491: c = input.charAt(pos); /*2*/
1492: }
1493: }
1494:
1495: int wordLength = word.length();
1496: if (lineLength + wordLength >= fixedLength) {
1497: // Force a word wrap here, because the length of the
1498: // text line exceeds the fixed length
1499: buf.append(delimiter);
1500: lineLength = 0;
1501: }
1502:
1503: // Add the word
1504: buf.append(word);
1505: lineLength += wordLength;
1506: }
1507:
1508: return buf.toString();
1509: }
1510:
1511: public static void main(String args[]) {
1512: // 01234567890123456789
1513: String text = "CAT SAT ON THE MAT";
1514:
1515: String textResult = createWordWrappedString(text, 12, "\n");
1516:
1517: System.out.println(textResult);
1518:
1519: }
1520:
1521: /**
1522: * remove surrounding quote marks (either "" or ''), only if quotes are at both the beginning and end of the string
1523: *
1524: * @param s string for testing
1525: * @return string which has surrounding quotes, if any, removed
1526: */
1527: public static String unquote(String s) {
1528: String result = s;
1529: if (startsAndEnds(s, "\"") || startsAndEnds(s, "'")) {
1530: result = s.substring(1, s.length() - 1);
1531: }
1532:
1533: return result;
1534: }
1535:
1536: /**
1537: * determine whether a string both starts and ends with the given substring
1538: *
1539: * @param s string to look at
1540: * @param search substring to search for
1541: * @return true if string is surrounded by search string
1542: */
1543: public static boolean startsAndEnds(String s, String search) {
1544: if (s != null && s.length() >= 2 && s.startsWith(search)
1545: && s.endsWith(search)) {
1546: return true;
1547: }
1548:
1549: return false;
1550: }
1551:
1552: } /* StringUtil */
|