Searching in file - java - java

I will write data into the text file in format like this:
Jonathan 09.5.2015 1
John 10.5.2015 4
Jonathan 11.5.2015 14
Jonathan 12.5.2015 15
Jonathan 13.5.2015 7
Tobias 14.5.2015 9
Jonathan 15.5.2015 6
The last number is hours. I need to make something where I can write two dates and name. For example - Jonathan 11.5.2015 and second date 15.5.2015. All I want to do is count hours between these dates. Output should looks like Jonathan 11.5.2014 - 15.5.2014 - 42 hours I don't have problem with GUI but I don't know the right way how to compute my result.

Assuming that you have to write a method that, given a text file in the above format, a name and two dates, returns the total hours attributed to that person between the two dates, your code can be made very simple:
public int totalHours(Iterable<String> input, String person, String date1, String date2) {
SimpleDateFormat sdf = new SimpleDateFormat("MM.dd.yyyy");
Date start = sdf.parse(date1);
Date end = sdf.parse(date2);
int total = 0;
for (String line : input) { // assuming each string in input is a line
String parts[] = line.split(" ");
if ( ! parts[0].equals(person)) continue; // ignore - not him
Date d = sdf.parse(parts[1]);
if (d.compareTo(end) > 0) break; // if dates are sorted, we're finished
if (d.compareTo(start) <= 0) total += Integer.parseInt(parts[2]);
}
return total;
}
This code assumes that your input is already split into lines. You write that you already know how to read from files, so this should not be an obstacle. The function would run a lot faster (for repeated queries) if you store all lines in a TreeMap, indexed by their dates. And even more efficient if you built a HashMap<String, TreeMap<Date, Integer> > from the file, where the strings would be people's names and the integers would be the hours on those dates.
Edit: one way of doing the file-reading part
There are many ways of reading files. The most standard is the one you describe in your comment. This is a modified version that makes minimal changes to the above totalHours (argument input is now an Iterable<String> instead of String[]). The code has been adapted from
Iterating over the content of a text file line by line - is there a best practice? (vs. PMD's AssignmentInOperand):
public class IterableReader implements Iterable<String> {
private BufferedReader r;
public IterableReader(String fileName) throws IOException {
r = new BufferedReader(new FileReader(fileName));
}
public Iterator<String> iterator() {
return new Iterator<String>() {
String nextLine = readAndIfNullClose();
private String readAndIfNullClose() {
try {
String line = r.readLine();
if (line == null) r.close();
return line;
} catch (IOException e) {
return null;
}
}
#Override
public boolean hasNext() {
return nextLine != null;
}
#Override
public String next() {
String line = nextLine;
nextLine = readAndIfNullClose();
return line;
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
And you should now be able to call it as follows:
System.out.println("Hours worked by Bob from 11.5.2015 to 15.5.2015: "
+ totalHours(new IterableReader("inputfile.txt"),
"Bob", "11.5.2015", "15.5.2015"));

import java.io.*;
class Test{
BufferedReader f = null;
try{
f = new BufferedReader(new FileReader("youFile.txt"));
String something=null;
while((something=f.readLine())!=null){
String[] part= something.split(" ");
}
}catch(FileNotFoundException e){
e.getMessage();
}
}
After you split this code, you will get a array "part" with 3 index
per line, so you should convert to int or String depending what you
want to do. 0 = name 1 = hour 2 = this forever alone number :D

Related

Problems parsing in objects from buffered file and sending to the proper constructors

So i am having trouble wrapping my head around an issue, current working on a midi player that reads a file using buffered reader. i am reading the each object from the file as a string into an array list. Problem is when within the file there can be three different potential objects, the frequency of a note which is double, the midi note value an int, and a the note in letters(c4#). How can i tell which type of object exists in the string object from the ArrayList i have built.
ArrayList<String> noteList = new ArrayList<String>();
Note note;
String file = JOptionPane.showInputDialog("enter the file name of the song");
String line;
try
{
BufferedReader bufread = new BufferedReader(new FileReader("res/"+file));
while((line = bufread.readLine()) != null)
{
String[] result = line.split(",");
for(String str : result)
{
noteList.add(str);
}
}
bufread.close();
}
catch (IOException e)
{
e.printStackTrace();
}
for(int i=0; i<al.size();i++)
{
note = new Note(al.get(i)); //this is where the three constructors should be called
int midiInteger = note.getMIDIAbsoluteNumber();
channels[15].noteOn(midiInteger,127);
Thread.sleep(400);
channels[15].noteOff(midiInteger,127);
}
The constructors are just simple
public Note(double frequency)
{
frequency = this.frequency;
}
public Note(int noteNum)
{
noteNum = this.Note;
}
public Note(String letterNote)
{
letterNote = this.letterNote;
}
How do i differentiate between string or double objects from an array List of type string. I can't tell if i should change to ArrayList and make the object Note serializable or to just test the ArrayList element for a . or isLetter() and go from there or is there a more efficient way.
It seems that regex should do.
Double is different from integer by floating point, test it with /^[0-9]+(\\.[0-9]+)?$ and as for the notes, this could help:
Regex for matching a music Chord

Formatting an array list into a specific format

The program I am writing will sort a hospital record that comes in a text file. The format of the text file is lastname,firstname,age,roomnumber, it will look exactly like this :
Franklin,Benjamin,74,18
Hamilton,Alexander,25,6
Thatcher,Margaret,65,3
Nixon,Richard,45,7
and has to be printed with a certain format, but the user will specify how they are sorted. The format will look like this when sorted by last name:
Last First Age Room
Coolidge Calvin 24 27
Franklin Benjamin 74 8
Hamilton Alexander 50 123
Nixon Richard 45 7
I have been stuck on trying to find a way to store the lines and still be able to print out the lines together in order to keep the information together.
The Program has to be called through command-line and at the same time the program is called the user must specify the input file as the first argument (args[0]) and how to sort it as the second argument (args[1]).
I have tried a few different ways but I keep getting stuck in the same place, what would be the best way to approach this?
This is the current code btw. and the comment blocks is old code I have tried and keep it around, just in case.
import java.io.*;
import java.util.*;
public class PatientRecord {
public static void main(String args[])
{
System.out.println("Servando Hernandez");
System.out.println("Patient sorting Program.");
//
// Scanner scan = null;
// try
// {
// scan = new Scanner(new File(args[0]));
// }
// catch (FileNotFoundException e)
// {
// System.err.println("File path \"" + args[0] + "\" not found.");
// System.exit(0);
// }
//
// ArrayList<String> lines=new ArrayList<String>();
//
// while(scan.hasNextLine())
// lines.add(scan.nextLine());
//
// if(!(args.length == 0))
// {
// if(args[1] == lastname)
// {
// sortByLastName();
// }
// else if(args[1] == firstname)
// {
// sortByLastName();
// }
// else if(args[1] == age)
// {
// sortByAge();
// }
// else if(args[1] == roomnumber)
// {
// sortByRoomNumber();
// }
// }
//
List<Patient> patients = new ArrayList<>();
while(scan.hasNextLine())
{
String[] values= scan.nextLine().split(",");
patients.add(new Patient())
}
String sortType= args[1]
switch(sortType))
{
case "firsname":
break;
case "lastname":
break;
case "age":
break;
case "roomnumber":
break;
}
}
// static String sortByLastName()
// {
// Collections.sort(lines);
//
// for(String x : lines)
// System.out.println(x);
// }
class Patient
{
String firstName;
String lastName;
int age;
int roomNumber;
}
You should write a custom Comparator, let's call it PatientComparator. I will not implement the compare method completely, that's your job :-)
class PatientComparator implements Comparator<Patient> {
String sortType;
public PatientComparator(String sortType) {
this.sortType = sortType;
}
#Override
public int compare(Patient a, Patient b) {
// TODO: write your switch case here
return a.firstName.compareTo(b.firstName);
}
Then, you can sort the Patients using your own Comparator:
Collections.sort(patients, new PatientComparator(arg[1]));
Well I would start by dividing your exercise into two parts:
1- Calling the program through command-line with args[0]. Going through the file and showing the contents to the user (by respecting your format).
2- Add sorting to your script (this can be done in many ways; in general by overriding the compare method). Do step 1,sort with regarding to arg[1] and then the output.
To get you started I have done step 1 for you without doing any formatting on the output.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class Test3 {
//You will store each line as an array of strings
//then you store the lines in a list of arrays of strings
public static ArrayList<String[]> mainList=new ArrayList<String[]>();
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new FileReader(args[0]));
try {
//reading each line from the input file
String line = br.readLine();
//spliting the line by comma (,) which will return
//an array of strings - our names and numbers in string format
while (line != null) {
String[] lineElements=line.split(",");
line = br.readLine();
mainList.add(lineElements);
}
} finally {
br.close();
}
//showing to the user
for (String[] line :mainList){
for (String x:line){
System.out.print(x+" ");
}
System.out.println("");
}
}
}
You simply compile with: javac name.java
Then you simply specify the file's location when you actually run it: java name /path/to/your/file/
I have run it using your sample file and I get this in the console (you simply have to format the output):
Franklin Benjamin 74 18
Hamilton Alexander 25 6
Thatcher Margaret 65 3
Nixon Richard 45 7
There is much more to do but I think this is a great start!

I am getting a Array Index out of bounds yet I can't find the what is causing it?

In this class I am just working with a binary file but every time I compile I get an array index out of bounds all I needed to do was enhance this code so instead of it reading and writing from a text file it does it using binary, my array list seems to be fine to me? any help would be appreciated
import java.util.*;
import java.io.*;
import java.nio.file.*;
public final class ProductBinaryFile implements ProductDAO
{
private ArrayList<Product> products = null;
private Path productsPath = null;
private File productsFile = null;
private final String FIELD_SEP = "\t";
public ProductBinaryFile()
{
productsPath = Paths.get("products.bin");
productsFile = productsPath.toFile();
**products = this.getProducts();**
}
public ArrayList<Product> getProducts()
{
// if the products file has already been read, don't read it again
if (products != null)
return products;
products = new ArrayList<>();
if (Files.exists(productsPath)) // prevent the FileNotFoundException
{
try (DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream(productsFile))))
{
// read all products stored in the file
// into the array list
String line = in.readUTF();
while(line != null)
{
String[] columns = line.split(FIELD_SEP);
String code = columns[0];
**String description = columns[1];**
String price = columns[2];
Product p = new Product(
code, description, Double.parseDouble(price));
products.add(p);
line = in.readUTF();
}
}
catch(IOException e)
{
System.out.println(e);
return null;
}
}
return products;
}
public Product getProduct(String code)
{
for (Product p : products)
{
if (p.getCode().equals(code))
return p;
}
return null;
}
public boolean addProduct(Product p)
{
products.add(p);
return this.saveProducts();
}
public boolean deleteProduct(Product p)
{
products.remove(p);
return this.saveProducts();
}
public boolean updateProduct(Product newProduct)
{
// get the old product and remove it
Product oldProduct = this.getProduct(newProduct.getCode());
int i = products.indexOf(oldProduct);
products.remove(i);
// add the updated product
products.add(i, newProduct);
return this.saveProducts();
}
private boolean saveProducts()
{
try (DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(productsFile))))
{
// write all products in the array list
// to the file
for (Product p : products)
{
out.writeUTF(p.getCode() + FIELD_SEP);
out.writeUTF(p.getDescription() + FIELD_SEP);
out.writeDouble(p.getPrice());
}
}
catch(IOException e)
{
System.out.println(e);
return false;
}
return true;
}
}
my text file am trying to read from:
In below code, looks like your columns array length is 1. So, it can not access [1]. It can only access [0]
String[] columns = line.split(FIELD_SEP);
String code = columns[0];
**String description = columns[1];**
Check the length of columns array, by doing system out:
System.out.println("columns length : " + columns.length)
Answer Updated after Question updation:
After your recent comment and new error point** to this.getProducts, I am assuming that your issue lies in productFile content.
Do this:
BufferedReader in = new BufferedReader(new FileReader(productsFile));
in.readLine();
The way you are reading it is not right. Do what I have suggested. Then do split after reading the line.
Note: readUTF is for reading characters which have been encoded using formatted UTF-8. This simply means that this reads the data in the form of java primitive types. So that when you read, you can convert them directly back to java primitive type. Not recommend for reading normal UTF-8 string.
Note: readUTF should only used when you have written in the form of java primitive types(ie: writeUTF). Reading/Writing in the form of java primitive types.
Answer Updated (As OP wants to read it as java primitive types):
The way you are reading and getting the result is perfectly fine. Because readUTF is supposed to read java primitive types. Which is why you are getting java(check text file) in line variable. Check the way you are writing it. I don't know why you are doing string split when you are directly reading java primitive types. You need to keep doing readUTF and create the Product object out of it.
I imagine that your error is in one of the following lines:
String code = columns[0];
String description = columns[1];
String price = columns[2];
My theory is that what you're reading in is not as long as you think it is (perhaps tab is a poor choice for a delimiter); so you're only getting one entry or something. Get the length of columns and iterate through it (and print the elements) to make sure it's exactly what you think it is.
EDIT:
The way split works is that it takes your string and separates it based on your delimiter, in this case: tab. It's only going to have a length of one if there are zero tabs. If the input contains two tabs, for example: "gdfb\tdrfb\trdb," it will have length 3
Second Edit:
If you're only reading a standard text file, why not use BufferedReader or Scanner?
Ex: Scanner fromFile= new Scanner(new FileReader(filename));
then you can just use nextLine() to get the entire line and split on that.

