Токенайзер для математического выражения - PullRequest
0 голосов
/ 02 июля 2018

Использование StreamTokenizer Я пишу лексер, который будет токенизировать математическое выражение.

В качестве ввода я даю выражение (1+π)²(1−π)²+(5.3−-2)/6. Я ожидаю, что он будет помечен как
( 1 + π ) ² ( 1 - π ) ² + ( 5.3 − - 2 ) / 6
но я получаю ( 1 +π ) ² ( 1 -π ) ² + ( 5.3 −-2 ) / 6.

Я знаю, что мне нужно вставить операторы умножения в определенные места вывода, сделаю это позже.

/* s: The inputted expression */
public static String tokenize(String s)[] throws IOException
{
    StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(s));
    tokenizer.parseNumbers();
    tokenizer.wordChars('a', 'z');
    tokenizer.wordChars('A', 'Z');
    tokenizer.wordChars('A', 'Z');
    tokenizer.wordChars(SQUARED, SQUARED); // the superscript 2
    tokenizer.wordChars(PI, PI);
    tokenizer.wordChars(SUB.charAt(0), SUB.charAt(0)); // subtract (takeaway)
    tokenizer.wordChars(NEG.charAt(0), NEG.charAt(0)); // negate
    tokenizer.wordChars('/', '/');
    tokenizer.wordChars('*', '*');
    tokenizer.wordChars('+', '+');
    tokenizer.ordinaryChar(',');
    tokenizer.ordinaryChar('/');    // do not consider / as comment start

    ArrayList<String> tokBuf = new ArrayList<>();
    while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
        switch (tokenizer.ttype) {
            case StreamTokenizer.TT_NUMBER:
                tokBuf.add(String.valueOf(tokenizer.nval));
                break;
            case StreamTokenizer.TT_WORD:
                tokBuf.add(tokenizer.sval);
                break;
            default:
                tokBuf.add(String.valueOf((char) tokenizer.ttype));
        }
    }
    String ret[] = new String[tokBuf.size()];
    ret = tokBuf.toArray(ret);

    return ret;
}

1 Ответ

0 голосов
/ 03 июля 2018
enum TokType {
    FIRST,
    OPERAND,
    OPERATOR,
    LPAREN,
    RPAREN,
}

boolean shouldMultBeEmitted(TokType tt)
{
    return tt == TokType.OPERAND || tt == TokType.RPAREN;
}

public ArrayList<String> tokenize(String in)
{
    TokType prevTok = TokType.FIRST; /* keep track of the type of the prev. tok, so
                                        we know when to insert a mult. sign */

    String regex = "(?<=[-−+*/()])|(?=[-−+*/()])";
    String toks[] = in.split(regex);

    /* the string has been tokenized; insert any needed multiplication signs */
    ArrayList<String> ret = new ArrayList<>();

    for (String x : toks) {
        if (isNumeric(x) || x.equals("Ans") || x.equals("π")) {
            if (shouldMultBeEmitted(prevTok))
                ret.add("*");

            prevTok = TokType.OPERAND;
        }
        else if (x.equals(LPAREN)) {
            if (shouldMultBeEmitted(prevTok))
                ret.add("*");

            prevTok = TokType.LPAREN;
        }
        else if (x.equals(RPAREN))
            prevTok = TokType.RPAREN;
        else if (isOperator(x))
            prevTok = TokType.OPERATOR;

        ret.add(x);
    }
    return ret;
}

Предоставлено https://stackoverflow.com/a/15983144/2469027 за предоставление RegEx.

Упражнение для читателя: вставьте знак умножения после оператора в квадрате (²), чтобы приведенный вами в вопросе пример был верным.

...