Java | Finding specific lines from file - java

So I'm currently working on a project from school. I've saved data from customers in a .txt file in this format
-----
17-03-2020 15:49
WashType: De Luxe
ID: 1, Name: Janus Pedersen
-----
-----
20-03-2020 13:07
WashType: Standard
ID: 2, Name: Hardy Akira
-----
In order to thank customers for using this service, I'd like to give a customer some cinema tickets after each 10th purchase from us. To do that, I thought of reading this file again and look for their ID and count that but I simply can't make that work. My initial idea was something like the following, but it keeps giving me a null pointer
String[] words;
FileReader fr = new FileReader("stats.txt");
BufferedReader br = new BufferedReader(fr);
String s;
String input = String.valueOf(washCard.getCardID());
int count=0;
while((s=br.readLine())!=null)
{
words=s.split(" ");
for (String word : words)
{
if (word.equals(input))
{
count++;
System.out.println(word);
}
}
}
Anyone who has any great ideas for this?
For things to be easier I've added it all to a github repo:
https://github.com/rasm937k/curly-broccoli

The below code is based on Michał Kaciuba's answer but adapted to suit the actual format of your stats.txt file. I didn't know how to post this as a comment, hence I am posting it as an answer, but as I said, Michał Kaciuba should get the credit and I think you should accept his answer. Note that explanation of the code follows the actual code.
String input = String.valueOf(washCard.getCardID());
Pattern pttrn = Pattern.compile("^ID: (\\d+)");
Path p = Paths.get("stats.txt");
try {
long count = Files.lines(p) //throws java.io.IOException
.filter(l -> {Matcher mtchr = pttrn.matcher(l); return mtchr.find() && input.equals(mtchr.group(1));})
.count();
System.out.println(count);
}
catch (IOException x) {
x.printStackTrace();
}
Files.lines(p) creates a Stream where every element in the stream is a line from file stats.txt, i.e. a String.
The regular expression matches lines that start with ID: followed by a single space, followed by a series of one or more digits. The digits part is known as a capturing group because it is enclosed in parentheses.
The filter() checks to see if the line from the file matches the regular expression and if it does, the filter() then checks whether the "digits" in that line match your input, i.e. String.valueOf(washCard.getCardID()).
The count() counts all the elements in the stream returned by filter() and count() returns a long.

You can use Java 8 streams for that:
Files.lines(Paths.get("stats.txt"))
.map(line -> line.split(" "))
.filter(words -> words[5].equals(washCardId))
.count();
Also here's a nice tutorial on Java 8 Streams: https://www.baeldung.com/java-8-streams

Related

Reading data and storing in array Java