Preserving line breaks and spacing in file IO

I am workig on a pretty neat problem challenge that involves reading words from a .txt file. The program must allow for ANY .txt file to be read, ergo the program cannot predict what words it will be dealing with.
Then, it takes the words and makes them their "Pig Latin" counterpart, and writes them into a new file. There are a lot more requirements to this problem but siffice to say, I have every part solved save one...when printng to the new file I am unable to perserve the line spacing. That is to say, if line 1 has 5 words and then there is a break and line 2 has 3 words and a break...the same must be true for the new file. As it stands now, it all works but all the converted words are all listed one after the other.
I am interested in learning this so I am OK if you all wish to play coy in your answers. Although I have been at this for 9 hours so "semi-coy" will be appreaciated as well :) Please pay close attention to the "while" statements in the code that is where the file IO action is happening. I am wondering if I need to utilize the nextLine() commands from the scanner and then make a string off that...then make substrings off the nextLine() string to convert the words one at a time. The substrings could be splits or tokens, or something else - I am unclear on this part and token attempts are giving me compiler arrors exceptions "java.util.NoSuchElementException" - I do not seem to understand the correct call for a split command. I tried something like String a = scan.nextLine() where "scan" is my scanner var. Then tried String b = a.split() no go. Anyway here is my code and see if you can figure out what I am missing.
Here is code and thank you very much in advance Java gods....
import java.util.*;
import javax.swing.*;
import java.io.*;
import java.text.*;
public class PigLatinTranslator
{
static final String ay = "ay"; // "ay" is added to the end of every word in pig latin
public static void main(String [] args) throws IOException
{
File nonPiggedFile = new File(...);
String nonPiggedFileName = nonPiggedFile.getName();
Scanner scan = new Scanner(nonPiggedFile);
nonPiggedFileName = ...;
File pigLatinFile = new File(nonPiggedFileName + "-pigLatin.txt"); //references a file that may or may not exist yet
pigLatinFile.createNewFile();
FileWriter newPigLatinFile = new FileWriter(nonPiggedFileName + "-pigLatin.txt", true);
PrintWriter PrintToPLF = new PrintWriter(newPigLatinFile);
while (scan.hasNext())
{
boolean next;
while (next = scan.hasNext())
{
String nonPig = scan.next();
nonPig = nonPig.toLowerCase();
StringBuilder PigLatWord = new StringBuilder(nonPig);
PigLatWord.insert(nonPig.length(), nonPig.charAt(0) );
PigLatWord.insert(nonPig.length() + 1, ay);
PigLatWord.deleteCharAt(0);
String plw = PigLatWord.toString();
if (plw.contains("!") )
{
plw = plw.replace("!", "") + "!";
}
if (plw.contains(".") )
{
plw = plw.replace(".", "") + ".";
}
if (plw.contains("?") )
{
plw = plw.replace("?", "") + "?";
}
PrintToPLF.print(plw + " ");
}
PrintToPLF.close();
}
}
}
Use BufferedReader, not Scanner. http://docs.oracle.com/javase/6/docs/api/java/io/BufferedReader.html
I leave that part of it as an exercise for the original poster, it's easy once you know the right class to use! (And hopefully you learn something instead of copy-pasting my code).
Then pass the entire line into functions like this: (note this does not correctly handle quotes as it puts all non-apostrophe punctuation at the end of the word). Also it assumes that punctuation is supposed to go at the end of the word.
private static final String vowels = "AEIOUaeiou";
private static final String punct = ".,!?";
public static String pigifyLine(String oneLine) {
StringBuilder pigified = new StringBuilder();
boolean first = true;
for (String word : oneLine.split(" ")) {
if (!first) pigified.append(" ");
pigified.append(pigify(word));
first = false;
}
return pigified.toString();
}
public static String pigify(String oneWord) {
char[] chars = oneWord.toCharArray();
StringBuilder consonants = new StringBuilder();
StringBuilder newWord = new StringBuilder();
StringBuilder punctuation = new StringBuilder();
boolean consDone = false; // set to true when the first consonant group is done
for (int i = 0; i < chars.length; i++) {
// consonant
if (vowels.indexOf(chars[i]) == -1) {
// punctuation
if (punct.indexOf(chars[i]) > -1) {
punctuation.append(chars[i]);
consDone = true;
} else {
if (!consDone) { // we haven't found the consonants
consonants.append(chars[i]);
} else {
newWord.append(chars[i]);
}
}
} else {
consDone = true;
// vowel
newWord.append(chars[i]);
}
}
if (consonants.length() == 0) {
// vowel words are "about" -> "aboutway"
consonants.append("w");
}
consonants.append("ay");
return newWord.append(consonants).append(punctuation).toString();
}
You could try to store the count of words per line in a separate data structure, and use that as a guide for when to move on to the next line when writing the file.
I purposely made this semi-vague for you, but can elaborate on request.

