0

Thanks for checking out my question.

Starting off, the program has the following goal; the user inputs currency formatted as "xD xC xP xH"; the program checks the input is correct and then prints back the 'long' version: "x Dollars, x Cents, x Penny's, x half penny's"

Here I have some code that takes input from user as String currencyIn, splits the string into array tokens, then replaces the D's with Dollars etc and prints the output.

public class parseArray
{

    public parseArray()
    {
        System.out.print('\u000c');
        String CurrencyFormat = "xD xS xP xH";
        System.out.println("Please enter currency in the following format: \""+CurrencyFormat+"\" where x is any integer");
        System.out.println("\nPlease take care to use the correct spacing enter the exact integer plus type of coin\n\n");

        Scanner input = new Scanner(System.in);
        String currencyIn = input.nextLine();
        currencyIn.toUpperCase();
        System.out.println("This is the currency you entered: "+currencyIn);

        String[] tokens = currencyIn.split(" ");

        for (String t : tokens)
        {   
         System.out.println(t);
        }
        String dollars = tokens[0].replaceAll("D", " Dollars ");
        String cents = tokens[1].replaceAll("C", " cents");
        String penny = tokens[2].replaceAll("P", " Penny's");
        String hPenny = tokens[3].replaceAll("H", " Half penny's");

        System.out.println(" "+dollars+ " " +cents+ " " +penny+ " " +hPenny);
        input.close();
    }
}

Question 1: At the moment the program prints out pretty anything you put in. how do I establish some input control? I've seen this done in textbooks with switch statement and a series of if statements, but were too complicated for me. Would it parse characters using charAt() for each element of the array?

Question 2: Is there a 'better' way to print the output? My friend said converting my 4 strings (dollars, cents, penny's, hpenny's) into elements 0, 1, 2, 3 of a new array (called newArray) and print like this:

System.out.println(Arrays.toString(newArray));

Many thanks in advance.

1
  • currencyIn.toUpperCase(); -> not work, you need to assign it back Commented Apr 22, 2018 at 14:05

3 Answers 3

1

There is a neat solution, involving Regular Expressions, Streams and some lambdas. Core concept is that we define the input format through a regular expression. We need some sequence of digits, followed by a 'D' or a 'd', followed by a " ", followed by a sequence of digits, followed by a C or c,... I will skip derivation of this pattern, it is explained in the regular expression tutorial I linked above. We will find that

final String regex = "([0-9]+)[D|d]\\ ([0-9]+)[C|c]\\ ([0-9]+)[P|p]\\ ([0-9]+)[H|h]";

satisfies our needs. With this regular expression we can now determine whether our input String has the right format (input.matches(regex)), as well as extract the bits of information we are actually interested in (input.replaceAll(regex, "$1 $2 $3 $4"). Sadly, replaceAll yields another String, but it will contain the four digit sequences we are interested in, divided by a " ". We will use some stream-magic to transform this String into a long[] (where the first cell holds the D-value, the second holds the C-value,...). The final program looks like this:

import java.util.Arrays;

public class Test {
    public static void main(String... args) {
        final String input = args[0];
        final String regex =
                "([0-9]+)[D|d]\\ ([0-9]+)[C|c]\\ ([0-9]+)[P|p]\\ ([0-9]+)[H|h]";

        if (input.matches(regex) == false) {
            throw new IllegalArgumentException("Input is malformed.");
        }

        long[] values = Arrays.stream(input.replaceAll(regex, "$1 $2 $3 $4").split(" "))
                .mapToLong(Long::parseLong)
                .toArray();

        System.out.println(Arrays.toString(values));
    }
}

If you want to have a List<Long> instead a long[] (or a List<Integer> instead of an int[]), you would use

        List<Long> values = Arrays.stream(input.replaceAll(regex, "$1 $2 $3 $4").split(" "))
                .map(Long::parseLong)
                .collect(Collectors.toList());

It is necessary to change mapToLong to map to receive a Stream<Long> instead of a LongStream. I am sure that one could somehow write a custom Collector for LongStream to transform it into a List<Long>, but I found this solution more readable and reliable (after all, the Collector used comes from Oracle, I trust they test their code extensively).

Here is some example call:

$> java Test "10D 9c 8p 7H"
[10, 9, 8, 7]

$> java Test "10E 9C 8P 7H"
Exception in thread "main" java.lang.IllegalArgumentException: Input is malformed.
        at Test.main(Test.java:10)

$> java Test "10D 9C 8P 7H 10D 9C 8P 7H"
Exception in thread "main" java.lang.IllegalArgumentException: Input is malformed.
        at Test.main(Test.java:10)
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much for your response. It took me a few days to digest the new methods. I started a github page to display my code. I was still having some troubles, if you want to check out github.com/TiltedIntuition/CurrencyCalculator it has my code. Any feedback is greatly appreciated. The section is under the workInProgress branch.
0

Question1

You can actually check if the input is what it's supposed to be with simple checks. For example, you can check the first element like this:

if(tokens[0].charAt(1).equals("D")) 
    return true;
else
    return false;

Another way to check if the input is correct is by using Regular Expressions, but I assume you are a beginner and this is too much trouble for you, although it is the better way. So I leave it to you to look through it later.

Question2

You can actually listen to your friend and do as they said. You can write it as follows:

for(int i = 0; i < 4; i++) 
   System.out.print(" " + tokens[i])

System.out.println();

Or you may use

System.out.println(Arrays.toString(newArray));

And you have saved newArray like this:

newArray[0] = " " + tokens[0];

3 Comments

Thanks for your response. For q1, what if the x is a 3 digit integer? It not pick up because its not char 1 in tokens[0];?
I also get the error " char cannot be dereferenced"
@kp-a You can loop through each tokens and examine for the first occurrence of a non-digit character.
0

you could use the .equals() method to see if what a user has typed in matches what you have

if (currencyIn.equals("CurrencyFormat"))
{
 ...
}

this is probably the simplest way i can think of!

1 Comment

I fail to see how this is related to OP's question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.