The easiest way to achieve this is to use a positive lookaheads and lookbehinds to find valid operators and spaces between numbers.
After you have those tokens, just filter out any left-over spaces.
/[ ]/ //
/(?<=[-+*/\(\) ])/ // Positive Lookbehind
/(?=[-+*/\(\) ])/ // Positive Lookahead
import java.util.Arrays;
public class Tokenizer {
public static String[] tokenize(String expression) {
String[] tokens = expression.split("(?<=[-+*/\\(\\) ])|(?=[-+*/\\(\\) ])");
String[] result = new String[tokens.length];
int i = 0;
for (String token : tokens) {
if (!token.equals(" ")) {
result[i++] = token;
}
}
return Arrays.copyOf(result, i);
}
public static void main(String[] args) {
String[] tokens = tokenize("(- ( / 8 14) 0.5)");
for (int i = 0; i < tokens.length; i++) {
System.out.printf("%2d. %s%n", i, tokens[i]);
}
}
}
Result
0. (
1. -
2. (
3. /
4. 8
5. 14
6. )
7. 0.5
8. )
The best approach is to use a StringTokenizer
to parse through your string. You can find an example of this here:
Stack Overflow: How to Split a mathematical expression on operators as delimiters, while keeping them in the result?
Update
I wrote a simple parser to intelligently figure out what is white-space, a digit, or an operand. If you want to go the extra step, take a look at ANTLR or another grammar/language parser.
Using Scanner
This method is pretty much the same as the code above, except there is no post-processing with eliminating spaces. They are just gobbled up by the scanner.
import java.util.*;
public class MathExpressionParser {
public static void main(String[] args) {
String[] tokens = parseExpression("(- ( / 8 14) 0.5)");
for (int i = 0; i < tokens.length; i++) {
System.out.printf("%2d. %s%n", i, tokens[i]);
}
}
public static String[] parseExpression(String expression) {
List<String> result = new ArrayList<String>();
Scanner scanner = new Scanner(expression);
scanner.useDelimiter("[ ]+(?<=[-+*/\\(\\) ])|(?=[-+*/\\(\\) ])");
while (scanner.hasNext()) {
result.add(scanner.next());
}
scanner.close();
return result.toArray(new String[result.size()]);
}
}
Using Custom Parser
This is the best way to go. Regular expressions can get pretty big and hard to manage, also they kill performance. If you exactly what your criteria is, go ahead and parse it yourself. It will speed up performance and you can easily add new conditions when you see fit.
import java.util.*;
public class MathExpressionParser {
public static void main(String[] args) {
String[] tokens = parseExpression("(- ( / 8 14) 0.5)");
for (int i = 0; i < tokens.length; i++) {
System.out.printf("%2d. %s%n", i, tokens[i]);
}
}
public static String[] parseExpression(String expression) {
List<String> result = new ArrayList<String>();
StringBuffer buffer = new StringBuffer();
for (char ch : expression.toCharArray()) {
if (Character.isWhitespace(ch)) {
bufferToItem(buffer, result);
} else {
if (Character.isDigit(ch) || ch == '.') {
buffer.append(ch);
} else {
bufferToItem(buffer, result);
result.add(Character.toString(ch));
}
}
}
return result.toArray(new String[result.size()]);
}
public static void bufferToItem(StringBuffer buffer, List<String> list) {
addItemIf(list, buffer);
clearBuffer(buffer);
}
public static void addItemIf(List<String> list, StringBuffer buffer) {
if (buffer.length() > 0) list.add(buffer.toString());
}
public static void clearBuffer(StringBuffer buffer) {
buffer.delete(0, buffer.length());
}
}