Read String line by line

Given a string that isn't too long, what is the best way to read it line by line?
I know you can do:
BufferedReader reader = new BufferedReader(new StringReader(<string>));
reader.readLine();
Another way would be to take the substring on the eol:
final String eol = System.getProperty("line.separator");
output = output.substring(output.indexOf(eol + 1));
Any other maybe simpler ways of doing it? I have no problems with the above approaches, just interested to know if any of you know something that may look simpler and more efficient?
There is also Scanner. You can use it just like the BufferedReader:
Scanner scanner = new Scanner(myString);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
// process the line
}
scanner.close();
I think that this is a bit cleaner approach that both of the suggested ones.
You can also use the split method of String:
String[] lines = myString.split(System.getProperty("line.separator"));
This gives you all lines in a handy array.
I don't know about the performance of split. It uses regular expressions.
Since I was especially interested in the efficiency angle, I created a little test class (below). Outcome for 5,000,000 lines:
Comparing line breaking performance of different solutions
Testing 5000000 lines
Split (all): 14665 ms
Split (CR only): 3752 ms
Scanner: 10005
Reader: 2060
As usual, exact times may vary, but the ratio holds true however often I've run it.
Conclusion: the "simpler" and "more efficient" requirements of the OP can't be satisfied simultaneously, the split solution (in either incarnation) is simpler, but the Reader implementation beats the others hands down.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* Test class for splitting a string into lines at linebreaks
*/
public class LineBreakTest {
/** Main method: pass in desired line count as first parameter (default = 10000). */
public static void main(String[] args) {
int lineCount = args.length == 0 ? 10000 : Integer.parseInt(args[0]);
System.out.println("Comparing line breaking performance of different solutions");
System.out.printf("Testing %d lines%n", lineCount);
String text = createText(lineCount);
testSplitAllPlatforms(text);
testSplitWindowsOnly(text);
testScanner(text);
testReader(text);
}
private static void testSplitAllPlatforms(String text) {
long start = System.currentTimeMillis();
text.split("\n\r|\r");
System.out.printf("Split (regexp): %d%n", System.currentTimeMillis() - start);
}
private static void testSplitWindowsOnly(String text) {
long start = System.currentTimeMillis();
text.split("\n");
System.out.printf("Split (CR only): %d%n", System.currentTimeMillis() - start);
}
private static void testScanner(String text) {
long start = System.currentTimeMillis();
List<String> result = new ArrayList<>();
try (Scanner scanner = new Scanner(text)) {
while (scanner.hasNextLine()) {
result.add(scanner.nextLine());
}
}
System.out.printf("Scanner: %d%n", System.currentTimeMillis() - start);
}
private static void testReader(String text) {
long start = System.currentTimeMillis();
List<String> result = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new StringReader(text))) {
String line = reader.readLine();
while (line != null) {
result.add(line);
line = reader.readLine();
}
} catch (IOException exc) {
// quit
}
System.out.printf("Reader: %d%n", System.currentTimeMillis() - start);
}
private static String createText(int lineCount) {
StringBuilder result = new StringBuilder();
StringBuilder lineBuilder = new StringBuilder();
for (int i = 0; i < 20; i++) {
lineBuilder.append("word ");
}
String line = lineBuilder.toString();
for (int i = 0; i < lineCount; i++) {
result.append(line);
result.append("\n");
}
return result.toString();
}
}
Using Apache Commons IOUtils you can do this nicely via
List<String> lines = IOUtils.readLines(new StringReader(string));
It's not doing anything clever, but it's nice and compact. It'll handle streams as well, and you can get a LineIterator too if you prefer.
Since Java 11, there is a new method String.lines:
/**
* Returns a stream of lines extracted from this string,
* separated by line terminators.
* ...
*/
public Stream<String> lines() { ... }
Usage:
"line1\nline2\nlines3"
.lines()
.forEach(System.out::println);
Solution using Java 8 features such as Stream API and Method references
new BufferedReader(new StringReader(myString))
.lines().forEach(System.out::println);
or
public void someMethod(String myLongString) {
new BufferedReader(new StringReader(myLongString))
.lines().forEach(this::parseString);
}
private void parseString(String data) {
//do something
}
You can also use:
String[] lines = someString.split("\n");
If that doesn't work try replacing \n with \r\n.
You can use the stream api and a StringReader wrapped in a BufferedReader which got a lines() stream output in java 8:
import java.util.stream.*;
import java.io.*;
class test {
public static void main(String... a) {
String s = "this is a \nmultiline\rstring\r\nusing different newline styles";
new BufferedReader(new StringReader(s)).lines().forEach(
(line) -> System.out.println("one line of the string: " + line)
);
}
}
Gives
one line of the string: this is a
one line of the string: multiline
one line of the string: string
one line of the string: using different newline styles
Just like in BufferedReader's readLine, the newline character(s) themselves are not included. All kinds of newline separators are supported (in the same string even).
Or use new try with resources clause combined with Scanner:
try (Scanner scanner = new Scanner(value)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
// process the line
}
}
You can try the following regular expression:
\r?\n
Code:
String input = "\nab\n\n \n\ncd\nef\n\n\n\n\n";
String[] lines = input.split("\\r?\\n", -1);
int n = 1;
for(String line : lines) {
System.out.printf("\tLine %02d \"%s\"%n", n++, line);
}
Output:
Line 01 ""
Line 02 "ab"
Line 03 ""
Line 04 " "
Line 05 ""
Line 06 "cd"
Line 07 "ef"
Line 08 ""
Line 09 ""
Line 10 ""
Line 11 ""
Line 12 ""
The easiest and most universal approach would be to just use the regex Linebreak matcher \R which matches Any Unicode linebreak sequence:
Pattern NEWLINE = Pattern.compile("\\R")
String lines[] = NEWLINE.split(input)
#see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/regex/Pattern.html

Categories

Resources