I am writing a program which will allow users to reserve a room in a hotel (University Project). I have got this problem where when I try and read data from the file and store it in an array I receive a NumberFormatException.
I have been stuck on this problem for a while now and cannot figure out where I am going wrong. I've read up on it and apparently its when I try and convert a String to a numeric but I cannot figure out how to fix it.
Any suggestions, please?
This is my code for my reader.
FileReader file = new FileReader("rooms.txt");
Scanner reader = new Scanner(file);
int index = 0;
while(reader.hasNext()) {
int RoomNum = Integer.parseInt(reader.nextLine());
String Type = reader.nextLine();
double Price = Double.parseDouble(reader.nextLine());
boolean Balcony = Boolean.parseBoolean(reader.nextLine());
boolean Lounge = Boolean.parseBoolean(reader.nextLine());
String Reserved = reader.nextLine();
rooms[index] = new Room(RoomNum, Type, Price, Balcony, Lounge, Reserved);
index++;
}
reader.close();
This is the error message
This is the data in my file which I am trying to read:
Change your while loop like this
while (reader.hasNextLine())
{
// then split reader.nextLine() data using .split() function
// and store it in string array
// after that you can extract data from the array and do whatever you want
}
You're trying to parse the whole line to Integer. You can read the whole line as a String, call
.split(" ")
on it. This will split the whole line into multiple values and put them into an array. Then you can grab each item from the array and parse separately as you intended.
Please avoid posting screenshots next time, use proper formatting and text so someone can easily copy your code or test data to IDE and reproduce the scenario.
Use next() instead of nextLine().
With Scanner one must use hasNextLine, nextLine, hasNext, next, hasNextInt, nextInt etcetera. I would do it as follows:
Using Path and Files - the newer more general classes i.o. File.
Files can read lines, here I use Files.lines which gives a Stream of lines, a bit like a loop.
Try-with-resources: try (AutoCloseable in = ...) { ... } ensures that in.close() is always called implicitly, even on exception or return.
The line is without line ending.
The line is split into words separated by one or more spaces.
Only lines with at least 6 words are handled.
Create a Room from the words.
Collect an array of Room-s.
So:
Path file = Paths.get("rooms.txt");
try (Stream<String> in = Files.lines(file)) {
rooms = in // Stream<String>
.map(line -> line.split(" +")) // Stream<String[]>
.filter(words -> words.length >= 6)
.map(words -> {
int roomNum = Integer.parseInt(words[0]);
String type = words[1];
double price = Double.parseDouble(words[2]);
boolean balcony = Boolean.parseBoolean(words[3]);
boolean lounge = Boolean.parseBoolean(words[4]);
String reserved = words[5];
return new Room(roomNum, type, price, balcony, lounge, reserved);
}) // Stream<Room>
.toArray(Room[]::new); // Room[]
}
For local variables use camelCase with a small letter in front.
The code uses the default character encoding of the system to convert the bytes in the file to java Unicode String. If you want all Unicode symbols,
you might store your list as Unicode UTF-8, and read them as follows:
try (Stream<String> in = Files.lines(file, StandardCharsets.UTF_8)) {
An other issue is the imprecise floating point double. You might use BigDecimal instead; it holds a precision:
BigDecimal price = new BigDecimal(words[2]);
It is however much more verbose, so you need to look at a couple of examples.

Method count words in a file

Hi guys I'm writing a method which counts words in a file, but apparently there is a mistake somewhere in the code and the method does not work. Here's my code:
public class Main2 {
public static void main(String[] args) {
count("/home/bruno/Desktop/WAR_JEE_S_09_Podstawy/MojPlik");
}
static int count(String fileName){
Path path = Paths.get(fileName);
int ilosc = 0;
String wyjscie = "";
try {
for (String charakter : Files.readAllLines(path)){
wyjscie += charakter;
}
StringTokenizer token = new StringTokenizer(wyjscie," \n");
} catch (IOException e) {
e.printStackTrace();
}
return ilosc;
}
}
The file path is correct, here is the file content
test test
test
test
after i call the method in main it displays nothing. Where is the mistake ?
Your code would count lines in a file ... well, if you followed up on that thought.
Right ow your code is simply reading lines, putting them into one large string, to then do nothing about the result of that operation. You have a single int counter ... who is init'ed to 0, and then just returned without ever being used/increased! And unless I am mistaken, readAllLines() will automatically remove the newline char in the end, so overall, your code is nothing but useless.
To count words you have to take each line and (for example) split that one-line-string for spaces. That gives you a number. Then add up these numbers.
Long story short: the real answer here is that you should step back. Don't just write code, assuming that this will magically solve the problem. Instead: first think up a strategy (algorithm) that solves the problem. Write down the algorithm ideas using a pen and paper. Then "manually" run the algorithm on some sample data. Then, in the end, turn the algorithm into code.
Also, beside that you does not output anything, there is a slight error behind you logic. I have made a few changes here and there to get your code working.
s.trim() removes any leading and trainling whitespace, and trimmed.split("\\s+") splits the string at any whitespace character, including spaces.
static int count(String fileName) throws IOException {
Path path = Paths.get(fileName);
int count = 0;
List<String> lines = Files.readAllLines(path);
for (String s : lines) {
String trimmed = s.trim();
count += trimmed.isEmpty() ? 0 : trimmed.split("\\s+").length;
}
return count;
}
Here is the code using functional-style programming in Java 8. This is also a common example of using Stream's flatMap - may be used for counting or printing words from a file.
long n = Files.lines(Paths.get("test.txt"))
.flatMap(s -> Stream.of(s.split("\\s+")))
.count();
System.out.println("No. of words: " + n);
Note the Files.lines(Path) returns a Stream<String> which has the lines from the input file. This method is similar to readAllLines, but returns a stream instead of a List.

In Java, how do I read both Strings and Doubles from the same txt file? [duplicate]

I am creating a simple program to data read from a text file. The file stores information about a person, with the name, age and a number on each line:
Eg: File format per line
Francis Bacon 50 2
I can read in a file no problem if it is just text, but I am confused on how to differentiate between text and numbers. Here is a look at my code:
import java.io.*;
public class Test{
private People people[] = new People[5];
public Test(){
BufferedReader input;
input = new BufferedReader(new FileReader("People.txt"));// file to be readfrom
String fileLine;
int i = 0;
while (test != null){
fileLine = input.readLine();
// Confused as to how to parse this line into seperate parts and store in object:
// eg:
people[i].addName(fileLine - part 1);
people[i].addBookNo(fileLine - part 2);
people[i].addRating(fileLine - part 3)
i++
}
}
}
I strongly suggest you use the Scanner class instead. That class provides you with methods such as nextInt and so on.
You could use it to read from the file directly like this:
Scanner s = new Scanner(new File("People.txt"));
while (s.hasNext()) {
people[i].addName(s.next());
people[i].addBookNo(s.nextInt());
people[i].addRating(s.nextInt());
}
(Just realized that you may have spaces in the name. That complicates things slightly, but I would still consider using a scanner.)
An alternative solution would be to use a regular expression and groups to parse the parts. Something like this should do:
(.*?)\s+(\d+)\s+(\d+)
The following regex works on these 3 cases, breaking them into 3 matched groups.
Regex
(.*)\s+(\d+)\s+(\d+)
Cases
Francis Bacon 50 2
Jill St. John 20 20
St. Francis Xavier III 3 3
If you want to do in this way, you can try doing like this :
Fixing the way data will be present in the file, say
firstName.lastName.age.number;
Then you can write code to read data upto . and store it in a variable (you will be knowing what it is meant for) and after ";" there will be second entry.

using split to get rid of regexp from an Arraylist

I am trying to create a spell checker, but before I can do so I must read in two separate files. The first (the dictionary), I did file. The second is a novel for which I must spell check. Problem is, I need to remove all special characters that are not letters (regexp?) from the novel. I am trying to use the string.split, but am having no luck. I am testing this one a small section of the novel, test2.
This is the section of code I have...
public static void readFileBook() {
File f = new File("test2.txt");
ArrayList<String> list2 = new ArrayList<String>();
try {
Scanner input = new Scanner(f);
int i = 0;
while (input.hasNext()) {
String oliver = input.next();
list2.add(oliver);
String[] oliverArray = oliver.split("[.#]");
System.out.println(list2.get(i));
i++;
}
} catch (IOException e) { //opening failed
e.printStackTrace();
}
}`enter code here`
I started small with the '.' and '#' symbols. The System.out is just to check if things are working (they aren't), but output still has symbols.
I know there is probably a more elegant way of doing this, but the instructor a specific thing in find.
Any help would be appreciated.
so in you code
String oliver = input.next();
list2.add(oliver);
String[] oliverArray = oliver.split("[.#]");
System.out.println(list2.get(i));
you are (line by line)
reading input into String oliver
adding oliver to a list
splitting oliver into oliverArray which never gets used
printing the string in the list at position i
How would you know if this is working or not?

Java - Ideas to turn strings into numbers (RegEx/Parsing/etc.)?

I'm reading in from a file, and the input is like this:
Description (1.0,2.0) (2,7.6) (2.1,3.0)
Description2 (4,1)
...
Description_n (4,18) (8, 7.20)
I want to be able to take the numbers inside parentheses and use turn them from strings into numbers so that I can do mathematical operations of them. Right now, to simplify things, my code only reads in the first line and then splits it based on spaces:
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(new File("filename.txt")));
//reader reads in the first line
String firstLine = reader.readLine();
//splits into an array of ["Description","(1.0,2.0)","(2,7.6)","(2.1,3.0)"]
String[] parts = first.split(" ");
//now I want to store 1.0, 2, and 2.1 in one array as ints and 2.0, 7.6, and 3.0 in another int array
} catch (Exception e) {
System.exit(0);
}
What are some ways I can store the numbers inside parentheses into two separate arrays of ints (see comment above)? Should I use regular expressions to somehow capture something of the form "( [1-9.] , [1-9.] )" and then pass those into another function that will then separate the first number in the pair from the second and then convert them both into integers? I'm new to regular expression parsing in Java, so I'm not sure how to implement this.
Or is there a simply, better way to do this?
This stores the numbers into Double-arrays (not two-dimensional arrays, arrays of Double objects), since some have .#. int-arrays would eliminate the post decimal part.
It uses the regex \b([\d.]+)\b to find each number within each paren-group, adding each to an ArrayList<Double>. Note that it assumes all input is perfect (nothing like (bogus,3.2). The list is then translated into an array of Double objects.
This should give you a good start towards your goal.
import java.util.Arrays;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
<P>{#code java DoubleInParenStringsToArrays}</P>
**/
public class DoubleInParenStringsToArrays {
public static final void main(String[] ignored) {
String input = "(1.0,2.0) (2,7.6) (2.1,3.0)";
String[] inputs = input.split(" ");
//"": Dummy string, to reuse matcher
Matcher mtchrGetNums = Pattern.compile("\\b([\\d.]+)\\b").matcher("");
for(String s : inputs) {
ArrayList<Double> doubleList = new ArrayList<Double>();
mtchrGetNums.reset(s);
while(mtchrGetNums.find()) {
//TODO: Crash if it's not a number!
doubleList.add(Double.parseDouble(mtchrGetNums.group(0)));
}
Double[] doubles = doubleList.toArray(new Double[doubleList.size()]);
System.out.println(Arrays.toString(doubles));
}
}
}
Output:
[C:\java_code\]java DoubleInParenStringsToArrays
[1.0, 2.0]
[2.0, 7.6]
[2.1, 3.0]
How to parse per item:
Double.parseDouble("your string here");
As for the storing, I didnt get the pattern you want to store your values. What's the reason why you want 1.0, 2, and 2.1 in 1 array and 2.0, 7.6, and 3.0 to another?
Just do Integer.parseInt(string), or Double.parseDouble(string), then add those to the array. I'm not really 100% sure what you're asking, though.
I would use a String Tokenizer.But need more information and thought for full impl.
This is your line : "Description (1.0,2.0) (2,7.6) (2.1,3.0)"
First thing - can there be cases without parenthesis? Will there always be sets f 2,2,2 numbers ?
Do you want to take care of errors at each number or just skip the line or skip processing if there is an error (like number of numbers does not match?).
Now you need a data structure to hold numbers. You could make a class to hold each individual element in a seperate property if each number has a distinct meaning in the domain or have an array list or simple array if you want to treat them as a simple list of numbers. If a class one sample (incopmplete):
class LineItem{
}
Now to actually break up the string there are many ways to do it. Really depends on the quality of data and how you want to deal with possible errors
One way is find the first opening parenthesis( take rest of string and parse out using a String Tokenizer.
Something like:
int i = str.indexOf("(");
String s2 = str.substring(i);
StringTokenizer st = new StringTokenizer(s2, "() ,";//parenthesis, comma and space
ArrayList<Double> lineVals1 = new ArrayList<Double>();
ArrayList<Double> lineVals1 = new ArrayList<Double>();
int cnt = 0;
while(st.hasMoreTokens()){
cnt++;//use this to keep count of how many numbers you got in line and raise error if need be
String stemp = st.nextToken();
if(isNumeric(stemo)){
if(cnt % 2 == 1){
lineVals1.add(Double.parseDouble(stemp));
}else{
lineVals2.add(Double.parseDouble(stemp));
}
}else{
/raise error if not numberic
}
}
public static boolean isNumeric(String str)
{
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}

Categories

Resources