简体   繁体   中英

Java: Stringtokenizer To Array

Given a polynomial, I'm attempting to write code to create a polynomial that goes by the degree's, and adds like terms together For instance... given

String term = "323x^3+2x+x-5x+5x^2" //Given
What I'd like = "323x^3+5x^2-2x" //result

So far I've tokenized the given polynomial by this...

    term = term.replace("+" , "~+");
    term = term.replace("-", "~-");
    System.out.println(term);
    StringTokenizer multiTokenizer = new StringTokenizer(term, "~");
    int numberofTokens = multiTokenizer.countTokens();
    String[] tokensArray = new String[numberofTokens];
    int x=0;
    while (multiTokenizer.hasMoreTokens())
    {

        System.out.println(multiTokenizer.nextToken());

    }

Resulting in

323x^3~+2x~+x~-5x~+5x^2
323x^3
+2x
+x
-5x
+5x^2

How would I go about splitting the coefficient from the x value, saving each coefficient in an array, and then putting the degrees in a different array with the same index as it's coefficient? I will then use this algorithm to add like terms....

for (i=0;i<=biggest_Root; i++)
     for(j=0; j<=items_in_list ; j++)
          if (degree_array[j] = i)
               total += b1[j];
     array_of_totals[i] = total;

Any and all help is much appreciated!

You can also update the terms so they all have coefficients:

s/([+-])x/\11/g

So +x^2 becomes +1x^2.

Your individual coefficients can be pulled out by simple regex expressions. Something like this should suffice:

/([+-]?\d+)x/     // match for x
/([+-]?\d+)x\^2/   // match for x^2
/([+-]?\d+)x\^3/   // match for x^3
/([+-]?\d+)x\^4/   // match for x^4

Then

sum_of_coefficient[degree] += match

where "match" is the parseInt of the the regex match (special case where coefficient is 1 and has no number eg. +x)

sum_of_coefficient[3] = 323
sum_of_coefficient[1] = +2+1-5 = -2
sum_of_coefficient[2] = 5

Using a "Regular Expression" Pattern to Simplify the Parsing

( and make the code cooler and more concise )

Here is a working example that parses coefficient, variable and degree for each term based on the terms you've parsed so far. It just inserted the terms shown into your example into a list of Strings and then processes each string the same way.

This program runs and produces output, and if you like it you can splice it into your program. To try it:

$ javac parse.java

$ java parse

Limitations and Potential Improvements:

Technically speaking the coefficient and degrees could be fractional, so the regular expression could easily be changed to handle those kinds of numbers. And then instead of Integer.parseInt() you could use Float.parseFloat() instead to convert the matched value to a variable you can use.

import java.util.*;
import java.util.regex.*;

public class parse {
    public static void main(String args[]) {

        /* 
         * Substitute this List with your own list or
         * array from the code you've written already...
         *
         * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */

        List<String>terms = new ArrayList<String>();
        terms.add("323x^3");
        terms.add("+2x");
        terms.add("+x");
        terms.add("-5x");
        terms.add("+5x^2");

        /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */

        for (String term : terms) {

            System.out.print("Term: " + term + ": \n");

            Pattern pattern = Pattern.compile("([+-]*\\d*)([A-Za-z]*)\\^*(\\d*)"); 
            Matcher matcher = pattern.matcher(term);

            if (matcher.find()) {

                int coefficient = 1;
                try {
                    coefficient = Integer.parseInt(matcher.group(1));
                } catch (Exception e) {}

                String variable = matcher.group(2);

                int degree = 1;
                try { 
                    degree = Integer.parseInt(matcher.group(3));
                } catch (Exception e) {}

                System.out.println("   coefficient = " + coefficient);
                System.out.println("   variable    = " + variable);
                System.out.println("   degree      = " + degree);

                /* 
                 * Here, do what you need to do with
                 *     variable, coefficient and degree 
                 */ 

            } 
        }
    }
}

Explanation of the Regular Expression in the Example Code:

This is the regular expression used:

([+-]*\\d*)([A-Za-z]*)\\^*(\\d*)

Each parenthesized section represents part of the term I want to match and extract into my result. It puts whatever is matched in a group corresponding to the set of parenthesis. First set of parenthesis goes into group 1, second into group 2, etc...

  1. The first matcher (grouped by ( ) ), is ([+-]*\\\\d*) That is designed match (eg extract) the coefficient (if any) and put it into group 1. It expects something that has zero or more occurances of '+' or '-' characters, followed by zero or more digits. I probably should have written in [+-]?\\\\d* which would match zero or one + or - characters.

  2. The next grouped matcher is ([A-Za-z]*) That says match zero or more capital or lowercase letters. That is trying to extract the variable name, if any and put it into group 2.

  3. Following that, there is an ungrouped \\\\^* , which matches 0 or more ^ characters. It's not grouped in parenthesis, because we want to account for the ^ character in the text, but not stash it anywhere. We're really interested in the exponent number following it. Note: Two backslashes are how you make one backslash in a Java string. The real world regular expression we're trying to represent is \\^* . The reason it's escaped here is because ^ unescaped has special meaning in regular expressions, but we just want to match/allow for the possibility of an actual caret ^ at that position in the algebraic term we're parsing.

  4. The final pattern group is (\\\\d*) . Outside of a string literal, as most regex's in the wild are, that would simply be \\d* . It's escaped because, by default, in a regex, d , unescaped, means match a literal d at the current position in the text, but, escaped, \\d is a special regex pattern that matches match any digit [0-9] (as the Pattern javadoc explains). * means expect (match) zero or more digits at that point. Alternatively, + would mean expect 1 or more digits in the text at the current position, and ? would mean 0 or 1 digits are expected in the text at the current position. So, essentially, the last group is designed to match and extract the exponent (if any) after the optional caret, putting that number into group 3.

Remember the ( ) (parenthesized) groupings are just so that we can extract those areas parsed into separate groups.

If this doesn't all make perfect sense, study regular expressions in general and read the Java Pattern class javadoc online. The are NOT as scary as they first look, and an extremely worthwhile study for any programmer ASAP, as it crosses most popular scripting languages and compilers, so learn it once and you have an extremely powerful tool for life.

This looks like a homework question, so I won't divulge the entire answer here but here's how I'd get started

public class Polynomial {

private String rawPolynomial;
private int lastTermIndex = 0;
private Map<Integer, Integer> terms = new HashMap<>();

public Polynomial(String poly) {
    this.rawPolynomial = poly;
}

public void simplify() {
    while(true){
        String term = getNextTerm(rawPolynomial);
        if ("".equalsIgnoreCase(term)) {
            return;
        }
        Integer degree = getDegree(term);
        Integer coeff = getCoefficient(term);
        System.out.println(String.format("%dx^%d", coeff, degree));
        terms.merge(degree, coeff, Integer::sum);
    }
}

private String getNextTerm(String poly) {
...
}

private Integer getDegree(String poly) {
    ...
}

private Integer getCoefficient(String poly) {
    ...
}

@Override public String toString() {
    return terms.toString();
}
}

and some tests to get you started -

public class PolynomialTest {
    @Test public void oneTermPolynomialRemainsUnchanged() {
        Polynomial poly = new Polynomial("3x^2");
        poly.simplify();
        assertTrue("3x^2".equalsIgnoreCase(poly.toString()));
    }

}

You should be able to fill in the blanks, hope this helps. I'll be happy to help you further if you're stuck somewhere.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM