001: // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002: // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003: // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005: // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008: // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009: // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010: // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011: // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012: // POSSIBILITY OF SUCH DAMAGE.
013: //
014: // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015: package com.metaboss.util;
016:
017: import java.io.ByteArrayOutputStream;
018: import java.io.IOException;
019: import java.io.InputStream;
020: import java.util.NoSuchElementException;
021: import java.util.StringTokenizer;
022: import java.util.Vector;
023:
024: /** Set of useful utilites to do with string manipulations */
025: public class StringUtils {
026: static public String readTextStreamFully(InputStream str)
027: throws IOException {
028: ByteArrayOutputStream baos = null;
029: try {
030: baos = new ByteArrayOutputStream();
031: StreamUtils.copyData(str, baos);
032: baos.flush();
033: return baos.toString();
034: } finally {
035: if (baos != null)
036: baos.close();
037: }
038: }
039:
040: static public boolean isBlank(String str) {
041: // null?
042: if (str == null)
043: return (true);
044:
045: // blank?
046: if (str.length() == 0)
047: return true;
048:
049: // All spaces?
050: int spacesCount = 0;
051: for (int i = 0; i < str.length(); i++)
052: if (str.charAt(i) == ' ')
053: spacesCount++;
054: if (spacesCount == str.length())
055: return true;
056:
057: return false; // Its not blank!
058: }
059:
060: /** Returns string with certain number of spaces.
061: * @param lStepSize - the size of each step in indentation (e.g. 4 spaces per tab)
062: * @param lRequiredNumberOfSteps - the number of steps required
063: * @return string filled with blanks to required length
064: */
065: public static String getIndent(int lStepSize,
066: int lRequiredNumberOfSteps) {
067: if (lStepSize <= 0 || lRequiredNumberOfSteps <= 0)
068: return "";
069: StringBuffer lStepBuffer = new StringBuffer();
070: for (int i = 0; i < lStepSize; i++)
071: lStepBuffer.append(' ');
072: String lStepString = lStepBuffer.toString();
073:
074: StringBuffer lRequiredStringBuffer = new StringBuffer();
075: for (int i = 0; i < lRequiredNumberOfSteps; i++)
076: lRequiredStringBuffer.append(lStepString);
077: return lRequiredStringBuffer.toString();
078: }
079:
080: /** Returns string with every occurrence of the character specified in pFind replaced
081: * with the string specified in pReplace */
082: public static String replace(String pInput, char pFind,
083: String pReplace) {
084: if (pInput == null || pReplace == null)
085: return pInput;
086: StringBuffer sb = new StringBuffer();
087: for (int i = 0; i < pInput.length(); i++) {
088: char ch = pInput.charAt(i);
089: if (ch == pFind)
090: sb.append(pReplace);
091: else
092: sb.append(ch);
093: }
094: return sb.toString();
095: }
096:
097: /** Returns string with every occurrence of the string specified in pFind replaced
098: * with the string specified in pReplace */
099: public static String replace(String pInput, String pFind,
100: String pReplace) {
101: if (pInput == null || pReplace == null)
102: return pInput;
103: int lFindLen = pFind.length();
104: StringBuffer sb = new StringBuffer();
105: while (true) {
106: int pos = pInput.indexOf(pFind);
107: if (pos < 0) {
108: sb.append(pInput);
109: break;
110: }
111: sb.append(pInput.substring(0, pos));
112: sb.append(pReplace);
113: pInput = pInput.substring(pos + lFindLen);
114: }
115: return sb.toString();
116: }
117:
118: // Get the nth token from a string
119: static public String getToken(String str, String delim, int count) {
120: StringTokenizer st = new StringTokenizer(str, delim);
121: String token = null;
122: while (count-- >= 0) {
123: try {
124: token = st.nextToken();
125: } catch (NoSuchElementException nsex) {
126: return (null);
127: }
128: }
129:
130: return (token);
131: }
132:
133: /** Builds the string consisting of Token string concatenated TokenRepeatCount number of times
134: * with specified prefix, suffix and separator strings */
135: public static String fill(String pToken, String pPrefix,
136: String pSuffix, String pSeparator, int pTokenRepeatCount) {
137: StringBuffer lResult = new StringBuffer(pPrefix);
138: lResult.append(pToken);
139: for (int i = 1; i < pTokenRepeatCount; i++) {
140: lResult.append(pSeparator);
141: lResult.append(pToken);
142: }
143: lResult.append(pSuffix);
144: return lResult.toString();
145: }
146:
147: /** Combine specified number of elements into the single string
148: * filling the filler string in between tokens */
149: public static String combine(String[] pSource, String pFiller) {
150: return combine(pSource, pFiller, 0, pSource.length);
151: }
152:
153: /** Combine specified number of elements into the string
154: * using specified token separator. All elements starting from the beginIndex (inclusive) and up to
155: * (but not including) the endIndex will be used.
156: * @throws ArrayIndexOutOfBoundsException when specified indexes are out of bounds */
157: public static String combine(String[] pSource, String pFiller,
158: int beginIndex, int endIndex) {
159: StringBuffer lResult = new StringBuffer();
160: for (int i = beginIndex; i < endIndex; i++) {
161: if (i > beginIndex)
162: lResult.append(pFiller);
163: lResult.append(pSource[i]);
164: }
165: return lResult.toString();
166: }
167:
168: /** Split a string into tokens. Note that this predates the split facility
169: * available since JDK 1.4. The JDK facility should be used in preference to this */
170: public static String[] split(String val, String split) {
171: int pos;
172: Vector strs = new Vector();
173: boolean doit = true;
174: if (val == null)
175: return new String[0];
176:
177: for (int i = 0; doit; i++) {
178: pos = val.indexOf(split);
179: if (pos < 0) {
180: doit = false;
181: strs.addElement(val.trim());
182: break;
183: }
184: try {
185: strs.addElement(val.substring(0, pos).trim());
186: val = val.substring(pos + 1);
187: } catch (StringIndexOutOfBoundsException ex) {
188: doit = false;
189: }
190: }
191:
192: String retVal[] = new String[strs.size()];
193: for (int j = 0; j < strs.size(); j++) {
194: retVal[j] = (String) strs.elementAt(j);
195: }
196: return retVal;
197: }
198:
199: /**
200: * Returns string with value right justified, padded with spaces.
201: * If ield value is wider - field value only is returned
202: * @param fillerElement - most often single space, but can be " " for html
203: */
204: static public String rightJustify(int fieldWidth,
205: String fieldValue, String fillerElement) {
206: StringBuffer l_result = new StringBuffer(fillerElement.length()
207: * fieldWidth);
208:
209: int fillerWidth = fieldWidth - fieldValue.length();
210: if (fillerWidth > 0) {
211: for (int i = 0; i < fillerWidth; i++)
212: l_result.append(fillerElement);
213: }
214: l_result.append(fieldValue);
215: return l_result.toString();
216: }
217:
218: /**
219: * Returns string with value left justified, padded with spaces.
220: * If ield value is wider - field value only is returned
221: * @param fillerElement - most often single space, but can be " " for html
222: */
223: static public String leftJustify(int fieldWidth, String fieldValue,
224: String fillerElement) {
225: StringBuffer l_result = new StringBuffer(fillerElement.length()
226: * fieldWidth);
227:
228: l_result.append(fieldValue);
229: int fillerWidth = fieldWidth - fieldValue.length();
230:
231: if (fillerWidth > 0) {
232: for (int i = 0; i < fillerWidth; i++)
233: l_result.append(fillerElement);
234: }
235: return l_result.toString();
236: }
237:
238: /** Counts letters (Character.isLetter() == true) in the string */
239: public static int countLetters(String in) {
240: int counter = 0;
241: if (in != null) {
242: for (int index = 0; index < in.length(); index++) {
243: if (Character.isLetter(in.charAt(index)))
244: counter++;
245: }
246: }
247: return counter;
248: }
249:
250: private static final String sTruncationPrefix = "...(";
251: private static final String sTruncationSuffix = " more)...";
252: private static final int sTruncationPrefixAndSuffixCombinedLength = sTruncationPrefix
253: .length()
254: + sTruncationSuffix.length();
255:
256: /** This utility analyses given text and suggests derived string, which is very convenient to
257: * output for log. If given string length is more than required visible length
258: * the string is truncated and suffixed with "...(nnnn more)..." suffix. If however
259: * actual string is only a little more than required visible length and printing out the whole string
260: * will in fact take less space than trunctated string plus suffix - the entire string will be returned
261: * @param pText - the text for which we need to suggest the output
262: * @param pRequiredVisibleLength - the minimum length required to be visible
263: * @return suggestion on how to display the text */
264: public static String suggestTruncatedOutput(String pText,
265: int pRequiredVisibleLength) {
266: if (pText == null)
267: return "null";
268: int lTextLength = pText.length();
269: // Fast exit for short strings
270: if (lTextLength <= pRequiredVisibleLength)
271: return pText;
272: if (lTextLength <= (pRequiredVisibleLength + sTruncationPrefixAndSuffixCombinedLength))
273: return pText;
274: // Take into account the actual length of a number anc give string a last chance
275: int lTruncatedLength = lTextLength - pRequiredVisibleLength;
276: String lTruncatedLengthText = Integer
277: .toString(lTruncatedLength);
278: if (lTextLength <= (pRequiredVisibleLength
279: + sTruncationPrefixAndSuffixCombinedLength + lTruncatedLengthText
280: .length()))
281: return pText;
282: // Now we definitely need to truncate
283: StringBuffer lTempBuffer = new StringBuffer(pText.substring(0,
284: pRequiredVisibleLength));
285: lTempBuffer.append(sTruncationPrefix);
286: lTempBuffer.append(lTruncatedLengthText);
287: lTempBuffer.append(sTruncationSuffix);
288: return lTempBuffer.toString();
289: }
290:
291: /** This utility analyses given message string and suggests derived string, which
292: * should be used as pattern argument in the java.text.MessageFormat.
293: * Basically this utility takes care of the string constants and the escape characters.
294: * @param pMessageString - the text for which we need to format using java.text.MessageFormat
295: * @return suggestion String to be used in the pattern in the java.text.MessageFormat class */
296: public static String suggestMessageFormatPatternString(
297: String pMessageString) {
298: if (pMessageString == null)
299: return pMessageString;
300: return pMessageString.replaceAll("'", "''");
301: }
302:
303: /** This utility analyses given text and suggests derived name, which can be used as java constant identifier
304: * (e.g. Heart Beat Rate becomes HEART_BEAT_RATE). It will ignore all not java identifier characters
305: * prepend all upper case characters with '_' (unless there was '_' already) and uppercase them
306: * @return null if it can not suggest anything useful */
307: public static String suggestConstantIdentifier(String pText) {
308: if (pText == null)
309: return null;
310: String lText = pText.trim();
311: if (lText.length() == 0)
312: return null;
313: StringBuffer lProposedIdentifier = new StringBuffer();
314: StringTokenizer lTokenizer = new StringTokenizer(pText,
315: " \r\n\t", false);
316: boolean lHasPassedFirstChar = false;
317: boolean lLastCharacterWasUnderscore = false;
318: while (lTokenizer.hasMoreTokens()) {
319: if ((lHasPassedFirstChar) && (!lLastCharacterWasUnderscore)) {
320: lProposedIdentifier.append("_"); // Insert underscore between tokens
321: lLastCharacterWasUnderscore = true;
322: }
323: String lToken = lTokenizer.nextToken();
324: int lNameLength = lToken.length();
325: for (int i = 0; i < lNameLength; i++) {
326: char lChar = lToken.charAt(i);
327: if (lHasPassedFirstChar == false) {
328: // Do not allow '_' as the first character
329: if ((lChar != '_')
330: && (Character.isJavaIdentifierStart(lChar))) {
331: lProposedIdentifier.append(Character
332: .toUpperCase(lChar));
333: lHasPassedFirstChar = true;
334: lLastCharacterWasUnderscore = false;
335: }
336: } else {
337: if (lChar == '_') {
338: // Insert single underscore if appropriate, otherwise just skip it
339: if (!lLastCharacterWasUnderscore) {
340: lProposedIdentifier.append("_");
341: lLastCharacterWasUnderscore = true;
342: }
343: } else if (Character.isJavaIdentifierPart(lChar)) {
344: if (Character.isUpperCase(lChar)
345: && (!lLastCharacterWasUnderscore)) {
346: lProposedIdentifier.append("_"); // Insert underscore between tokens
347: lLastCharacterWasUnderscore = true;
348: }
349: lProposedIdentifier.append(Character
350: .toUpperCase(lChar));
351: lLastCharacterWasUnderscore = false;
352: }
353: }
354: }
355: }
356: String lConstantIdentifier = lProposedIdentifier.toString();
357: return (lConstantIdentifier.length() > 0) ? lConstantIdentifier
358: : null;
359: }
360:
361: /** This utility analyses given text and suggests derived name, which can be used as java identifier
362: * it will skip all not java identifier characters and replace all space characters with '_'
363: * @return null if it can not suggest anything useful */
364: public static String suggestJavaIdentifier(String pText) {
365: if (pText == null)
366: return null;
367: String lText = pText.trim();
368: if (lText.length() == 0)
369: return null;
370: StringBuffer lProposedIdentifier = new StringBuffer();
371: StringTokenizer lTokenizer = new StringTokenizer(pText,
372: " \r\n\t", false);
373: boolean lHasPassedFirstChar = false;
374: while (lTokenizer.hasMoreTokens()) {
375: if (lHasPassedFirstChar)
376: lProposedIdentifier.append("_"); // Insert underscore between tokens
377: String lToken = lTokenizer.nextToken();
378: int lNameLength = lToken.length();
379: for (int i = 0; i < lNameLength; i++) {
380: char lChar = lToken.charAt(i);
381: if (lHasPassedFirstChar == false) {
382: if (Character.isJavaIdentifierStart(lChar)) {
383: lProposedIdentifier.append(lChar);
384: lHasPassedFirstChar = true;
385: } else if (Character.isDigit(lChar)) {
386: // There may be a special case when identifier starts with digit.
387: // Digit is not a valid first character in Java, but we do not really want to strip it.
388: // In this case we will reluctantly start identifier from the underscore '_' character.
389: lProposedIdentifier.append("_"); // Insert underscore at the front
390: lProposedIdentifier.append(lChar);
391: lHasPassedFirstChar = true;
392: }
393: } else {
394: if (Character.isJavaIdentifierPart(lChar))
395: lProposedIdentifier.append(lChar);
396: }
397: }
398: }
399: String lJavaIdentifier = lProposedIdentifier.toString();
400: return (lJavaIdentifier.length() > 0) ? lJavaIdentifier : null;
401: }
402:
403: /** Counts digits (Character.isDigit() == true) in the string */
404: public static int countDigits(String in) {
405: int counter = 0;
406: if (in != null) {
407: for (int index = 0; index < in.length(); index++) {
408: if (Character.isDigit(in.charAt(index)))
409: counter++;
410: }
411: }
412: return counter;
413: }
414:
415: /** Shrinks text to one word, which than can be used as a name etc.
416: * This is achieved by getting rid of whiltespace and optional capitallisation of each first letter
417: * and optional decapitalisation of the other letters.
418: * For example 'text to name' with as delimiters becomes 'TextToName' */
419: public static String suggestName(String pText,
420: boolean pCapitaliseFirst, boolean pDecapitaliseOther) {
421: if (pText == null)
422: return null;
423: String lText = pText.trim();
424: if (lText.length() == 0)
425: return null;
426: StringBuffer lProposedName = new StringBuffer();
427: StringTokenizer lTokenizer = new StringTokenizer(pText,
428: " \r\n\t", false);
429: while (lTokenizer.hasMoreTokens()) {
430: String lToken = lTokenizer.nextToken();
431: int lNameLength = lToken.length();
432: boolean lProcessedFirstChar = false;
433: for (int i = 0; i < lNameLength; i++) {
434: char lChar = lToken.charAt(i);
435: if (Character.isLetterOrDigit(lChar)) {
436: if (lProcessedFirstChar == false) {
437: // Dealing with the first character of this token
438: if (pCapitaliseFirst)
439: lProposedName.append(Character
440: .toUpperCase(lChar));
441: else
442: lProposedName.append(lChar);
443: lProcessedFirstChar = true;
444: } else {
445: // Dealing with the subsequent character of this token
446: if (pDecapitaliseOther)
447: lProposedName.append(Character
448: .toLowerCase(lChar));
449: else
450: lProposedName.append(lChar);
451: }
452: }
453: }
454: }
455: String lName = lProposedName.toString();
456: return (lName.length() > 0) ? lName : null;
457: }
458:
459: /** Returns string which can be specified as String constant in order to represent given string.
460: * Mainly it means that the escape characters '\' are prepended with the other '\' in order for string constant to be correctly
461: * interpreted by Java compiler */
462: public static String suggestJavaStringConstant(String pString) {
463: if (pString == null)
464: return pString;
465: StringBuffer sb = new StringBuffer();
466: for (int i = 0; i < pString.length(); i++) {
467: char ch = pString.charAt(i);
468: if (ch == '\\')
469: sb.append('\\');
470: sb.append(ch);
471: }
472: return sb.toString();
473: }
474:
475: /** Converts string to the same string which starts from the lower case letter */
476: public static String toLowerCaseFirstCharacter(String pSourceString) {
477: if (pSourceString == null)
478: return pSourceString; // String is null
479: int lSourceStringLength = pSourceString.length();
480: if (lSourceStringLength == 0)
481: return pSourceString; // String is empty
482: char lFirstCharacter = pSourceString.charAt(0);
483: if (Character.isLetter(lFirstCharacter) == false
484: || Character.isLowerCase(lFirstCharacter) == true)
485: return pSourceString; // Nothing to convert
486: return Character.toString(Character
487: .toLowerCase(lFirstCharacter))
488: + ((lSourceStringLength > 1) ? pSourceString
489: .substring(1) : "");
490: }
491:
492: /** Converts string to the same string which starts from the upper case letter */
493: public static String toUpperCaseFirstCharacter(String pSourceString) {
494: if (pSourceString == null)
495: return pSourceString; // String is null
496: int lSourceStringLength = pSourceString.length();
497: if (lSourceStringLength == 0)
498: return pSourceString; // String is empty
499: char lFirstCharacter = pSourceString.charAt(0);
500: if (Character.isLetter(lFirstCharacter) == false
501: || Character.isUpperCase(lFirstCharacter) == true)
502: return pSourceString; // Nothing to convert
503: return Character.toString(Character
504: .toUpperCase(lFirstCharacter))
505: + ((lSourceStringLength > 1) ? pSourceString
506: .substring(1) : "");
507: }
508: }
|