Parsing various values in Textfile (Java) - java

I have a textfile as such:
type = "Movie"
year = 2014
Producer = "John"
title = "The Movie"
type = "Magazine"
year = 2013
Writer = "Alfred"
title = "The Magazine"
What I'm trying to do is, first, search the file for the type, in this case "Movie" or "Magazine".
If it's a Movie, store all the values below it, i.e
Set the movie variable to be 2014, Producer to be "John" etc.
If it's a Magazine type, store all the variables below it as well separately.
What I have so far is this:
public static void Parse(String inPath) {
String value;
try {
Scanner sc = new Scanner(new FileInputStream("resources/input.txt"));
while(sc.hasNextLine()) {
String line = sc.nextLine();
if(line.startsWith("type")) {
value = line.substring(8-line.length()-1);
System.out.println(value);
}
}
} catch (FileNotFoundException ex) {
Logger.getLogger(LibrarySearch.class.getName()).log(Level.SEVERE, null, ex);
}
}
However, I'm already having an issue in simply printing out the first type, which is "Movie". My program seems to skip that one, and print out "Magazine" instead.
For this problem solely, is it because the line: line.startsWith("type")is checking if the current line in the file starts with type, but since the actual String called lineis set to the nextline, it skips the first "type"?
Also, what would be the best approach to parsing the actual values (right side of equal sign) below the type "Movie" and "Magazine" respectively?

I recommend you try the following:
BufferedReader reader = new BufferedReader(new FileReader(new File("resources/input.txt")));
String line;
while((line = reader.readLine()) != null) {
if (line.contains("=")) {
String[] bits = line.split("=");
String name = bits[0].trim();
String value = bits[1].trim();
if (name.equals("type")) {
// Make a new object
} else if (name.equals("year")) {
// Store in the current object
}
} else {
// It's a new line, so you should make a new object to store stuff in.
}
}
In your code, the substring looks suspect to me. If you do a split based on the equals sign, then that should be much more resilient.

Related

How to extract objects separated by semi-colon in another file in Java

As part of a project I'm working on, I want to parse/extract objects separated by semi-colons in a separate file on each line, so that I can create new objects corresponding to the ones on each line in the file whilst reading it.
I will have a file which will be taken as a parameter into a method - the file will will contain Character objects which are separated by semi-colons as demonstrated below in an example. The numbers represent level and ExperiencePoints respectively.
Mario(1,2);Luigi(2,3);Bowser(1,4);Toad(1,4);Yoshi(0,2)
Mario(2,2);Luigi(3,3);Bowser(1,4);Toad(1,4);Yoshi(0,2)
Mario(3,2);Luigi(4,3);Bowser(2,4);Toad(1,4);Yoshi(2,2)
Mario(4,2);Luigi(5,3);Bowser(2,4);Toad(2,4);Yoshi(2,2)
Mario(5,2);Luigi(6,3);Bowser(2,4);Toad(2,4);Yoshi(3,2)
Mario(6,2);Luigi(7,3);Bowser(3,4);Toad(2,4);Yoshi(3,2)
So far, I've written a method which looks like this; it takes a file as a parameter and reads it line by line. I cannot work out how to parse a file with values separated by semi-colons however; do I have to create a separate method to do this? Would appreciate if someone can point me in the right direction.
public void main(String fileName)
throws IOException {
try {
BufferedReader br = new BufferedReader(new FileReader(fileName));
String line;
} catch (FileNotFoundException e) {
System.out.println("Error accessing file");
e.printStackTrace();
}
}
I apologize if the scope requires buffered reader, but inside your try method you could do:
String myFileAsText = new String(Files.readAllBytes(Paths.get(fileName)));
List<String> myObjects = Arrays.asList(myFileAsText.split("[;\r\n]"));
Which will give you an array of each element in String form, which you'll have to parse into your objects by iterating through.
Lets ignore the file part and just consider a String line that you want to parse.
String line = "Mario(1,2);Luigi(2,3);Bowser(1,4);Toad(1,4);Yoshi(0,2)"
Now, you want to parse your line.
String[] tokens = line.split(";");
The resulting array will have:
{ "Mario(1,2)", "Luigi(2,3)", ...}
Now you want to parse the i'th token.
String token = tokens[i]
if(token.contains("Mario")){
//parse out the ints possibly with a scanner and create a Mario
}
Another way to parse your line is to use a regex.
Pattern p = Pattern.compile("(\\w+)\\((\\d+),(\\d+)\\)");
Matcher m = p.matcher(line);
List<Character> characters = new ArrayList<>();
while(m.find()){
String name = m.group(1);
int exp = Integer.parseInt( m.group(2) );
int level = Integer.parseInt( m.group(3) );
Character c = new Character( name , exp, level );
characters.add( c );
}
If you need a different constructor based on the name you could do a switch statement.
Character c;
switch(name){
case "Mario":
c = new Mario(name, exp, level);
break;
case "Luigi":
c = new Mario(name, exp, level);
break;
default:
c = new Character(name, exp, level);
}
characters.add(c);
Another solution would be to serialize your objects using JSON.

