Convert double values of a file into a special format - java

I am still relatively new to java but the problem that I am facing right now is that I keep getting a compile time error with what I currently have.
I'm not sure if there's a special logic structure that would take existing values from the file and convert the format of the numbers.
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
public class Music {
// Method header
public static void main(String [] args) throws IOException{
// Variable declarations
String id;
String artistName;
String title;
String releaseName;
int year;
double endOfFadeIn;
double startOfFadeOut;
double loudness;
double duration;
// Scanner to read input from the user
Scanner keyboard = new Scanner(System.in);
// Scanner to read in the file that the user types.
System.out.print("Enter the name of the file: ");
String filename = keyboard.nextLine();
File inFile = new File(filename);
Scanner fileScan = new Scanner(inFile);
fileScan.useDelimiter(",|\\r?\\n");
fileScan.nextLine();
// Read from file using Scanner
while(fileScan.hasNext()) {
id = fileScan.next();
System.out.println(id);
id = formatID(id);
System.out.println(id);
artistName = fileScan.next();
System.out.println(artistName);
artistName = truncate(artistName);
title = fileScan.next();
System.out.println(title);
title = truncate(title);
releaseName = fileScan.next();
System.out.println(releaseName);
releaseName = truncate(releaseName);
year = fileScan.nextInt();
System.out.println(year);
endOfFadeIn = fileScan.nextDouble();
System.out.println(endOfFadeIn);
startOfFadeOut = fileScan.nextDouble();
System.out.println(startOfFadeOut);
loudness = fileScan.nextDouble();
System.out.println(loudness);
System.out.printf("%-10s %-20s %-20s %-20s%n", id, artistName, title,
releaseName);
}
}// end main
public static String formatID(String id) {
String newid;
newid = id.substring(0,7) + "-" + id.substring(7,9) + "-" + id.substring(9,18);
return newid;
}//end formatID
public static String truncate(String str){
if (str.length() > 20) {
return str.substring(0, 20-3) + "...";
} else {
return str;
}
}//end truncateStr
public static String formatTime(double duration) {
int days=0;
int hours=0;
int minutes=0;
int seconds=0;
String Result;
Result = System.out.printf("%03s:%02s:%02s:%02s", days, hours, minutes, seconds);
string.format
System.out.printf("%03s:%02s:%02s:%02s", days, hours, minutes, seconds);
duration = (int) duration;
duration = (startOfFadeOut - endOfFadeIn);
duration = Math.round(duration);
}//end formatTime
}//end class
The expected result is that when the values are read in from the file the output will display the time in this format DD:HH:MM:SS.

You didn't specify what the compile-time error was or which line of your code was causing it, but since you posted a MRE, I just needed to copy your code in order to discover what it was. It is this line:
String Result;
Result = System.out.printf("%03s:%02s:%02s:%02s", days, hours, minutes, seconds);
Method printf returns a PrintStream and not a String. If you want a String, use method format
So your code should be...
String Result;
Result = String.format("%03s:%02s:%02s:%02s", days, hours, minutes, seconds);
System.out.printf(Result);
Also, according to java coding conventions, variable names - like Result - should start with a lower-case letter, i.e. result.

Related

Why am I getting "NoSuchElementException" When I can print everything from textfile?

