Manipulating tokens to deal with variable number of strings on one line - java

I will try to explain this as much as I can. I am reading scores from a file onto which my form appends lines. The line consists of a date, home team, score, away team, score.
The stats I gather is away wins, home wins and draws.
The following code works perfectly
JButton viewStatsButton = new JButton(new AbstractAction("VIEW STATS")
{
public void actionPerformed( ActionEvent e )
{
int homeScore = 0;
int awayScore = 0;
int homeWins = 0;
int awayWins = 0;
int scoreDraw = 0;
String line = null;
String output;
String matchDay;
#SuppressWarnings("unused")
String homeTeam;
#SuppressWarnings("unused")
String awayTeam;
String file = "scores.dat";
StringTokenizer tokenizer;
FileReader fileReader = null;
try
{
fileReader = new FileReader (file);
}
catch (FileNotFoundException e1)
{
e1.printStackTrace();
}
BufferedReader inFile = new BufferedReader (fileReader);
try
{
line = inFile.readLine();
}
catch (IOException e1)
{
e1.printStackTrace();
}
while(line != null)
{
tokenizer = new StringTokenizer(line);
matchDay = tokenizer.nextToken();
homeTeam = tokenizer.nextToken();
try
{
homeScore = Integer.parseInt(tokenizer.nextToken());
}
catch (NumberFormatException exception)
{
System.out.println("Error in input. Line ignored:");
System.out.println(line);
}
awayTeam = tokenizer.nextToken();
try
{
awayScore = Integer.parseInt(tokenizer.nextToken());
}
catch (NumberFormatException exception)
{
System.out.println("Error in input. Line ignored:");
System.out.println(line);
}
if(homeScore > awayScore)
{
homeWins++;
}
else if(awayScore > homeScore)
{
awayWins++;
}
else
{
scoreDraw++;
}
try
{
line = inFile.readLine();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
try
{
inFile.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
output = "Home Wins : "+homeWins+"\nAway Wins : "+awayWins+"\nDraws : "+scoreDraw;
JTextArea textArea = new JTextArea();
frame.getContentPane().add(textArea, BorderLayout.CENTER);
textArea.setText(output);
}
});
scorePanel.add(viewStatsButton);
}
The problem does not come to light until the name of team is made out of two strings i.e.Newcastle United. What I had to do was append the two strings together like NewcastleUnited. I have tried to find out the length of the token and if it's less than 3 then i take it and parse it as integer but it seems that even if the next token reference is in an if statement it still moves to the token after it.
I would appreciate any help and guidance.

Try following
Before calling tokenizer.nextToken() check tokenizer.hasMoreTokens() to ensure that there is a token to read
if(tokenizer.hasMoreTokens())
{
x = tokenizer.nextToken();
}
After reading team name(first part) check whether next part is integer if it is, treat it as score, otherwise append it to team name.
homeTeam = tokenizer.nextToken();
String temp = tokenizer.nextToken();
try
{
homeScore = Integer.parseInt(temp);
}
catch(Exception e)
{
//Comes here if temp is not an integer, so temp is second part of name
homeTeam = homeTeam + " "+temp;
homeScore = Integer.parseInt(tokenizer.nextToken());
}
//Whatever the case, if we come here, it means both hometeam and score are assigned.
...........
...........
...........
Don't forgot to check tokenizer.hasMoreTokens() if you are not sure whether there is a token.

Related

How to skip blank cells when reading a csv file in Java?

Trying to create a csv file reader, but the reader gets an ArrayIndexOutOfBoundsException when it comes across an end of line blank.
Example: Name, Email, Age, City
John, johnsmith#email, 23, New York - This works and is standard
John, johnsmith#email, 23, - This fails
,,23,New York - This works
John, johnsmith#email,, - This fails
Any additional feedback is welcome as well!
Here's the code.
public class Main {
static String filepath = "filepath.csv";
public static void main(String[] args) {
SQLiteDB db = new SQLiteDB();
CSVReader(filepath);
}
public static void CSVReader(String filepath) {
List<User> users = new ArrayList<User>();
BufferedReader br = null;
String line;
int count = 1;
try {
br = new BufferedReader(new FileReader(filepath));
while ((line = br.readLine()) != null) {
if(line.trim().length() > 0) {
User user = new User();
String[] userinfo = line.split(",(?=([^\"]|\"[^\"]*\")*$)");
user.firstName = userinfo[0];
user.lastName = userinfo[1];
user.email = userinfo[2];
user.gender = userinfo[3];
user.image = userinfo[4];
user.bank = userinfo[5];
user.transaction = userinfo[6];
user.bool1 = userinfo[7];
user.bool2 = userinfo[8];
user.city = userinfo[9];
users.add(user);
System.out.println("Count:" + count + " " + user.getBool2());
count++;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
For the city value, just use the ternary operator to check the array length before assignment:
user.city = userinfo.length == 10 ? userinfo[9] : "";
If this is not a homework project, why don't you use a library? There are several on GitHub, and here is one that seems easy to use - https://github.com/osiegmar/FastCSV.

Why I could not save the contents of a file after reading it twice?

Already fixed. Thanks for Mas & ruhul for observing my bugs.
I was trying to read a text file twice, named stationary.txt. The contents of the file has three columns such as the amount, the name of product and the total price.
What I am trying to do first is by averaging each product's price by reading line by line. Then I closed the Buffered and then open it again and read. The second reading takes a variable average and compares each product's price line by line. If line 1 is over the average, then write it into dearer.txt, otherwise write it into cheap.txt
Here is the stationary.txt
1 Highlighter 5.99
2 Pen 9.00
3 Eraser 5.00
4 DrawingPin 2.75
5 Highlighter 10.99
6 FountainPen 20.50
7 Pencil 14.50
Below is the source code
import java.util.*;
import java.io.*;
public class Ques {
public static void main(String[] args) throws FileNotFoundException {
double average = 0;
File inFile = new File("stationary.txt");
FileReader fileReader = new FileReader(inFile);
BufferedReader bufReader = new BufferedReader(fileReader);
File outFilel = new File("dearer.txt");
FileOutputStream outFileStreaml = new FileOutputStream(outFilel);
PrintWriter outStream1 = new PrintWriter(outFileStreaml);
File outFile2 = new File("cheap.txt");
FileOutputStream outFileStream2 = new FileOutputStream(outFile2);
PrintWriter outStream2 = new PrintWriter(outFileStream2);
computeAverage(bufReader, outStream1, outStream2, average);
}
public static void computeAverage(BufferedReader bufReader, PrintWriter outStream1, PrintWriter outStream2, double average) {
String line = "";
double mark = 0;
double sum = 0;
int count = 0;
try {
bufReader.readLine();
while ((line = bufReader.readLine()) != null) {
String [] data = line.split(" ");
mark = Double.parseDouble(data[2]);
sum += mark;
count++;
}
average = sum / count;
compareMark(outStream1, outStream2, average);
} catch (NumberFormatException | IOException e) {
System.out.println(e);
} finally {
if (bufReader != null) {
try {
bufReader.close();
} catch ( IOException e) {
e.printStackTrace();
}
}
}
}
public static void compareMark(PrintWriter outStream1, PrintWriter outStream2, double average) throws FileNotFoundException {
File inFile = new File("stationary.txt");
FileReader fileReader = new FileReader(inFile);
BufferedReader bufReader = new BufferedReader(fileReader);
String line = " ";
double sum = 0;
double mark = 0;
int count = 0;
try {
double ave = (double) Math.round(average * 100) / 100;
System.out.println("another " + ave);
bufReader.readLine();
while ((line = bufReader.readLine()) != null) {
System.out.println(line);
String [] data = line.split(" ");
mark = Double.parseDouble(data[2]);
if (mark > ave) {
System.out.println("Over");
outStream1.write(line);
} else {
System.out.println("Less");
outStream2.write(line);
}
}
} catch (IOException e) {
System.out.println(e);
} catch (NumberFormatException ex) {
System.out.println(ex);
} finally {
if (bufReader != null) {
try {
bufReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
The source code is perfectly working, just that I received 0 bytes of both files after executing reading twice (first, doing average and last, doing comparison). Why is that? what am I doing wrong here?
Thank you for your kind help.
Your code is not correct and does not compile. But the main flaws are the following:
Your Double.parseDouble(data[2]) shouldn't work with your 4th line of data. Better use Double.parseDouble(data[data.length - 1])
Remove the readLine()-calls in front of the while-loop.
Write the lines including a line separator.
Close the OutStreams
The Data File that you have provided have the columns seperated by a space. As the 2nd Column has data which contains spaces, the convertion of data[2] to double will trigger an exception. Which will make the program to close the buffers and exit.
Use Commas to seperate column data.
Use better exception handling to find exceptions easily.
All you need is to close those output stream. As you are using bufferredWriter and not flushing it after each write you need to close those output-stream. which will write back those lines or datas into the file. Here is an example how you can do it:
Example 1: using flush().
....
outStream1.write(line);
outStream1.flush();
} else {
System.out.println("Less");
outStream2.write(line);
outStream2.flush();
}
Example 2: most efficient (either way you need to close those buffer too like bufReader.close())
...
} catch (IOException e) {
System.out.println(e);
} catch (NumberFormatException ex) {
System.out.println(ex);
} finally {
// add try catch.
outStream2.close();
outStream1.close();
if (bufReader != null ... ) {
try {
bufReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
As requested, an example using List
First a class to hold the stationary data, must be completed:
public class Stationary {
private final int id; // or String if desired
private final String name;
private final double mark; // BigDecimal would be better for money
public Stationary(int id, String name, double mark) {
// TODO error checking
this.id = id;
...
}
public int getId() {
return id;
}
... // TODO other getters
// TODO equals, hashCode, toString
}
and to read the file:
public List<Stationary> read(File file) {
List<Stationary> list= new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
// TODO parse line into id, name, mark
list.add(new Stationary(id, name, mark);
}
}
return list;
}
now the list can be used as needed, e.g. average:
List<Stationary> stationaries = read(STATIONARY_FILE);
...
for (Stationary stationary : stationaries) {
sum += stationary.getMark();
count += 1;
}
...
streams not used to keep it simple

Comparing integers from a text file and program that has strings involved

I've tried in vain to compare scores in my application with scores already saved in a separate text file. Comparing the score is easy enough when strings aren't involved but when I save the score and assign it a name, the program doesn't work as it cannot parse strings & integers.
Example text file:
Name, 8
Name, 1
Name, 4
Code I'm using to compare:
int highScore = 0;
try {
BufferedReader reader = new BufferedReader(new FileReader("txt.txt"));
String line = reader.readLine();
while (line != null)
{
try {
int score = Integer.parseInt(line.trim());
if (score > highScore)
{
highScore = score;
}
} catch (NumberFormatException e1) {
//ignore invalid scores
//System.err.println("ignoring invalid score: " + line);
}
line = reader.readLine();
}
reader.close();
} catch (IOException ex) {
System.err.println("ERROR");
}
The rest of the code is fine and the score is generated as the game finishes comparing it to the score in the file, it just generates a 0 value when comparing as it reads the string and doesn't work. I'm not sure on how to use scanners/delimiters.
EDIT:
I'd like the program to execute and show the name of the user which got that highscore. So the desired output would be;
The all time high score was 8 by Name1
Currently it only says the highscore (following Michu93's input).
Run the below program. It will give you desired output. Please correct the other things, I just concentrated on output.
public class Test {
static int highScore = 0;
static String highscorer = "";
public static void main(String[] args) {
try {
BufferedReader reader = new BufferedReader(new FileReader("src/com/test/package1/txt.txt"));
String line = null;
while ((line = reader.readLine()) != null) {
try {
String[] parts = line.split(",");
int tempScore = Integer.parseInt(parts[1].trim());
String tempHigScorer = (parts[0]);
if (tempScore > highScore) {
highScore = tempScore;
highscorer = tempHigScorer;
}
} catch (NumberFormatException e1) {
// handle NumberFormatException if any
}
}
reader.close();
} catch (IOException ex) {
System.err.println("ERROR");
}
System.out.println("The all time high score was " + highScore + " by name " + highscorer);
}
}
Remove digits from string and parse it to int:
int score = Integer.valueOf(line.replaceAll("[^\\d.]", ""));
#Edit
int highScore = 0;
String name = "";
try {
BufferedReader reader = new BufferedReader(new FileReader("txt.txt"));
String line = reader.readLine();
while (line != null) {
try {
int score = Integer.parseInt(line.split(" ")[1]);
if (score > highScore) {
highScore = score;
name = line.split(" ")[0].replace(",", "");
}
} catch (NumberFormatException e1) {
//ignore invalid scores
//System.err.println("ignoring invalid score: " + line);
}
line = reader.readLine();
}
System.out.println(String.format("The all time high score was %s by %s", highscore, name));
} catch (IOException ex) {
System.err.println("ERROR");
} finally {
reader.close(); // close stream always in finnaly block or use try with resources!!!
}
Observe that when you read a whole line you are getting a String with both Name and the Integer you want to get. I'd do the following:
int highScore = 0;
String name = "";
try {
BufferedReader reader = new BufferedReader(new FileReader("txt.txt"));
String line = null;
while ((line = reader.readLine()) != null) {
try {
String[] parts = line.split(",");
if(parts.length > 1){
int score = Integer.parseInt(parts[1].trim());
if (score > highScore) {
highScore = score;
name = line[0];
}
}
} catch (NumberFormatException e1) {
//ignore invalid scores
//System.err.println("ignoring invalid score: " + line);
}
}
System.out.println("The all time high score was %s by %s", highScore, name);
reader.close();

How to check if txt file contains a String, if so don't duplicate it

So right now I'm making a mod in Minecraft where it takes everyones username from a server and adds it to a txt file, it works but the the problem is I don't want to duplicate the names when I use the command again. Nothing has worked so far. How would I check if the txt already contains the username, don't add it again? Thank you. Again, I need it to before writing another name to the list, check the txt file if it already contains the name, if so don't add it.
for (int i = 0; i < minecraft.thePlayer.sendQueue.playerInfoList.size(); i++) {
List playerList = minecraft.thePlayer.sendQueue.playerInfoList;
GuiPlayerInfo playerInfo = (GuiPlayerInfo) playerList.get(i);
String playerName = StringUtils.stripControlCodes(playerInfo.name);
try {
fileWriter = new FileWriter(GameDirectory() + "\\scraped.txt", true);
bufferedReader = new BufferedReader(new FileReader(GameDirectory() + "\\scraped.txt"));
lineNumberReader = new LineNumberReader(new FileReader(GameDirectory() + "\\scraped.txt"));
} catch (IOException e) {
e.printStackTrace();
}
printWriter = new PrintWriter(fileWriter);
try {
fileWriter.write(playerName + "\r\n");
lineNumberReader.skip(Long.MAX_VALUE);
} catch (IOException e) {
e.printStackTrace();
}
printWriter.flush();
}
addMessage("Scraped " + lineNumberReader.getLineNumber() + " usernames!");
EDIT: Really need an answer guys :( Thank you
EDIT: this is what I have now, but it's not even writing it anymore.
List playerList = minecraft.thePlayer.sendQueue.playerInfoList;
for (int i = 0; i < minecraft.thePlayer.sendQueue.playerInfoList.size(); i++) {
GuiPlayerInfo playerInfo = (GuiPlayerInfo) playerList.get(i);
String playerName = StringUtils.stripControlCodes(playerInfo.name);
String lines;
try {
if ((lines = bufferedReader.readLine()) != null) {
if (!lines.contains(playerName)) {
bufferedWriter.write(playerName);
bufferedWriter.newLine();
bufferedWriter.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
int linenumber = 0;
try {
while (lineNumberReader.readLine() != null) {
linenumber++;
}
} catch (IOException e) {
e.printStackTrace();
}
The logic of your second piece of code is wrong. If you write out the pseudo-code of it, it's easy to see why:
Open a File Reader at the start of the file
For every Player on the server
Save the player name
Read the next line of the file
If we have not reached the end of the file
If the player name is not on this line of the file
Write the name of the player to the file
You need to read the entire file outside of the loop, and then check if the player exists anywhere in the file, not just if it happens to be on the line which is the same position as the player on the server.
The easiest way to do this is to keep the players in a list while you're processing, and read/write them to file, like this:
public static List<String> loadPlayerList() throws FileNotFoundException
{
final Scanner scanner = new Scanner(new File(GameDirectory() + "\\scraped.txt"));
final List<String> players = new ArrayList<>();
while(scanner.hasNextLine())
players.add(scanner.nextLine());
return players;
}
public static void writePlayersList(final List<String> players) throws IOException
{
try(final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream((GameDirectory() + "\\scraped.txt")))))
{
for(final String player : players)
{
writer.write(player);
writer.newLine();
}
}
}
public static void main(String[] args) throws IOException
{
final List<String> players = loadPlayerList();
for(final GuiPlayerInfo player : minecraft.thePlayer.sendQueue.playerInfoList)
{
final String playerName = StringUtils.stripControlCodes(player.name);
if(!players.contains(playerName))
players.add(playerName);
}
writePlayersList(players);
}

Writing Out to Console as Well as to File

I am trying to get the output of my java program to write to a file.
The user inputs some data which should not be included in the file. When the program responds it should output information to the user, as well as write SOLELY the output to a file.
From examples I have begun with this at the top of my driver class:
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static String lineFromOutput;
This code is in every place where I might receive output from the program:
try {
lineFromInput = in.readLine();
FileWrite.write(lineFromInput);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
And the class its calling is:
public class FileWrite {
public static void write(String message) {
PrintWriter out = null;
try {
out = new PrintWriter(new FileWriter("output.txt"), true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.write(message);
out.close();
}
}
It creates the output file, but thats it. None of the output from the program is written.
I've looked over numerous examples and this seems to be the easiest way to get the ball rolling, although I'm open to any other suggestions.
Thanks!
Each call to write opens and closes the text file. Each time it is opened it is overwritten, so I would expect only the last thing to be written to appear in the file.
I recommend opening the output file from a constructor, and closing it from a close method.
I think it should be InputStremReader with single t in statement below:
static BufferedReader in= new BufferedReader(new OutputtStreamReader(System.in));
static String lineFromOutput;
As
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static String lineFromOutput;
EDIT: This works fine. Please make sure you provide the input through input console. Also please note that it reads and write(overwrite) single line ONLY.
public class FileWrite {
public static void write(String message) {
PrintWriter out = null;
try {
out = new PrintWriter(new FileWriter("output.txt"), true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.write(message);
out.close();
}
public static void main(String[] args){
String lineFromInput;
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
lineFromInput = in.readLine();
FileWrite.write(lineFromInput);
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
EDIT 2: Updated program for multi-line inputs. Its not best way to open and close file each time to write, but I am just trying to make your program work with minor changes. Let me know, if you need suggestion to avoid repeated opening/closing of the output file.
Change Highlights:
Read lines until "exit"(change the word as desired) is received in input
Open the file in append mode.
public class FileWrite {
public static void write(String message) {
PrintWriter out = null;
try {
out = new PrintWriter(new FileWriter("output.txt", true), true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.write(message);
out.close();
}
public static void main(String[] args){
String lineFromInput = "";
try {
System.out.println("Provide the inputs in any number of lines");
System.out.println("Type \"exit\" in new line when done");
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
while(!"exit".equals(lineFromInput)){
lineFromInput = in.readLine();
FileWrite.write(lineFromInput+System.lineSeparator());
}
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
EDIT3: Your updated program using Scanner to read the inputs:
private static HashMap<Integer, Object> shapes =
new HashMap<Integer, Object>();
static int i = 0;
public static void main(String[] args) {
PrintWriter output = null;
Scanner scanner = new Scanner(System.in);
try {
output = new PrintWriter(new FileWriter("output.txt"), true);
} catch (IOException e1) {
System.err.println("You don't have accress to this file");
System.exit(1);
}
String command = "";
while(!"quit".equalsIgnoreCase(command)){
System.out.println("Enter your Command: ");
command = scanner.next();
if (command.equalsIgnoreCase("create")) {
String type = scanner.next();
if (type.equalsIgnoreCase("line")) {
double length = scanner.nextDouble();
Line l = new Line(length);
scanner.nextLine();//flush the previous line
String line = scanner.nextLine();
output.format("%s", line);
shapes.put(i, l);
i++;
}else if (type.equalsIgnoreCase("circle")) {
double radius = scanner.nextDouble();
String color = scanner.next();
Circle c = new Circle(radius, Colors.valueOf(color));
scanner.nextLine();//flush the previous line
String line = scanner.nextLine();
output.format("%s", line);
shapes.put(i, c);
i++;
}else if (type.equals("rectangle")) {
double length = scanner.nextDouble();
double width = scanner.nextDouble();
String color = scanner.next();
Rectangle r = new Rectangle(length, width,
Colors.valueOf(color));
scanner.nextLine();//flush the previous line
String line = scanner.nextLine();
output.format("%s", line);
shapes.put(i, r);
i++;
}else if (type.equals("square")) {
double length = scanner.nextDouble();
String color = scanner.next();
Square s = new Square(length, Colors.valueOf(color));
scanner.nextLine();//flush the previous line
String line = scanner.nextLine();
output.format("%s", line);
shapes.put(i, s);
i++;
}
}else if (command.equals("printbyperimeter")) {
Shape[] shapeArray = shapes.values().toArray(new Shape[0]);
Arrays.sort(shapeArray);
System.out.println("Print in ascending order...");
for (int j = 0; j < shapeArray.length; j++) {
Shape temp = shapeArray[j];
if (temp.getClass().getName().equals("Line")) {
System.out.println("Shape: "
+ temp.getClass().getName() + ", Perimeter: "
+ temp.getPerimeter());
} else {
System.out.println("Shape: "
+ temp.getClass().getName() + ", Color: "
+ ((Colorable) temp).getColor()
+ ", Perimeter: " + temp.getPerimeter());
}
}
}else if (command.equals("printbyarea")) {
Shape[] shapeArray = shapes.values().toArray(new Shape[0]);
System.out.println("Print in random order...");
for (int j = 0; j < shapeArray.length; j++) {
Shape temp = shapeArray[j];
if (!temp.getClass().getName().equals("Line")) {
System.out.println("Shape: "
+ temp.getClass().getName() + ", Color: "
+ ((Colorable) temp).getColor() + ", Area: "
+ ((Areable) temp).getArea());
}
}
}else if (command.equals("quit")) {
scanner.close();
System.exit(0);
}
}
output.close();
}
Try using the code. It works for me. You just need to change the file path to match where you want the output to go. I am using a BufferedWriter here which I believe is preferred.
public static void main(String[] args) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String lineFromOutput;
try {
lineFromOutput = in.readLine();
FileWrite.write(lineFromOutput);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static class FileWrite {
private static void write(String message) throws IOException {
BufferedWriter out = null;
try {
out = new BufferedWriter(new FileWriter(new File("C:\\Users\\Teresa\\Dropbox\\output.txt")));
//Replace the above line with your path.
out.write(message);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();
}
}

Categories