Java-Reading from a file to initalize an object with data conversion

I have this file: "Test.txt" -> 1,cont,details,950.5,asd
My Class is Auto, the constructor is int, string, string, double, string.
How can I read from this file and then initialize my object with the correct data conversion?
I think I need to use a comma splitter too.
FileReader inFile2=null;
BufferedReader outBuffer2=null;
inFile2=new FileReader("Test.txt");
outBuffer2 = new BufferedReader(inFile2);
List<String> lines = new ArrayList<String>();
String line="";
while((line = outBuffer2.readLine()) != null) {
lines.add(line);
System.out.println(lines);
}
outBuffer2.close();
inFile2.close();
//
String[] splitTranzactie = lines.toArray(new String[]{});
Auto t = new Auto(Int32(splitTranzactie[0]), splitTranzactie[1], splitTranzactie[2],
ToDouble(splitTranzactie[3]), splitTranzactie[4]);
There are a few issues here. First of all:
String[] splitTranzactie = lines.toArray(new String[]{});
is going to just turn your list of lines into an array of lines. To split each line into its constituent parts you can use something like String.split(","). This will return an array of Strings. Note that if you expect any of the last values to be empty, i.e. ending in one or more commas then the returned array will be as long as the last value position it finds. i.e. if the line is 1,cont,details,, you split will return an array of length 3 not 5. You should code defensively against this.
To convert a String to an int or double you can use Integer.parseInt() and Double.parseInt() respectively. Again you may want to consider coding defensively if the values may be anything other than numeric values as those two methods will throw an exception if they can't parse the input.
You should also place your close() methods in a finally block to ensure they are called, however as they are AutoCloseable you can avoid this altogether by using the try-with-resources syntax which will close the reader automatically.
try(Reader in = new Reader()) {
}
A working example with all of the above (but without any defensive code) following your example may look something like the following:
List<Auto> autos = new ArrayList<>();
try (BufferedReader in = new BufferedReader(new FileReader("Test.txt"))) {
String line = null;
while((line = in.readLine()) != null) {
String[] values = line.split(",");
autos.add(new Auto(
Integer.parseInt(values[0]),
values[1],
values[2],
Double.parseDouble(values[3]),
values[4]));
}
}
you can create stream from the lines then you can apply the Function(ArrayList< String >,ArrayList< Auto >) interface to get data by defining custom behaviour through lambda function. To convert data to integer from String use Integer.parse(String) and for double data use Double.parse(string)
Using Java 8 stream:
try (Stream<String> fileStream = Files.lines(Paths.get("Test.txt"))) {
fileStream.map(line -> line.split(",")).forEach(array -> {
Auto auto = new Auto(Integer.parseInt(array[0]), array[1], array[2], Double.parseDouble(array[3]), array[4]);
});
}
You can collect the auto to list by:
List<Auto> autoList;
try (Stream<String> fileStream = Files.lines(Paths.get("Test.txt"))) {
autoList = fileStream.map(line -> {
String[] array = line.split(",");
return new Auto(Integer.parseInt(array[0]), array[1], array[2], Double.parseDouble(array[3]), array[4]);
}).collect(Collectors.toList());
}
Following your current scheme, here one way I might carry out the task. The code also validates the data and places defaults if those validations fail.
public List<Auto> getAutoListFromFile(String filePath) {
List<Auto> list = new ArrayList<>(); // Declare a List Interface
Auto auto; // Declare Auto
// Open a file reader. Try With Resourses is used here so as to auto close reader.
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line = "";
// Iterate through the file lines
while((line = reader.readLine()) != null) {
line = line.trim(); // Trim lines of any unwanted leading or trailing whitespaces, tabs, etc.
// Skip blank lines.
if (line.equals("")) {
continue;
}
System.out.println(line); // Display file line to console (remove if desired).
/* Split the current comma delimited file line into specific components.
A regex is used here to cover all comma/space scenarios (if any). */
String[] lineParts = line.split("\\s{0,},\\s{0,}");
// Establish the first Auto memeber value for the Auto class constructor.
int id = -1; // default
// Make sure it is an unsigned Integer value. RegEx is used here again.
if (lineParts[0].matches("\\d+")) {
id = Integer.parseInt(lineParts[0]);
}
// Establish the second Auto memeber value for the Auto class constructor.
String cont = !lineParts[1].equals("") ? lineParts[1] : "N/A"; //Ternary Used
// Establish the third Auto memeber value for the Auto class constructor.
String details = !lineParts[2].equals("") ? lineParts[2] : "N/A"; //Ternary Used
// Establish the fourth Auto memeber value for the Auto class constructor.
double price = 0.0d; //default
// Make sure it is a signed or unsigned Integer or double value. RegEx is used here again.
if (lineParts[3].matches("-?\\d+(\\.\\d+)?")) {
price = Double.parseDouble(lineParts[3]);
}
// Establish the fifth Auto memeber value for the Auto class constructor.
String asd = !lineParts[4].equals("") ? lineParts[4] : "N/A"; //Ternary Used
auto = new Auto(id, cont, details, price, asd); // Create an instance of Auto
list.add(auto); // Add Auto instance to List.
// Go and read next line if one exists
}
}
// Handle Exceptions.
catch (FileNotFoundException ex) {
Logger.getLogger("getAutoListFromFile() Method Error!").log(Level.SEVERE, null, ex);
}
catch (IOException ex) {
Logger.getLogger("getAutoListFromFile() Method Error!").log(Level.SEVERE, null, ex);
}
return list; // Return the filled list.
}
And to use this method you might do:
List<Auto> list = getAutoListFromFile("Test.txt");
For int you can use
int a = Integer.parseInt(string);
Almost the same for the double
double b = Double.parseDouble(string);
But be aware that both can throw NumberFormatException if the string is not what it is meant to be.

