[Uml-user] Java2XMI converter hacked
张钰彦
zhangyy at cmail.cn
Sun Sep 4 00:27:07 UTC 2005
* Hacked by Hyacinth, Sep 2th, 2005
*
* 1. Package distinguish is hacked.
* The old program treats very sub-dir as a Java package except "CVS" dir.
* The new program considers only when a sub-dir contains Java source files as Java package.
* It causes Java string used. So the new program needs more memory for XMI code buffer.
*
* 2. The source codes are re-formatted by "astyle -b".
*
* 3. Folding marks are used, the source codes look fine in editors that support "Folding", such as
* VIM/Emacs/jEdit/etc.
*
* mrkissinger _at_ gmail.com/msn.com/cmail.cn
-------------- next part --------------
import java.io.*;
/**
* Java2XMI converter
*
*
* Written by R.Rawson-Tetley, 9th Feb, 2005
*
* Input: Source Directory containing Java files (as classpath root)
* Output: XMI description of passed in source files, complete with
* packages, classes, methods, etc
*
* Consider this class public domain - do what you want with it.
*
* robin at rawsontetley.org
*
*
* Hacked by Hyacinth, Sep 2th, 2005
*
* 1. Package distinguish is hacked.
* The old program treats very sub-dir as a Java package except "CVS" dir.
* The new program considers only when a sub-dir contains Java source files as Java package.
* It causes Java string used. So the new program needs more memory for XMI code buffer.
*
* 2. The source codes are re-formatted by "astyle -b".
*
* 3. Folding marks are used, the source codes look fine in editors that support "Folding", such as
* VIM/Emacs/jEdit/etc.
*
* mrkissinger _at_ gmail.com/msn.com/cmail.cn
*
*
*/
public class J2XMI
{
public static void main(String[] args)//{{{
{
if (args.length == 0)
{
System.out.println("java2xmi 050218 - convert java source to XMI");
System.out.println("Written by R.Rawson-Tetley");
System.out.println("");
System.out.println("This library is distributed in the hope that it will be useful,");
System.out.println("but WITHOUT ANY WARRANTY; without even the implied warranty of");
System.out.println("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU");
System.out.println("General Public Licence for more details.");
System.out.println("");
System.out.println("Usage: java2xmi [--noprivate] [--noprotected] <source folder>");
System.exit(1);
}
new J2XMI(args);
}//}}}
/** The number of spaces we are currently at to indent the
* package/class/interface/operation XMI structures at
* This value is incremented/decremented as we traverse
* the file tree and find classes
*/
private int depth = 1;
/** Whether we are excluding private accessors */
private boolean noprivate = false;
/** Whether we are excluding protected accessors */
private boolean noprotected = false;
/** The last accessor type return by <code>findNextAccessor</code> */
public String lastAc = "public";
private int nextID = 1000;
public J2XMI(String[] args)//{{{
/**
* Construct a new J2XMI with the specified folder and go.
*/
{
try
{
String src = args[args.length-1];
for (int i = 0; i < args.length; i++)
{
if (args[i].equals("--noprivate"))
noprivate = true;
if (args[i].equals("--noprotected"))
noprotected = true;
}
File f = new File(src);
outputHeader();
System.out.println(traverse(f));
outputFooter();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
}//}}}
public String traverse(File f)//{{{
/**
* Enumerates each file for the given directory
* and processes it as XMI output: This routine will
* call itself recursively for any directories
* it finds whilst processing.
*
* @param f The <code>File</code> to look in
* @param firstTime Whether or not it's the first time (and hence
* whether we need to output UML package structure)
*/
{
/*
* Whether the current dir is a Java package.
*/
boolean isPackageDir=false;
boolean isFirstJavaFile=true;
String xmiCode="";
// Move up one depth for indenting XML
depth++;
try
{
// Output a package element for the directory. We
// don't want to include the folder to start in though, so if it's
// the first time, don't bother outputting package details.
/*
if (!firstTime)
System.out.println(getSpaces(depth) + "<UML:Package visibility=\"public\" xmi.id=\"" +
getXmiID() + "\" name=\"" + f.getName() + "\">");
*/
File[] d = f.listFiles();
for (int i = 0; i < d.length; i++)
{
// If we have a directory, process it
if (d[i].isDirectory())
{
// Unless it's a CVS directory
if (!d[i].getName().equals("CVS"))
{
//System.out.println(d[i].getName());
String code=traverse(d[i]);
if ( (null!=code) )//&& (!f.getName().equals(".")) )
{
//System.out.println(d[i].getName());
/*
System.out.println(
getSpaces(depth) +
"<UML:Package visibility=\"public\" xmi.id=\"" +
getXmiID() + "\" name=\"" + d[i].getName() + "\">\n"+
code+"\n"+
"</UML:Package>"
);
*/
xmiCode=xmiCode+getSpaces(depth) +
"<UML:Package visibility=\"public\" xmi.id=\"" +
getXmiID() + "\" name=\"" + d[i].getName() + "\">\n"+
code+"\n"+
"</UML:Package>\n";
}
}
}
// If it's a java file, process it
if (d[i].getName().toLowerCase().endsWith(".java"))
{
/*
if (null==xmiCode)
{
xmiCode=new String();
}
*/
if (isFirstJavaFile)
{
/*
System.out.println(getSpaces(depth) + "<UML:Package visibility=\"public\" xmi.id=\"" +
getXmiID() + "\" name=\"" + f.getName() + "\">");
*/
/*
xmiCode=xmiCode+getSpaces(depth) + "<UML:Package visibility=\"public\" xmi.id=\"" +
getXmiID() + "\" name=\"" + f.getName() + "\">";
*/
isPackageDir=true;
}
xmiCode=xmiCode+processJava(d[i]);
}
}
}
catch (Exception e)
{}
// Close the package element
/*
if (!firstTime)
System.out.println(getSpaces(depth) + "</UML:Package>");
*/
//if (isPackageDir)
{
//System.out.println(getSpaces(depth) + "</UML:Package>");
//xmiCode=xmiCode+getSpaces(depth) + "</UML:Package>";
}
// Move down a level for indenting XML
depth--;
return(xmiCode);
}//}}}
public String getSpaces(int num)//{{{
/**
* Returns a string of the requested number of spaces.
*
* @param num The number of spaces to return
*/
{
StringBuffer b = new StringBuffer(num);
for (int i = 0; i < num; i++)
b.append(" ");
return b.toString();
}//}}}
public String processJava(File f)//{{{
/**
* Process a Java file, outputting details of the class/interface
* and all methods
*
* This is really crude and probably should have been split out
* into some delegated code that built a tree of objects and
* then looped through them to generate the XML, but time is
* a factor and I don't have much to waste working on this
*
* @param f The java <code>File</code> to process.
*/
{
boolean wroteHeader = false;
boolean isInterface = true;
String xmiCode="";
try
{
String s = readFileToString(f);
// Remove comments since they can confuse us if they
// have code snippets and things in there
s = stripComments(f.getName(), s);
// Look for the first curly brace and then work back
// to find an interface or class declaration
int fcb = s.indexOf("{");
int ipos = s.lastIndexOf(" interface", fcb);
if (ipos == -1)
{
ipos = s.lastIndexOf(" class", fcb);
isInterface = false;
}
// We couldn't find an initial declaration. Abort.
if (ipos == -1)
{
System.err.println(f.getName() + ": Couldn't find initial \"public interface\" or \"public class\" declaration");
return(xmiCode);
}
// Determine the name by looking for a space after
// the class/interface type
int namepos = s.indexOf(" ", ipos + 2) + 1;
// Get the end of the name by looking for the first linebreak/space
// after the name
int nameend = getNextWhitespaceChar(s, namepos + 1);
String name = asXMLAttribute(s.substring(namepos, nameend));
// Drop a depth level and output the class/interface XMI
depth++;
if (isInterface)
{
/*
System.out.println(getSpaces(depth) + "<UML:Interface stereotype=\"42\" " +
"visibility=\"public\" xmi.id=\"" + getXmiID() + "\" isAbstract=\"true\" " +
"name=\"" + asXMLAttribute(name) + "\">");
*/
xmiCode=xmiCode+getSpaces(depth) + "<UML:Interface stereotype=\"42\" " +
"visibility=\"public\" xmi.id=\"" + getXmiID() + "\" isAbstract=\"true\" " +
"name=\"" + asXMLAttribute(name) + "\">\n";
}
else
{
/*
System.out.println(getSpaces(depth) + "<UML:Class visibility=\"public\" xmi.id=\"" +
getXmiID() + "\" name=\"" + asXMLAttribute(name) + "\">");
*/
xmiCode=xmiCode+getSpaces(depth) + "<UML:Class visibility=\"public\" xmi.id=\"" +
getXmiID() + "\" name=\"" + asXMLAttribute(name) + "\">\n";
}
// Mark the header as written to make sure we write a closer should
// the worst happen.
wroteHeader = true;
// Start looking for methods/fields from the first curly brace
int pos = fcb;
// Look for an accessor string that could be the start of a field/method
// (public/private/protected)
pos = findNextAccessor(s, pos + 1);
// Whether we need to abandon during the loop - we need to do this if
// we find something horrible or unexpected so we don't write crap XMI
boolean abort = false;
// Whether we're dealing with a static method/field
boolean isStatic = false;
boolean isTransient = false;
boolean isSynchronized = false;
boolean isAbstract = false;
boolean isFinal = false;
boolean isConstructor = false;
// Whether this is a field or a method
boolean isMethod = false;
// The method/field name and type
String mname = "";
String mtype = "";
// Where split strings go when breaking up the method/field signature
String[] methodbits = null;
while (pos != -1)
{
abort = false;
isStatic = false;
isTransient = false;
isSynchronized = false;
isAbstract = false;
isFinal = false;
isConstructor = false;
mname = "";
mtype = "";
isMethod = false;
// Get the next terminator (semi-colon or close bracket);
// if the next one is a semi-colon, then we're dealing
// with a field rather than a method.
int sigterminator = -1;
for (int i = pos; i < s.length()-1; i++)
{
if (s.substring(i, i+1).equals(";"))
{
sigterminator = i;
isMethod = false;
break;
}
else if (s.substring(i, i+1).equals(")"))
{
sigterminator = i;
isMethod = true;
break;
}
}
if (isMethod)
{
// METHOD PARSER
// ================================================================
// Read the method signature
String msig = "";
try
{
msig = s.substring(pos, sigterminator).trim();
}
catch (StringIndexOutOfBoundsException e)
{
// This shouldn't ever happen
abort = true;
System.err.println("WARN: Couldn't find the end of the method sig - aborting: "
+ pos + "-" + sigterminator);
}
// Verify that the method start we found wasn't
// inside a string literal and some smart alec is
// running java2xmi over it's own source
if (s.substring(pos - 1, pos).equals("\""))
{
abort = true;
System.err.println("WARN: Almost confused by a string literal - aborting:\n " + msig);
}
if (!abort)
{
// Split the method sig on spaces
methodbits = split(flattenWhiteSpace(msig), " ");
// Loop through those bits and pick out
// words we recognise. The first one that
// we don't is the method type, followed
// by the method name.
for (int z = 1; z < methodbits.length; z++)
{
if (methodbits[z].equals("static"))
isStatic = true;
else if (methodbits[z].equals("abstract"))
isAbstract = true;
else if (methodbits[z].equals("transient"))
isTransient = true;
else if (methodbits[z].equals("synchronized"))
isSynchronized = true;
else if (methodbits[z].equals("final"))
isFinal = true;
else
{
try
{
// The next one must be the type
mtype = methodbits[z];
// And the name...
mname = methodbits[z + 1];
// Does the type contain a bracket?
// if so, it's a constructor with
// arguments.
if (mtype.indexOf("(") != -1)
{
mtype = name;
mname = name;
isConstructor = true;
}
break;
}
catch (ArrayIndexOutOfBoundsException e)
{
// We've run out of bits - this is
// a constructor.
isConstructor = true;
mtype = name;
mname = name;
break;
}
}
}
}
if (!abort)
{
// Chop everything after that first bracket out of the method name
// if there is no bracket, then that's because they put a space after
// the method name and before the first bracket (which is ok)
try
{
mname = mname.substring(0, mname.indexOf("("));
}
catch (StringIndexOutOfBoundsException e)
{}
}
if (!abort)
{
// Enter another depth and output the operation
depth++;
/*
System.out.println(getSpaces(depth) + "<UML:Operation visibility=\"" + lastAc + "\" " +
"xmi.id=\"" + getXmiID() + "\" type=\"" + unqualifyType(asXMLAttribute(mtype)) + "\" " +
"name=\"" + asXMLAttribute(mname) + "\"" +
(isStatic ? " ownerScope=\"classifier\"" : "") +
(isAbstract ? " isAbstract=\"true\"" : "") +
">");
*/
xmiCode=xmiCode+getSpaces(depth) + "<UML:Operation visibility=\"" + lastAc + "\" " +
"xmi.id=\"" + getXmiID() + "\" type=\"" + unqualifyType(asXMLAttribute(mtype)) + "\" " +
"name=\"" + asXMLAttribute(mname) + "\"" +
(isStatic ? " ownerScope=\"classifier\"" : "") +
(isAbstract ? " isAbstract=\"true\"" : "") +
">\n";
// Read the parameters
String params = msig.substring(msig.indexOf("(") + 1, msig.length());
String[] pbits = split(params, ",");
depth++;
for (int z = 0; z < pbits.length; z++)
{
try
{
String pb = pbits[z].trim();
String[] sp = split(pb, " ");
/*
System.out.println(getSpaces(depth) + "<UML:Parameter " +
"visibility=\"" + lastAc + "\" xmi.id=\"" + getXmiID() + "\" " +
"value=\"\" type=\"" + unqualifyType(asXMLAttribute(sp[0])) +
"\" name=\"" + asXMLAttribute(sp[1]) + "\"/>");
*/
xmiCode=xmiCode+getSpaces(depth) + "<UML:Parameter " +
"visibility=\"" + lastAc + "\" xmi.id=\"" + getXmiID() + "\" " +
"value=\"\" type=\"" + unqualifyType(asXMLAttribute(sp[0])) +
"\" name=\"" + asXMLAttribute(sp[1]) + "\"/>\n";
}
catch (ArrayIndexOutOfBoundsException e)
{
// No params
}
catch (StringIndexOutOfBoundsException e)
{
// No params
}
}
depth--;
// Back up
//System.out.println(getSpaces(depth) + "</UML:Operation>");
xmiCode=xmiCode+getSpaces(depth) + "</UML:Operation>\n";
depth--;
}
}
else
{
// FIELD PARSER:
// ==============================================================
// Read the field signature
String fsig = "";
try
{
fsig = s.substring(pos, sigterminator).trim();
}
catch (StringIndexOutOfBoundsException e)
{
// This shouldn't ever happen
abort = true;
System.err.println("WARN: Couldn't find the end of the method sig - aborting: "
+ pos + "-" + sigterminator);
}
// Verify that the field start we found wasn't
// inside a string literal and some smart alec is
// running java2xmi over it's own source
if (s.substring(pos - 1, pos).equals("\""))
{
abort = true;
System.err.println("WARN: Almost confused by a string literal - aborting:\n " + fsig);
}
if (!abort)
{
// Split the field sig on spaces
methodbits = split(flattenWhiteSpace(fsig), " ");
// Loop through those bits and pick out
// words we recognise. The first one that
// we don't is the field type, followed
// by the field name.
for (int z = 1; z < methodbits.length; z++)
{
if (methodbits[z].equals("static"))
isStatic = true;
else if (methodbits[z].equals("abstract"))
isAbstract = true;
else if (methodbits[z].equals("transient"))
isTransient = true;
else if (methodbits[z].equals("synchronized"))
isSynchronized = true;
else if (methodbits[z].equals("final"))
isFinal = true;
else if (methodbits[z].trim().equals(""))
isFinal = isFinal; // Ignore empty space
else
{
try
{
// The next one must be the type
mtype = methodbits[z];
// And the name...
mname = methodbits[z + 1];
break;
}
catch (ArrayIndexOutOfBoundsException e)
{
abort = true;
System.err.println("WARN: Couldn't get enough parts for field type and name - aborting:\n " + fsig);
}
}
}
}
if (!abort)
{
// Chop everything after that first equals out of the field name
// if there is no equals, then that's because they put a space after
// the field name and before the equals (which is ok).
// Throw away upto the semicolon if we have one as well.
try
{
if (mname.indexOf("=") != -1)
mname = mname.substring(0, mname.indexOf("="));
else if (mname.indexOf(";") != -1)
mname = mname.substring(0, mname.indexOf(";"));
}
catch (StringIndexOutOfBoundsException e)
{}
// TODO: Maybe add support for extracting the initial value
// by looking at what's after the equals sign and before the
// semi-colon?
}
if (!abort)
{
// Enter another depth and output the attribute
depth++;
/*
System.out.println(getSpaces(depth) + "<UML:Attribute visibility=\"" + lastAc + "\" " +
"xmi.id=\"" + getXmiID() + "\" type=\"" + unqualifyType(asXMLAttribute(mtype)) + "\" " +
"name=\"" + asXMLAttribute(mname) + "\"" +
(isStatic ? " ownerScope=\"classifier\"" : "") +
"/>");
*/
xmiCode=xmiCode+getSpaces(depth) + "<UML:Attribute visibility=\"" + lastAc + "\" " +
"xmi.id=\"" + getXmiID() + "\" type=\"" + unqualifyType(asXMLAttribute(mtype)) + "\" " +
"name=\"" + asXMLAttribute(mname) + "\"" +
(isStatic ? " ownerScope=\"classifier\"" : "") +
"/>\n";
depth--;
}
}
// Look for a public method/field again
pos = findNextAccessor(s, pos + 1);
}
}
catch (Exception e)
{
System.err.println("Exception occurred, abandoning class parse: " + e.getMessage());
}
// Output the closer for the class/interface and move back
// up a depth level.
if (wroteHeader)
{
if (isInterface)
{
//System.out.println(getSpaces(depth) + "</UML:Interface>");
xmiCode=xmiCode+"</UML:Interface>\n";
}
else
{
//System.out.println(getSpaces(depth) + "</UML:Class>");
xmiCode=xmiCode+getSpaces(depth) + "</UML:Class>\n";
}
depth--;
}
return(xmiCode);
}//}}}
public int getNextWhitespaceChar(String findin, int start)//{{{
/**
* Finds the next line break/space character in the given string
* from the given position.
*/
{
int i = start;
while (i < findin.length())
{
if (findin.substring(i, i + 1).equals( new String(new byte[] { 13 })))
return i;
else if (findin.substring(i, i + 1).equals( new String(new byte[] { 10 })))
return i;
else if (findin.substring(i, i + 1).equals(" "))
return i;
i++;
}
return -1;
}//}}}
public String unqualifyType(String type)//{{{
/**
* Given a Java type, unqualifies (removes the package) from
* the class name.
* @param type The type to unqualify
* @return the unqualified class name
*/
{
// Do nothing if no package
int lastDot = type.lastIndexOf(".");
if (lastDot == -1)
return type;
else
return type.substring(lastDot + 1, type.length());
}//}}}
public String flattenWhiteSpace(String in)//{{{
/**
* Given a string, loops through it and converts multiple
* spaces/line breaks to one single space.
*/
{
StringBuffer o = new StringBuffer(in.length());
boolean lastCharWasSpace = false;
boolean outputOneSpace = false;
for (int i = 0; i < in.length(); i++)
{
// Space or line break qualify as whitespace
if (in.substring(i, i+1).equals(" "))
{
lastCharWasSpace = true;
}
else if (in.substring(i, i+1).equals("\n"))
{
lastCharWasSpace = true;
}
// If the char isn't one, append it and flag
// it as such
else
{
o.append(in.substring(i, i+1));
lastCharWasSpace = false;
outputOneSpace = false;
}
if (lastCharWasSpace && !outputOneSpace)
{
o.append(" ");
outputOneSpace = true;
}
}
return o.toString();
}//}}}
public int findNextAccessor(String in, int pos)//{{{
/**
* Finds the next accessor in a given string
* An accessor is one of public/private/protected
* @param in the string to find in
* @param pos the position to start at
* @return the position of the next accessor, or -1 if none was found
*/
{
int pu = in.indexOf("public ", pos);
int pr = in.indexOf("private ", pos);
int pt = in.indexOf("protected ", pos);
// If private/protected accessors are turned off, pretend we
// didn't find any
if (noprivate)
pr = 99999;
if (noprotected)
pt = 99999;
// Translate -1s to 99999 to effectively ignore
if (pu == -1)
pu = 99999;
if (pr == -1)
pr = 99999;
if (pt == -1)
pt = 99999;
int lowest = 99999;
lastAc = "none";
if (pu < lowest)
{
lowest = pu;
lastAc = "public";
}
if (pr < lowest)
{
lowest = pr;
lastAc = "private";
}
if (pt < lowest)
{
lowest = pt;
lastAc = "protected";
}
if (lowest == 99999)
return -1;
else
return lowest;
}//}}}
public String stripComments(String filename, String s)//{{{
/**
* Removes all C-Style java comments from a piece
* of code.
* @param s The code to look for comments in
* @return The code without any comments
*/
{
StringBuffer output = new StringBuffer(s.length());
int f = 0;
for (int i = 0; i < s.length()-1; i++)
{
if (s.substring(i, i+2).equals("/*"))
{
f = s.indexOf("*/", i + 1);
if (f != -1)
{
i = f;
}
else
{
System.err.println("WARN: Oops no closing */ tag found after /* in " + filename);
i = s.length() - 1;
}
}
if (s.substring(i, i+2).equals("//"))
{
f = s.indexOf("\n", i + 1);
if (f != -1)
{
i = f;
}
else
{
System.err.println("WARN: Oops - no line break found after // in " + filename);
i = s.length() - 1;
}
}
try
{
output.append(s.substring(i, i+1));
}
catch (StringIndexOutOfBoundsException e)
{
System.err.println("WARN: Error appending char whilst removing comments - " + e.getMessage());
}
}
return output.toString();
}//}}}
public String asXMLAttribute(String v)//{{{
/** A final check before a value goes into an XML attribute
* all XML-upsetting chars are removed.
*/
{
v = v.replace('"', ' ');
v = v.replace('&', ' ');
return v.trim();
}//}}}
public int getXmiID()//{{{
/** Returns the next unique ID for use with xmi.id tags */
{
nextID++;
return nextID;
}//}}}
public void outputHeader()//{{{
/**
* Outputs the document header
*/
{
String s = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<XMI xmlns:UML=\"org.omg/standards/UML\" verified=\"false\" timestamp=\"\" xmi.version=\"1.2\">\n" +
" <XMI.header>\n" +
" <XMI.documentation>\n" +
" <XMI.exporter>Java2XMI http://www.rawsontetley.org</XMI.exporter>\n" +
" <XMI.exporterVersion>1.0</XMI.exporterVersion>\n" +
" <XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding>\n" +
" </XMI.documentation>\n" +
" <XMI.model xmi.name=\"java2xmi\" href=\"\"/>\n" +
" <XMI.metamodel xmi.name=\"UML\" xmi.version=\"1.3\" />\n" +
" </XMI.header>\n" +
" <XMI.content>\n" +
" <UML:Model>\n" +
" <UML:Stereotype visibility=\"public\" xmi.id=\"3\" name=\"datatype\" />\n" +
" <UML:Stereotype visibility=\"public\" xmi.id=\"42\" name=\"interface\" />";
System.out.println(s);
}//}}}
public void outputFooter()//{{{
/**
* Outputs the document footer
*/
{
String s = " </UML:Model>\n" +
" </XMI.content>\n" +
"</XMI>";
System.out.println(s);
}//}}}
public String readFileToString(File f)//{{{
/**
* Given a <code>File</code>, reads it into a single
* String and returns it for parsing.
*
* @param f the file to read.
*/
{
try
{
FileInputStream in = new FileInputStream(f);
byte[] buffer = new byte[in.available()];
in.read(buffer);
in.close();
return new String(buffer);
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
}//}}}
public static String[] split(String splitstring, String splitchar)//{{{
/**
* Splits a string by a particular char and returns an array of
* strings. If there are no occurrences of the split char, the
* original string is returned in an array of 1 item.
* @param splitstring The string to be split
* @param splitchar The char to split on
* @return An array of strings
*/
{
splitstring = splitstring.trim();
// If there is only one element, just return that
if (splitstring.indexOf(splitchar) == -1)
{
String[] rets = new String[1];
rets[0] = splitstring;
return rets;
}
// Find how many there are
int tot = 0;
int lpos = splitstring.indexOf(splitchar);
while (lpos != -1)
{
tot++;
lpos = splitstring.indexOf(splitchar, lpos + 1);
}
tot++;
// Create our new array
String[] rets = new String[tot];
tot = 0;
lpos = 0;
int spos = splitstring.indexOf(splitchar);
while (spos != -1)
{
// Add into the array
rets[tot] = splitstring.substring(lpos, spos);
tot++;
lpos = spos + 1;
spos = splitstring.indexOf(splitchar, lpos);
}
// Include last word
rets[tot] = splitstring.substring(lpos, splitstring.length());
// Return it
return rets;
}//}}}
}
More information about the umbrello
mailing list