001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.uml.util;
043:
044: import java.util.ArrayList;
045: import java.util.Arrays;
046: import java.util.Enumeration;
047: import java.util.Iterator;
048: import java.util.LinkedList;
049: import java.util.List;
050: import java.util.StringTokenizer;
051:
052: /**
053: * A complement to <code>java.util.StringTokenizer</code> that provides
054: * tokenizing by substrings instead of single characters as well as static
055: * utility methods for standard tasks.
056: * This class is semantically compatible with StringTokenizer. There is
057: * not a default delimiter as there is with
058: * <code>java.util.StringTokenizer</code>. There is only a single delimiter
059: * whereas <code>java.util.StringTokenizer</code> allows for multiple
060: * characters. The delimiter may be optionally case sensitive.
061: *
062: * @see "java.util.StringTokenizer"
063: *
064: * @author Todd Fast, todd.fast@sun.com
065: * @author Mike Frisino, michael.frisino@sun.com
066: */
067: public class StringTokenizer2 extends Object implements Enumeration,
068: Iterator {
069: /**
070: * Create tokenizer with property <code>returnTokens</code> set to
071: * <code>false</code> and property <code>ignoreCase</code> set to
072: * <code>false</code>. Blank delimiter results in the entire text
073: * as a single token.
074: *
075: * @param text string to be parsed (must not be null)
076: * @param delimiter to be be used to tokenize text (must not be null)
077: *
078: */
079: public StringTokenizer2(String text, String delimiter) {
080: this (text, delimiter, false);
081: }
082:
083: /**
084: * Create tokenizer with option for property <code>returnTokens</code>
085: * and property <code>ignoreCase</code> set to <code>false</code>. Blank
086: * delimiter results in the entire text as a single token.
087: *
088: * @param text string to be parsed (must not be null)
089: * @param delimiter to be be used to tokenize text (must not be null)
090: * @param returnTokens mimics <code>java.util.StringTokenizer</code> in that when <code>true</code> delimiters are returned as tokens
091: */
092: public StringTokenizer2(String text, String delimiter,
093: boolean returnTokens) {
094: this (text, delimiter, returnTokens, false);
095: }
096:
097: /**
098: * Create tokenizer with options for properties
099: * <code>returnTokens</code> and <code>ignoreCase</code>. Blank delimiter
100: * results in the entire text as a single token.
101: *
102: * @param text string to be parsed (must not be null)
103: * @param delimiter to be be used to tokenize text (must not be null)
104: * @param returnTokens mimics <code>java.util.StringTokenizer</code> in that when <code>true</code> delimiters are returned as tokens
105: * @param ignoreCase delimiters not case sensitive when <code>true</code>
106: */
107: public StringTokenizer2(String text, String delimiter,
108: boolean returnTokens, boolean ignoreCase) {
109: super ();
110: this .text = text;
111: this .delimiter = delimiter;
112: this .returnDelimiterTokens = returnTokens;
113: parse(ignoreCase);
114: }
115:
116: /**
117: *
118: *
119: */
120: private void parse(boolean ignoreCase) {
121: String matchText = null;
122: String matchDelim = null;
123:
124: if (ignoreCase) {
125: matchText = text.toUpperCase();
126: matchDelim = delimiter.toUpperCase();
127: } else {
128: matchText = text;
129: matchDelim = delimiter;
130: }
131:
132: int startIndex = 0;
133: int endIndex = matchText.indexOf(matchDelim, startIndex);
134: while (endIndex != -1) {
135: String token = text.substring(startIndex, endIndex);
136: parsedTokens.add(token);
137: if (returnDelimiterTokens)
138: parsedTokens.add(delimiter);
139: startIndex = endIndex + delimiter.length();
140: endIndex = matchText.indexOf(matchDelim, startIndex);
141: }
142:
143: parsedTokens.add(text.substring(startIndex));
144: }
145:
146: /**
147: *
148: * @see "java.util.StringTokenizer.hasNext()"
149: */
150: public boolean hasNext() {
151: return hasMoreTokens();
152: }
153:
154: /**
155: *
156: * @see "java.util.StringTokenizer.next()"
157: */
158: public Object next() {
159: return nextToken();
160: }
161:
162: /**
163: * Feature not supported
164: *
165: */
166: public void remove() {
167: throw new UnsupportedOperationException();
168: }
169:
170: /**
171: *
172: * @see "java.util.StringTokenizer.hasMoreTokens()"
173: */
174: public boolean hasMoreTokens() {
175: return tokenIndex < parsedTokens.size();
176: }
177:
178: /**
179: *
180: * @see "java.util.StringTokenizer.hasMoreElements()"
181: */
182: public boolean hasMoreElements() {
183: return hasMoreTokens();
184: }
185:
186: /**
187: *
188: * @see "java.util.StringTokenizer.countTokens()"
189: */
190: public int countTokens() {
191: return parsedTokens.size();
192: }
193:
194: /**
195: *
196: * @see "java.util.StringTokenizer.nextToken()"
197: */
198: public String nextToken() {
199: return (String) parsedTokens.get(tokenIndex++);
200: }
201:
202: /**
203: *
204: * @see "java.util.StringTokenizer.nextElement()"
205: */
206: public Object nextElement() {
207: return nextToken();
208: }
209:
210: ////////////////////////////////////////////////////////////////////////////////
211: // Static utility methods
212: ////////////////////////////////////////////////////////////////////////////////
213:
214: /**
215: * Performs a classic string find and replace of FIRST occurrence only
216: *
217: * @param str original string to be modified
218: * @param findValue text to be replaced throughout string (must not be null)
219: * @param replaceValue text to replace found tokens (must not be null)
220: * @return modified string
221: */
222: public static String replaceFirst(String str, String findValue,
223: String replaceValue) {
224: StringTokenizer2 tok = new StringTokenizer2(str, findValue,
225: false);
226: String result = ""; // NOI18N
227: for (int i = 0; i < tok.countTokens(); i++) {
228: if (i == 0)
229: result += tok.nextToken() + replaceValue;
230: else
231: result += tok.nextToken();
232: }
233: return result;
234: }
235:
236: /**
237: * Performs a classic string find and replace
238: *
239: * @param str original string to be modified
240: * @param findValue text to be replaced throughout string (must not be null)
241: * @param replaceValue text to replace found tokens (must not be null)
242: * @return modified string
243: */
244: public static String replace(String str, String findValue,
245: String replaceValue) {
246: StringTokenizer2 tok = new StringTokenizer2(str, findValue,
247: false);
248:
249: String result = ""; // NOI18N
250: for (int i = 0; i < tok.countTokens() - 1; i++)
251: result += tok.nextToken() + replaceValue;
252: result += tok.nextToken();
253:
254: return result;
255: }
256:
257: /**
258: * Performs a classic string find & replace, optionally ignoring the case
259: * of the string
260: *
261: * @param str original string to be modified
262: * @param findValue search text to be replaced throughout string (must not be null)
263: * @param replaceValue text to replace found tokens (must not be null)
264: * @param ignoreCase search text case insensitive when <code>true</code>
265: * @return modified string
266: */
267: public static String replace(String str, String findValue,
268: String replaceValue, boolean ignoreCase) {
269: StringTokenizer2 tok = new StringTokenizer2(str, findValue,
270: false, ignoreCase);
271:
272: StringBuffer result = new StringBuffer();
273: for (int i = 0; i < tok.countTokens() - 1; i++)
274: result.append(tok.nextToken()).append(replaceValue);
275: result.append(tok.nextToken());
276:
277: return result.toString();
278: }
279:
280: /**
281: * Shortcut to {@link #tokenize(String,String,boolean,boolean) generalized
282: * search method} with property <code>trim</code> set to <code>false
283: * </code> and property <code>ignoreCase</code> set to <code>false
284: * </code>
285: */
286: public static String[] tokenize(String str, String findValue) {
287: return tokenize(str, findValue, false);
288: }
289:
290: /**
291: * Shortcut to {@link #tokenize(String,String,boolean,boolean) generalized
292: * search method} with property <code>ignoreCase</code> set to <code>false
293: * </code>
294: *
295: */
296: public static String[] tokenize(String str, String findValue,
297: boolean trim) {
298: return tokenize(str, findValue, trim, false);
299: }
300:
301: /**
302: * Utility method to create array of string tokens with optional support for
303: * trimming results and ignoring case when searching.
304: *
305: * @param str text to be searched (must not be null)
306: * @param findValue search string (must not be null)
307: * @param trim flag indicating that resulting tokens should be trimmed
308: * @param ignoreCase flag indicating that search should be case insensitive
309: * @return array of string tokens resulting from search
310: *
311: */
312: public static String[] tokenize(String str, String findValue,
313: boolean trim, boolean ignoreCase) {
314: StringTokenizer2 tok = new StringTokenizer2(str, findValue,
315: false, ignoreCase);
316:
317: List result = new LinkedList();
318: for (int i = 0; i < tok.countTokens(); i++) {
319: if (trim)
320: result.add(((String) tok.nextToken()).trim());
321: else
322: result.add(((String) tok.nextToken()));
323: }
324:
325: return (String[]) result.toArray(new String[result.size()]);
326: }
327:
328: /**
329: * Utility method to breakup larger string into array of strings,
330: * one string per line.
331: *
332: */
333: public static String[] tokenizeLines(String string) {
334: StringTokenizer tok = new StringTokenizer(string, "\n\r", true); // NOI18N
335:
336: List result = new LinkedList();
337: String previousToken = null;
338: while (tok.hasMoreTokens()) {
339: String token = tok.nextToken();
340: if (token.equals("\r")) // NOI18N
341: ; //Discard
342: else if (token.equals("\n")) // NOI18N
343: {
344: if (previousToken != null)
345: result.add(previousToken);
346: else
347: result.add(""); // NOI18N // Add a blank line
348:
349: previousToken = null;
350: } else
351: previousToken = token;
352: }
353:
354: // Make sure we get the last line, even if it didn't end
355: // with a carriage return
356: if (previousToken != null)
357: result.add(previousToken);
358:
359: return (String[]) result.toArray(new String[result.size()]);
360: }
361:
362: /**
363: * Converts an array of Objects into a delimited string of values
364: *
365: */
366: public static String delimitedString(Object[] vals, String delimiter) {
367: // Make sure we have a valid array
368: if (vals == null) {
369: return null;
370: }
371:
372: // Get one less than the size, so we can add on the last seperately.
373: int lastIndex = vals.length - 1;
374: if (lastIndex < 0) {
375: // Handle empty array as special case
376: return ""; // NOI18N
377: }
378:
379: // Iterate over the elements
380: StringBuffer buf = new StringBuffer();
381: for (int count = 0; count < lastIndex; count++) {
382: // Add element + delimiter
383: buf.append(vals[count]);
384: buf.append(delimiter);
385: }
386:
387: // Add on last element
388: buf.append(vals[lastIndex]);
389: return buf.toString();
390:
391: }
392:
393: /**
394: * Makes a String array from a delimited String of values
395: *
396: */
397: public static String[] toArray(String delimitedStr, String delimiter) {
398: if (delimitedStr == null || delimitedStr.length() == 0)
399: return new String[0];
400:
401: return StringTokenizer2.tokenize(delimitedStr, delimiter);
402: }
403:
404: /**
405: *
406: *
407: */
408: public static boolean delimitedStringContains(String delimitedStr,
409: String delimiter, String findStr) {
410: return Arrays.asList(toArray(delimitedStr, delimiter))
411: .contains(findStr);
412: }
413:
414: ////////////////////////////////////////////////////////////////////////////
415: // Name utility methods
416: ////////////////////////////////////////////////////////////////////////////
417:
418: /**
419: *
420: * @deprected Use NameUtil instead
421: */
422: public static String upcaseFirstLetter(String value) {
423: return NameUtil.capitalize(value);
424: }
425:
426: /**
427: *
428: * @deprected Use NameUtil instead
429: */
430: public static String lowcaseFirstLetter(String value) {
431: return NameUtil.decapitalize(value);
432: }
433:
434: /**
435: *
436: * @deprected Use NameUtil instead
437: */
438: public static String toDisplayName(String value) {
439: return NameUtil.toDisplayName(value);
440: }
441:
442: /**
443: *
444: * @deprected Use NameUtil instead
445: */
446: public static String toJavaConstant(String value) {
447: return NameUtil.toJavaConstant(value);
448: }
449:
450: ////////////////////////////////////////////////////////////////////////////////
451: // Instance variables
452: ////////////////////////////////////////////////////////////////////////////////
453:
454: private String text;
455: private String delimiter;
456: private boolean returnDelimiterTokens = false;
457: private List parsedTokens = new ArrayList();
458: private int tokenIndex = 0;
459: }
|