How To Read A Specific Part Of A Line In A Text File In Java?

I have a text file in which I have written some information line by line like this:
name|Number|amount|PIN
How can I read back data In a way that (for example) I will be able to use just the "name" part in a method?
The sample code is shown in the image below.
in the beginning declare a List to collect the accounts:
import java.util.ArrayList;
...
public Account[] inReader() { //BTW: why do you pass an Account[] here?
ArrayList accountList = new ArrayList();
...
}
replace the for(String records : dataRecords) {...} with
String name = dataRecords[0];
String cardNumber = dataRecords[1];
int pin = Integer.parseInt(dataRecords[2]); //to convert the String back to int
double balance = Double.parseDouble(dataRecords[3]);
Account account = new Account(name, cardNumber, pin, balance);
accountList.add(account);
because you already proceed record by record (while ((line = br.readLine())!=null) {...})
in the end return accountList.toArray(new Account[0]);
You can read the text line by line and then use the "|" delimiter to separate the columns.
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
}
You could read the file line-by-line and split on the delimiter '|'.
The following example assumes the filepath is in args[0] and would read then output the name component of the input:
public static void main(String[] args) {
File file = new File(args[0]);
BufferedReader br = new BufferedReader(new FileReader(file));
while(String line = br.readLine()) != null) {
String[] details = line.split("|");
System.out.println(details[0]);
}
}
As mentioned in the comment above, you can simply split the line on your delimiter, |, and go from there.
Something like:
public class Account {
// ...
public static Account parseLine(String line) {
String[] split = line.split("|");
return new Account(split[0], split[1], split[2], split[3]);
}
}
should work fine (assuming you have a constructor which takes the four things you're putting in). If your Account class has more information than this, you can create an AccountView or similarly named class which does only contain the details you have available here. With this, just iterate line by line, parse your lines to one of these Objects, and use it's properties (including the already available getters) when calling other methods which need name, etc.
First, you need to read the whole content of the file or line by line.
Then, for each line you need to create a function to split the line text by a configurable delimiter. This function can receive the column number and it should return the needed value. For example: extractData(line, 0) should return 'name', extractData(line, 2) should return 'amount' etc.
Also, you need some validation: what if there are only 3 columns and you expect 4? You can throw and exception or you can return null/empty.
There are many possible ways to do it. One of them is to make an object that will hold the data. Example since you know that your data will always have name, number, amount and pin then you can make a class like this:
public class MyData {
private String name;
private String number;
private double amount;
private String pin;
// Add getters and setters below
}
Then while reading the text file you can make a list of MyData and add each data. You can do it like this:
try {
BufferedReader reader = new BufferedReader(new FileReader("path\file.txt"));
String line = reader.readLine();
ArrayList<MyData> myDataList = new ArrayList<MyData>();
while (line != null) {
String[] dataParts = line.split("|"); // since your delimiter is "|"
MyData myData = new MyData();
myData.setName(dataParts[0]);
myData.setNumber(dataParts[1]);
myData.setAmount(Double.parseDouble(dataParts[2]));
myData.setPin(dataParts[3]);
myDataList.add(myData);
// read next line
line = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
Then you can use the data like this:
myDataList.get(0).getName(); // if you want to get the name of line 1
myDataList.get(1).getPin(); // if you want to get the pin of line 2
You can convert the file into a csv file and use a library specific for reading csv files, e.g. OpenCSV. This will give you more flexibility in handling the data in the file.

read txt file and store data in a hashtable in java

I am reading a txt file and store the data in a hashtable, but I couldn't get the correct output. the txt file like this (part) attached image
this is part of my data
And I want to store the column 1 and column 2 as the key(String type) in hashtable, and column 3 and column 4 as the value (ArrayList type) in hashtable.
My code below:
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"));
br.readLine();
ArrayList<String[]> value = new ArrayList<String[]>();
String[] probDes = new String[2];
String key = "";
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String [] splited = line.split("\\t");
source = splited[0];
action = splited[1];
key = source+","+action;
probDes[0] = splited[2];
probDes[1] = splited[3];
value.add(probDes);
hashTableForWorld.put(key, value);
System.out.println("hash table is like this:" +hashTableForWorld);
}
br.close();
return hashTableForWorld;
}
The output looks like this:
it's a very long long line
I think maybe the hashtable is broken, but I don't know why. Thank you for reading my problem.
The first thing we need to establish is that you have a really obvious XY-Problem, in that "what you need to do" and "how you're trying to solve it" are completely at odds with each other.
So let's go back to the original problem and try to work out what we need first.
As best as I can determine, source and action are connected, in that they represent queryable "keys" to your data structure, and probability, destination, and reward are queryable "outcomes" in your data structure. So we'll start by creating objects to represent those two concepts:
public class SourceAction implements Comparable<SourceAction>{
public final String source;
public final String action;
public SourceAction() {
this("", "");
}
public SourceAction(String source, String action) {
this.source = source;
this.action = action;
}
public int compareTo(SourceAction sa) {
int comp = source.compareTo(sa.source);
if(comp != 0) return comp;
return action.compareto(sa.action);
}
public boolean equals(SourceAction sa) {
return source.equals(sa.source) && action.equals(sa.action);
}
public String toString() {
return source + ',' + action;
}
}
public class Outcome {
public String probability; //You can use double if you've written code to parse the probability
public String destination;
public String reward; //you can use double if you're written code to parse the reward
public Outcome() {
this("", "", "");
}
public Outcome(String probability, String destination, String reward) {
this.probability = probability;
this.destination = destination;
this.reward = reward;
}
public boolean equals(Outcome o) {
return probability.equals(o.probability) && destination.equals(o.destination) && reward.equals(o.reward);
public String toString() {
return probability + ',' + destination + ',' + reward;
}
}
So then, given these objects, what sort of Data Structure can properly encapsulate the relationship between these objects, given that a SourceAction seems to have a One-To-Many relationship to Outcome objects? My suggestion is that a Map<SourceAction, List<Outcome>> represents this relationship.
private Map<SourceAction, List<Outcome>> readData() throws Exception {
It is possible to use a Hash Table (in this case, HashMap) to contain these objects, but I'm trying to keep the code as simple as possible, so we're going to stick to the more generic interface.
Then, we can reuse the logic you used in your original code to insert values into this data structure, with a few tweaks.
private Map<SourceAction, List<Outcome>> readData() {
//We're using a try-with-resources block to eliminate the later call to close the reader
try (BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"))) {
br.readLine();//Skip the first line because it's just a header
//I'm using a TreeMap because that makes the implementation simpler. If you absolutely
//need to use a HashMap, then make sure you implement a hash() function for SourceAction
Map<SourceAction, List<Outcome>> dataStructure = new TreeMap<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//split by tab
String [] splited = line.split("\\t");
SourceAction sourceAction = new SourceAction(splited[0], splited[1]);
Outcome outcome = new Outcome(splited[2], splited[3], splited[4]);
if(dataStructure.contains(sourceAction)) {
//Entry already found; we're just going to add this outcome to the already
//existing list.
dataStructure.get(sourceAction).add(outcome);
} else {
List<Outcome> outcomes = new ArrayList<>();
outcomes.add(outcome);
dataStructure.put(sourceAction, outcomes);
}
}
} catch (IOException e) {//Do whatever, or rethrow the exception}
return dataStructure;
}
Then, if you want to query for all the outcomes associated with a given source + action, you need only construct a SourceAction object and query the Map for it.
Map<SourceAction, List<Outcome>> actionMap = readData();
List<Outcome> outcomes = actionMap.get(new SourceAction("(1,1)", "Up"));
assert(outcomes != null);
assert(outcomes.size() == 3);
assert(outcomes.get(0).equals(new Outcome("0.8", "(1,2)", "-0.04")));
assert(outcomes.get(1).equals(new Outcome("0.1", "(2,1)", "-0.04")));
assert(outcomes.get(2).equals(new Outcome("0.1", "(1,1)", "-0.04")));
This should yield the functionality you need for your problem.
You should change your logic for adding to your hashtable to check for the key you create. If the key exists, then grab your array list of arrays that it maps to and add your array to it. Currently you will overwrite the data.
Try this
if(hashTableForWorld.containsKey(key))
{
value = hashTableForWorld.get(key);
value.add(probDes);
hashTableForWorld.put(key, value);
}
else
{
value = new ArrayList<String[]>();
value.add(probDes);
hashTableForWorld.put(key, value);
}
Then to print the contents try something like this
for (Map.Entry<String, ArrayList<String[]>> entry : hashTableForWorld.entrySet()) {
String key = entry.getKey();
ArrayList<String[]> value = entry.getValue();
System.out.println ("Key: " + key + " Value: ");
for(int i = 0; i < value.size(); i++)
{
System.out.print("Array " + i + ": ");
for(String val : value.get(i))
System.out.print(val + " :: ")
System.out.println();
}
}
Hashtable and ArrayList (and other collections) do not make a copy of key and value, and thus all values you are storing are the same probDes array you are allocating at the beginning (note that it is normal that the String[] appears in a cryptic form, you would have to make it pretty yourself, but you can still see that it is the very same cryptic thing all the time).
What is sure is that you should allocate a new probDes for each element inside the loop.
Based on your data you could work with an array as value in my opinion, there is no real use for the ArrayList
And the same applies to value, it has to be allocated separately upon encountering a new key:
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
try(BufferedReader br=new BufferedReader(new FileReader("MyGridWorld.txt"))) {
br.readLine();
Hashtable<String, ArrayList<String[]>> hashTableForWorld=new Hashtable<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String[] split = line.split("\\t");
source = split[0];
action = split[1];
String key = source+","+action;
String[] probDesRew = new String[3];
probDesRew[0] = split[2];
probDesRew[1] = split[3];
probDesRew[2] = split[4];
ArrayList<String[]> value = hashTableForWorld.get(key);
if(value == null){
value = new ArrayList<>();
hashTableForWorld.put(key, value);
}
value.add(probDesRew);
}
return hashTableForWorld;
}
}
Besides relocating the variables to their place of actual usage, the return value is also created locally, and the reader is wrapped into a try-with-resource construct which ensures that it is getting closed even if an exception occurs (see official tutorial here).

Reading file to arraylist with multiple data type

I have a problem with reading from a text file to an arraylist. The problem is that i don't know how to read in multiple types, because in my arraylist there are Points, Strings, booleans, therefor linesplit doesn't work. I checked all the topics and didn't find a solution to this.
edit: Elrendezes class looks like
class Elrendezes {
protected Point Po;
protected String hely;
protected String foglalo;
protected boolean foglalt;
}
Here's how my file looks like:
java.awt.Point[x=16,y=13], 1, name1, false
And the method to read is
public static ArrayList<Elrendezes> readDataFromFile(){
ArrayList<Elrendezes> ElrList = new ArrayList<Elrendezes>();
FileInputStream fstream = null;
try
{
fstream = new FileInputStream("src/files/DataFile.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine = null ;
String tokens[] = strLine.split(", ");
while ((strLine = br.readLine()) != null) {
tokens = strLine.split(", ");
// THIS DOES NOT WORK: ElrList.add(new Elrendezes(tokens[0], tokens[1], tokens[2], tokens[3]));
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try { fstream.close(); } catch ( Exception ignore ) {}
}
return ElrList;
}
As you probably dont know regular expressions, I will use:
Get x and y:
int v1 = strLine.indexOf("x=");
int v2 = strLine.indexOf(",y=");
int v3 = strLine.indexOf("]") ;
string x = strLine.substring(v1 +2, v2);
string y = strLine.substring(v2 +3, v3);
Break point representation from the rest.
string secondpart = strLine.substring(v3+1);
Now break secondpart with only the coma as separator.
Convert string representation, using Integer.parseInt() and etc..
Construct your object back.
Note: written in a hurry, check if the indexes used for x, y and secondpart are correct.
I also assumed the input is correct.
I think you have to choose a char to split the String.
Cast the split string into boolean, integer etc.
Elrendezes(String[] s){
Point Po = s[0]; // dont know how to cast string to point, never done before
hely = s[1];
foglalo = s[2];
foglalt = Boolean.parseBoolean(s[3]);
}

Categories