I'm able to read everything from the text file and print the data yet I get a "No Such Element" Exception. All the solutions i've found say to use "HasNext" in while loop and yet it doesn't seem to work for me
public void fileReader() throws IOException {
String id;
String brand;
int yearOfManufacture;
int numSeats;
double rentalPerDay;
double insurancePerDay;
double serviceFee;
double discount;
String model;
String type;
String color;
ArrayList<Vehicle> vehicleArray = new ArrayList<>();
File file = new File("C:/Users/jockg/Downloads/Fleet (1).csv");
Scanner scan = new Scanner(file);
scan.useDelimiter("n/n");
while (scan.hasNext() || scan.hasNextDouble() || scan.hasNextInt()) {
id = scan.next();
System.out.println(id);
brand = scan.next();
System.out.println(brand);
model = scan.next();
System.out.println(model);
type = scan.next();
System.out.println(type);
yearOfManufacture = Integer.parseInt(scan.next());
System.out.println(yearOfManufacture);
numSeats = Integer.parseInt(scan.next());
System.out.println(numSeats);
color = scan.next();
System.out.println(color);
rentalPerDay = Double.parseDouble(scan.next());
System.out.println(rentalPerDay);
insurancePerDay = Double.parseDouble(scan.next());
System.out.println(insurancePerDay);
serviceFee = Double.parseDouble(scan.next());
System.out.println(serviceFee);
if (scan.next().equals("N/A")) {
discount = 0;
} else {
discount = Double.parseDouble(scan.next());
}
System.out.println(discount);
Car newCar = new Car(id, brand, yearOfManufacture, numSeats, rentalPerDay, insurancePerDay, serviceFee,
discount, model, type, color);
vehicleArray.add(newCar);
}
}
C001,Toyota,Yaris,Sedan,2012,4,Blue,50,15,10,10
C002,Toyota,Corolla,Hatch,2020,4,White,45,20,10,10
C003,Toyota,Kluger,SUV,2019,7,Grey,70,20,20,10
C004,Audi,A3,Sedan,2015,5,Red,65,10,20,10
C005,Holden,Cruze,Hatch,2020,4,Green,70,10,10,10
C006,BMW,X5,SUV,2018,7,White,100,25,20,10
C007,BMW,320i,Sedan,2021,5,Grey,75,10,15,N/A
C008,Ford,Focus,Sedan,2014,5,Red,45,10,10,N/A
C009,Ford,Puma,SUV,2015,5,Black,70,20,15,20
This is the Exception I get:
your CSV has actually two delimiters: comma and new line. Try: scan.useDelimiter(",|\\R");
discount is read twice for numeric values, try:
String discountStr = scan.next();
discount = discountStr.equals("N/A") ? 0 : Double.parseDouble(discountStr);
if (scan.next().equals("N/A")
might be your problem here. from what it looks like, this is not doing what you intend on doing.
When you call scan.next() it will read regardless of whether it is equal to "N/A"
you put an else statement after this and say discount = Double.parseDouble(scan.next() and I presume you are talking about the same scan.next() that you called in the initial if statement, but that line has already passed. You need to store this scan.next() in a variable and then check if it is "N/A".

parsing a file with BufferedReader

I would like to learn more about working/parsing with files and more generally with Strings.
So for that i created a custom .txt file with this input:
Function Time
print() 0:32
find() 0:40
insert() 1:34
I want to parse that file and to aggregate how much "functions" have been activated. Also, I want to aggregate the total time that it took for that (i.e., (0.32+0.4+1.34)/0.6 = 2:46 minutes)
For the above data, the output should be:
3 functions in total time of 2:46 minutes
For the solution, I obviously create BufferedReader and parse line by line, but there are lots of spaces, and I am not so great with working with that kind of input. I hope if someone can suggest me the proper way to work with that kind of data.
I will also appreciate any link to exercises of this kind since I am trying to get a job and they ask lots of questions about parsing this kind of data (strings and files).
Thanks for any help! :)
In general terms, you should process the file line by line. For each line, you can use the split function to split the line into several parts (from String to String[]). Notice that the argument of the split function is the character or the regular expression to use to split the original text. For instance, using str.split("\\s+") will split the input text treating multiple spaces as a single space. Also, you can use the trim function to erase unwanted spaces, end lines, tabs, etc. and then parse the information properly.
Concerning the specifics of parsing time values, Java has several built-in classes and methods to handle local dates, elapsed times, etc. (such as LocalTime or Calendar). However, in my example, I have built a custom FuncTime class to keep things easy.
Here is the code:
package fileParser;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class FileParser {
private static class FuncTime {
private int seconds;
private int minutes;
public FuncTime() {
this.seconds = 0;
this.minutes = 0;
}
public FuncTime(int seconds, int minutes) {
this.seconds = seconds;
this.minutes = minutes;
}
public void accumulate(FuncTime ft) {
this.seconds += ft.seconds;
while (this.seconds >= 60) {
this.seconds -= 60;
this.minutes += 1;
}
this.minutes += ft.minutes;
}
#Override
public String toString() {
return this.minutes + ":" + this.seconds;
}
}
private static void parseInfo(String fileName) {
// Create structure to store parsed data
Map<String, FuncTime> data = new HashMap<>();
// Parse data from file
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
// Skip header (DATA FILE MUST ALWAYS CONTAIN HEADER)
String line = reader.readLine();
// Begin to process from 2nd line
line = reader.readLine();
while (line != null) {
// Split funcName and time
String[] lineInfo = line.split("\\s+");
String funcName = lineInfo[0].trim();
// Split time in minutes and seconds
String[] timeInfo = lineInfo[1].split(":");
int seconds = Integer.valueOf(timeInfo[1].trim());
int minutes = Integer.valueOf(timeInfo[0].trim());
// Store the function name and its times
FuncTime ft = new FuncTime(seconds, minutes);
data.put(funcName, ft);
// Read next line
line = reader.readLine();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
// Print parsed information
FuncTime totalTime = new FuncTime();
for (Entry<String, FuncTime> entry : data.entrySet()) {
String funcName = entry.getKey();
FuncTime ft = entry.getValue();
System.out.println(funcName + " " + ft);
totalTime.accumulate(ft);
}
// Print total
System.out.println(data.size() + " functions in total time of " + totalTime);
}
public static void main(String[] args) {
String fileName = args[0];
parseInfo(fileName);
}
}
You can store the example data you provided in a file named example.data:
$ more example.data
Function Time
print() 0:32
find() 0:40
insert() 1:34
And run the above code obtaining the following output:
insert() 1:34
print() 0:32
find() 0:40
3 functions in total time of 2:46
You mean something like this?
int count = 0;
int totalMinutes = 0;
int totalSeconds = 0;
try (BufferedReader in = Files.newBufferedReader(Paths.get("test.txt"))) {
Pattern p = Pattern.compile("(\\S+)\\s+(\\d+):(\\d+)");
for (String line; (line = in.readLine()) != null; ) {
Matcher m = p.matcher(line);
if (m.matches()) {
// not used: String function = m.group(1);
int minutes = Integer.parseInt(m.group(2));
int seconds = Integer.parseInt(m.group(3));
count++;
totalMinutes += minutes;
totalSeconds += seconds;
}
}
}
if (count == 0) {
System.out.println("No functions found");
} else {
totalMinutes += totalSeconds / 60;
totalSeconds %= 60;
System.out.printf("%d functions in total time of %d minutes %d seconds%n",
count, totalMinutes, totalSeconds);
}
Output
3 functions in total time of 2 minutes 46 seconds

How can a User create dates in my Calender (java)?

I m currently trying to code a Calender with java.
I created 3 classes:
1. Date( includes year, month....)
2. Event(includes people, place, the class Date ... + an option to create dates )
3. Mainclass My mainclass that contains the menu.
My problem is that I don't know how the user is able to create his own date, because I have to create the object Termin myself... So, can somebody help me fix this? Thx in advance!
public class Event {
private String mDescription, mPlace, mNames;
private Date mStart, mEnd;
Termin(String description, String place, String names, Date start, Date end) {
mBetreff = description;
mOrt = place;
mNamen = names;
mBeginn = start;
mEnde = end;
}
public void create() {
Scanner read = new Scanner(System.in);
System.out.println("Enter 1. description 2. place 3. names 4. start 5. end ein");
mDescription = read.nextLine();
mPlace = read.nextLine();
mNames = read.nextLine();
}
public String toString() {
return "Description : " + mDescription + "\nPlace: " + mPlace + "\nNames: " + mNames + "\nIts starts at " + mStart
+ " and ends at " + mEnd;
}
}
public class Date {
private int year, day, month, hours, minutes;
Datum(int year, int month, int day, int hours, int minutes) {
this.day= day;
this.year= year;
this.month= month;
this.hours= hours;
this.minutes= minutes;
}
public String toString() {
return "\n" + day + "." + month + "." + year + " um " + hours+ ":" + minutes;
}
public void enterDate() {
}
}
EDIT:
I asked this question 2 years ago, back when I just started coding and had no idea of oop and encapsulation ...
To answer my own question, for every newbie that also tries to create a terminal calender:
Date needs the following methos:
public setDate() {
this.year = read.nextLine();
...
}
for every member.
Event takes the resulting object Date, either in the constructor or in a setter like method.
Creating an instance-method to create an appointment is kind of... strange since one needs to create an appointment (called Termin in your case) to create an appointment. One possibility would be the builder pattern. By having a public static inner builder class, you can set the constructor(s) private and enforce the use of that builder:
public class Main {
private int value;
private Main(int value) {
this.value = value;
}
public int getValue() {
return (this.value);
}
public static class MainBuilder {
boolean valueWasSet;
int value;
public MainBuilder() {
this.valueWasSet = false;
this.value = -1;
}
public void setValue(int value) {
this.value = value;
this.valueWasSet = true;
}
public Main build() {
if (!this.valueWasSet) {
throw new IllegalStateException("value must be set before a Main can be build.");
}
return (new Main(this.value));
}
}
}
(this is a simplified sketch to show the core mechanism on how to assert that certain values are set before constructing a Main through MainBuilder.
The process of constructing a Main would be:
MainBuilder builder = new MainBuilder();
builder.setValue(100);
// all following Main's will have a value of 100
Main mainOne = builder.build();
Main mainTwo = builder.build();
builder.setValue(200);
// all following Main's will have a value of 200
Main mainThree = builder.build();
Main mainFour = builder.build();

Change from hour minute second to second from string

Now,I have a string String time= "200hour 0minute 0second"
I want to track numbers in string and convert to second..As above string..I want to get value 200*3600..
My code:
//change from hour minute to second
public String changeSecond(String time)
{
String result;
int ind_hour=time.indexOf("hour");
int ind_minute=time.indexOf("minute");
int ind_second=time.indexOf("second");
int hour=Integer.parseInt(time.substring(0, ind_hour));
int minute=Integer.parseInt(time.substring(ind_hour+1, ind_minute));;
int second=Integer.parseInt(time.substring(ind_minute+1, ind_second));
result=String.valueOf(hour*3600+minute*60+second);
return result;
}
but when i run changeSecond(time).It don't work..How must I do.
public String changeSecond(String time)
{
String result;
int ind_hour=time.indexOf("hour");
int ind_minute=time.indexOf("minute");
int ind_second=time.indexOf("second");
int hour=Integer.parseInt(time.substring(0, ind_hour));
int minute=Integer.parseInt(time.substring(ind_hour+6, ind_minute));; // value 6 is length of minute
int second=Integer.parseInt(time.substring(ind_minute+6, ind_second));
int totalsec=((hour*60*60)+(minute*60)+second);
result=String.valueOf(totalsec);
return result;
}
You should make changes to the following lines:
int hour=Integer.parseInt(time.substring(0, ind_hour));
int minute=Integer.parseInt(time.substring(ind_hour+5, ind_minute));
int second=Integer.parseInt(time.substring(ind_minute+7, ind_second));
Its not the way to do it.But It will work.Try this,
String hour="200hour 0minute 0second";
String[] secondarray=hour.split("hour");
String second=secondarray[0]; //here "second" will have the value 200
You can split the tab into 3 parts : One will contains the hours, another the minutes and the last one the seconds.
public static String changeSecond(String time)
{
String tab[] = time.split(" ");
String result = "";
int ind_hour=tab[0].indexOf("hour");
int ind_minute=tab[1].indexOf("minute");
int ind_second=tab[2].indexOf("second");
int hour=Integer.parseInt(tab[0].substring(0, ind_hour));
int minute=Integer.parseInt(tab[1].substring(0, ind_minute));
int second=Integer.parseInt(tab[2].substring(0, ind_second));
result=String.valueOf(hour*3600+minute*60+second);
return result;
}
This is the cleanest solution I could come up with. Just split on " " then remove the text that's irrelevant.
public String changeSecond(final String time)
{
final String[] times = time.split(" ");
final int hour = Integer.parseInt(times[0].replace("hour", ""));
final int minute = Integer.parseInt(times[1].replace("minute", ""));
final int second = Integer.parseInt(times[2].replace("second", ""));
return String.valueOf(hour*3600+minute*60+second);
}
The initial code was throwing parsing errors since alpha characters were being passed to the Integer.parseInt method. The alpha characters were being included because the substring did not take into account the length of the terms hour, minute and second. I would recommend splitting the string to tidy things up.
public String changeSecond(String time) {
String[] tokens = time.split(" ");
tokens[0] = tokens[0].substring(0, tokens[0].indexOf("hour"));
tokens[1] = tokens[1].substring(0, tokens[1].indexOf("minute"));
tokens[2] = tokens[2].substring(0, tokens[2].indexOf("second"));
return String.valueOf(Integer.parseInt(tokens[0]) * 3600
+ Integer.parseInt(tokens[1]) * 60 + Integer.parseInt(tokens[2]));
}
Update your hours,minutes and seconds parsing as:
int hour=Integer.parseInt(time.substring(0, ind_hour));
int minute=Integer.parseInt(time.substring(ind_hour + "hour".length() + 1, ind_minute));
int second=Integer.parseInt(time.substring(ind_minute + "minute".length() + 1, ind_second));

Returning a double from a method

I am currently writing a program that will read through a designated text file that checks the transaction values of each buy/sell/summary and checks the arithmetic such that if the transactions from the buy and sell statements do not equal the total transaction amount that was given in the summary then it outputs an error and closes the program. But currently my method scanMoneyValue has an error that says it's not returning a double, when in fact it is. Is there a different way I should go about returning the values from my method? Here is my code for reference:
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
public class RecurrsionFileChecker {
public static void main(String[] args) {
int result;
//File Chooser Window
JFileChooser chooser = new JFileChooser("/home/nick/workspace/CS 1410-001/src/assignment03");
chooser.setDialogTitle("Please choose a file to be checked");
result = chooser.showOpenDialog(null);
//User Cancelled the chooser
if (result == JFileChooser.CANCEL_OPTION)
return;
File inputfile = chooser.getSelectedFile();
try
{
Scanner in = new Scanner(inputfile);
//Call Method to look at next transaction
scanNextTransaction(in);
}
catch (IOException e)
{
System.out.println("Could not read file: " + inputfile);
}
}
/**
* Returns double if the parameter Scanner has an error that does,
* not match the summary before it.
*
* #param s Any scanner
* #return double if Summaries don't match.
*/
public static double scanNextTransaction(Scanner s)
{
String buy, sell, summary, date;
double amount = 0, referenceValue, total = 0;
summary = s.next();
date = s.next();
referenceValue = scanMoneyValue(s);
while (s.hasNext())
{
if (s.next() == "Buy")
{
date = s.next();
amount = scanMoneyValue(s);
}
if(s.next() == "Sell")
{
date = s.next();
amount = scanMoneyValue(s);
}
if(s.next() == "Summary")
{
amount = scanSubSummary(s);
}
//add the transactions
total = total + amount;
}
return total;
}
public static double scanMoneyValue(Scanner in)
{
String dollar = in.next();
if(dollar.charAt(0) == '$')
{ //convert string to a double
String amount = dollar.substring(1);
double complete = Double.parseDouble(amount);
complete = complete * 100;
return complete;
}
}
public static double scanSubSummary(Scanner sub)
{
String summaryDate, transDate, transType;
int summarySubEntries, count = 0;
double transValue, summaryValue = 0, totalValue = 0, summaryAmount;
summaryDate = sub.next();
summaryAmount = scanMoneyValue(sub);
summarySubEntries = sub.nextInt();
while (count != summarySubEntries)
{
transType = sub.next();
if (transType == "Summary")
{
summaryValue = scanSubSummary(sub);
}
transValue = scanMoneyValue(sub);
totalValue = transValue + totalValue + summaryValue;
count++;
}
if (totalValue != summaryAmount)
{
System.out.print("Summary error on " + summaryDate + ".");
System.out.println("Amount is $" + summaryAmount + ", " + "should be $" + totalValue + ".");
}
return totalValue;
}
}
public static double scanMoneyValue(Scanner in)
{
String dollar = in.next();
if(dollar.charAt(0) == '$')
{ //convert string to a double
String amount = dollar.substring(1);
double complete = Double.parseDouble(amount);
complete = complete * 100;
return complete;
}
}
If the if condition fails then there's no return statement. You have a return inside of the condition but not outside. You'll need to add a return statement at the end, or throw an exception if not having a dollar sign is an error.
Okay, looking at the only relevant part of your code:
public static double scanMoneyValue(Scanner in)
{
String dollar = in.next();
if(dollar.charAt(0) == '$')
{ //convert string to a double
String amount = dollar.substring(1);
double complete = Double.parseDouble(amount);
complete = complete * 100;
return complete;
}
}
You do return a value if dollar starts with a $... but what do you expect to happen if it doesn't start with $? Currently you reach the end of the method without returning anything, which isn't valid.
You should probably throw an exception, if this is unexpected data that you can't actually handle.
Additionally, you shouldn't really use double for currency values anyway, due to the nature of binary floating point types. Consider using BigDecimal instead.
public static double scanMoneyValue(Scanner in)
{
String dollar = in.next();
if(dollar.charAt(0) == '$')
{ //convert string to a double
String amount = dollar.substring(1);
double complete = Double.parseDouble(amount);
complete = complete * 100;
return complete;
}
//NEED RETURN STATEMENT HERE
}
The error you get is because when you write a function all branches of that function must return a value of the correct type. In your case, if the if-statement fails it hits the end of the function without returning anything.
Its better to change it on
public static double scanMoneyValue(Scanner in)
{
String dollar = in.next();
String amount = dollar.replaceAll("[^\\d.]+", "")
double complete = Double.parseDouble(amount);
complete = complete * 100;
return complete;
}
link on explain - Parsing a currency String in java

Categories

Resources