I’m working with java Scanner trying to extract product information from a text file called Inventory.txt.
This file contains data on products in this format:
“Danelectro|Bass|D56BASS-AQUA|336177|395.00Orange|Amplifier|BT1000-H|319578|899.00Planet Waves|Superpicks|1ORD2-5|301075|4.50Korg|X50 Music Synthesizer|X50|241473|735.00Alpine|Alto Sax|AAS143|198490|795.00”
I am trying to parse the strings and add them into an arraylist such that each element in the arraylist would look something like this:
"Danelectro|Bass|D56BASS-AQUA|336177|395.00"
"Orange|Amplifier|BT1000-H|319578|899.00"
"KorPlanet Waves|Superpicks|1ORD2-5|301075|4.50"
"g|X50 Music Synthesizer|X50|241473|735.00"
"Alpine|Alto Sax|AAS143|198490|555.00”
Following is my code:
public class ItemDao {
public ItemDao() {
scanFile();
}
public void scanFile() {
Scanner scanner;
ArrayList <String> content = new ArrayList <String>();
try {
Pattern p1 = Pattern.compile("\\.[0-9]{2}$");
scanner = new Scanner(new File("Inventory.txt"));
while (scanner.hasNext(p1)) {
content.add(scanner.next(p1));
}
for (String item : content) {
System.out.println("Items:" + item);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
When I tested this code I found that the arraylist is empty. Any help would be much appreciated.
java -jar A00123456Lab5.jar
Create an ItemDAO class in a dao package
This class will contain an static inner class which implements Comparator
(DAO = Data Access Object)
You can define a Scanner on a String, and a delimiter.
Since the | is used in regex as OR combinator, you have to mask it with (double)-backslash:
sc = new java.util.Scanner ("Danelectro|Bass|D56BASS-AQUA|336177|395.00");
sc.useDelimiter ("\\|");
String name = sc.next ();
// name: java.lang.String = Danelectro
String typ = sc.next ();
// typ: java.lang.String = Bass
String model = sc.next
// model: java.lang.String = D56BASS-AQUA
int id = sc.nextInt ();
// id: Int = 336177
val d = sc.nextDouble ();
// d: Double = 395.0
I see you're using a pattern, those can come in handy--but I'd just take each line and substring it.
while(scanner.hasNextLine()){
String temp = scanner.nextLine();
while(temp.indexOf("|") != -1){
content.add(temp.substring(temp.indexOf("|"));
temp.substring(temp.indexOf("|")+1);
}
}
Just a thought--might be easier to debug with this way.
Related
Ok, so I have this issue that I can't seem to wrap my head around.
what I'm trying to do, is the following:
read in a CSV file line by line, split it up at the comma and pass it into a hashmap and then carry out some operations.
I'm effectively trying to replicate some of the behaviours of map reduce in java.
Now, what I have so far is:
public class mapper {
public static void main(String[] args) {
//file reading - here.
Scanner filePathInput = new Scanner(System.in);
String filePath = filePathInput.nextLine();
File file = new File(filePath);
if (file.isFile()) {
Scanner fileInput = null;
try {
fileInput = new Scanner(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
ArrayList<String> lineBuffer = new ArrayList<>();
while (fileInput.hasNextLine()) {
String line = fileInput.nextLine();
// char ch = line.charAt(0);
lineBuffer.add(line);
//String[] values = line.split(",");
// Map<String, Integer> reducer = new HashMap<String, Integer>();
// parse the line here
//System.out.println(values);
}
HashMap<String, ArrayList<FlightData>> test = mapper(lineBuffer);
}
}
I then have the mapper to the hash map down:
public static HashMap<String, ArrayList<FlightData>> mapper(ArrayList<String> lineBuffer) {
HashMap<String, ArrayList<FlightData>> mapdata = new HashMap<>();
for (String flightData: lineBuffer) {
String[] str = flightData.split(",");
FlightData flight = new FlightData(str[0], str[1], str[2].toCharArray(),str[3].toCharArray(), new Date(Long.valueOf(str[4])), Long.valueOf(str[5]).longValue());
mapdata.get(flight.getFlightID());
if(mapdata.containsKey(flight.getFlightID())){
mapdata.get(flight.getFlightID()).add(flight);
}
else {
ArrayList<FlightData> noID = new ArrayList<>();
noID.add(flight);
mapdata.put(flight.getFlightID(), noID);
}
}
System.out.println(mapdata);
return mapdata;
}
I have my flight data object defined here with the getters etc:
public class FlightData {
private String passengerID;
private String flightID;
private char[] fromID = new char[3];
private char[] tooID = new char[3];
public Date departTime;
public long flightTimeMins;
public Date arrivalTime;
//Constucter;
public FlightData(String passengerID, String flightID, char[] fromID, char[] tooID, Date departTime, long flightTimeMins) {
setPassengerID(passengerID);
setFlightID(flightID);
setFromID(fromID);
setTooID(tooID);
setFlightTimeMins(flightTimeMins);
setDepartTime(departTime);
setArrivalTime(arrivalTime);
However, I am having an issue is, how do I carry out the validation:
presumably I need to create a class that contains all of my patterns and all of the logic for that right? and just call it when needed?
I have set up a basic class for this:
public class Validation {
public static void validate(String theReg, String str2Check) {
final Pattern PtnPassenger = Pattern.compile(theReg);
final Pattern PtnFlight = Pattern.compile(theReg);
final Pattern PtnFrom = Pattern.compile(theReg);
final Pattern PtnToo = Pattern.compile(theReg);
Matcher regexMatcher = PtnPassenger.matcher(str2Check);
while (regexMatcher.find()) {
if (regexMatcher.group().length() != 0) {
System.out.println(regexMatcher.group().trim());
}
}
}
But, how to I do the following:
set it up so that as each line is read it it checks, it is empty?
set it up so that then, if its not it checks that "cell" against the pattern, moves onto the next and repeats step 1
so for example, each line should contain following comma separated data:
PID, FID, FromID, TooID, time(linux epoch) minutes e.g:
BWI0520BG0, MOO1786A, MAD, FRA, 1420563408, 184
so, for example, for pID I would need a regex like this:
[A-Z]{3}[0-9]{4}[A-Z]{2}[0-9]{1}
but, how do I check each element? should I do this before I pass them into the hash map? or?
Any help would be great.
Cheers
I'm trying to figure out how to delete a specific line in my Arraylist when a user types in a book ID number. However it seems that it can't find that ID number anywhere in my Arraylist.
private void removeBook()
// Removes a certain book from the Book List.
{
Scanner IDS = setbookID();
int idNum = IDS.nextInt();
if(bookList.contains(idNum)){ //problem
bookList.remove("B"+Integer.valueOf(idNum));
}
}
private Scanner setbookID(){
Scanner bookID = new Scanner(System.in);
System.out.println("Enter your book's ID number. ");
return bookID;}
bookList is an ArrayList that read through a text file and come out as a String. A line in my text file looks like this:
B998 ; Aithiopika ; Heliodorus ; 1829
However if the user types in "998" it doesn't remove this line from the ArrayList. Any ideas on how I can go about doing this? Would an iterator somewhat help?
EDIT: This is how I added the books to the ArrayList in the first place.
private ArrayList<Book> readBooks(String filename) {
ArrayList<Book> lines = new ArrayList<>();
readTextFileB(filename, lines);
return lines;
}
private void readTextFileB(String filename, ArrayList<Book> lines)
// Reads the books.txt file.
{
Scanner s = null;
File infile = new File(filename);
try{
FileInputStream fis = new FileInputStream(infile);
s = new Scanner(fis);
} catch (FileNotFoundException e){
e.printStackTrace();
}
while(s.hasNextLine())
lines.add(new Book(s.nextLine()));
}
You have multiple problems with your code. Not clear what you are trying to achieve whether you want to remove the Book object from the list. If so then you need to compare the ID field(using iterator) of the book object assuming your Book class is like below:
class Book {
int id;
Book(int id) {
this.id = id;
}
}
If above case is not the scenario then your list is a list of Book object then how can you pass String as parameter on the remove method bookList.remove("B"+Integer.valueOf(idNum));
you should pass Book object here or index number.
I am using TreeMap structure in Java. The key contains character ':' in it and the values is a list of things. The problem is when i debug the program stops at this line (not working anymore...)
if (!string.isEmpty()) {
**string = jin.nextLine();**
}
I really have no idea what can be the problem. Here below is my code. Data(where I keep date variable) and ListOfBills (where I keep list of objects of the Bill Class) are two other Classes.
public void read(InputStream in) throws ParseException {
Scanner jin = new Scanner(in);
TreeMap<Date, ListOfBills> tree = new TreeMap<Date, ListOfBills>();
ListOfBills obBill = new ListOfBills();
Data data;
String string = jin.nextLine();
while (jin.hasNextLine()) {
if (string.contains(":")) {
data = new Data((string));
string = jin.nextLine();
while (!string.contains(":")) {
String[] parts1 = string.split(" ");
obBill.listOfBills.add(new Bill(Integer.parseInt(parts1[0]), Float.parseFloat(parts1[2]),
parts1[3], Float.parseFloat(parts1[5])));
if (!string.isEmpty()) {
string = jin.nextLine();
}
}
tree.put(data.date1, obBill);
}
}
for (Date date : tree.keySet()) {
System.out.println(date + "\n");
}
jin.close();
}
It keeps blocked because it is waiting an input ...
You need to enter a value in your stdin if your testing from console ...
Hope it helps
If I have a file like this, in which each section is delimited by "**". How can I read each section and put them into different data structures?
AAA
BBB
CCC
**
ccc:cc
ddd:dd
**
xyz;XYZ
abc;ABC
**
Name: John
Email: john#gmail.com
Name: Jack
Email: jack#gmail.com
Name: kate
Email: kake#hotmail.com
**
In a while loop, I can test whether the line equals "**". But since the number of lines in each section is unknown, it seems hard to recognize which section a particular line belongs to?
String line;
while((line=reader.readline()) != null){
if(!line.equals("**"){
// the line has to be parsed and built into different data structures.
For the first section, AAA,BBB,CCC will be added into an ArrayList.
}
}
IMO you should just make the reading method a little bit more clever.
Here is an example (a kind of pseudo code, assuming you have a reader that does an actual IO):
void main() {
List<List<String>> sections = ...
while(reader.hasMoreDataToProcess()) {
sections.add(processSection(reader));
}
}
List<String> processSection(reader) {
List<String> section = ...
do {
String line = reader.readLine();
if(line.equals("**")) { // end of section or whatever delimiter you have
return section;
}
section.addLine(line);
}while(true);
}
Sorry, in a hurry, so pseudocode:
currentSection = []
sections = [currentSection]
for each line:
if line is the separator:
currentSection = []
add currentSection to sections
else:
add line to currentSection
You can use split method of the string class in Java.
String string = "a-b,b-d,c-s,d-w,e-e,f-e";
String[] parts = string.split(",");
String part1 = parts[0]; // a-b
String part2 = parts[1]; // b-d
You should use scanner for this scenario. Here's how you do it. This code is not tested.
File file = new File("somefile.txt");
try {
Scanner sc = new Scanner(file);
sc.useDelimeter("\\*\\*");
while (sc.hasNext()) {
String s = sc.next();
}
sc.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
You can use a Scanner with a FileInputStream to scan the file, using setDelimiter(String) (which accepts a regex pattern) to set your delimiter.
public class Test {
public static void main(String[] args) {
ArrayList<String> firstList = new ArrayList<>();
ArrayList<String> secondList = new ArrayList<>();
try(Scanner scanner = new Scanner(new FileInputStream(new File("yourFile.txt"))).useDelimiter("[*]+")) {
firstList.add(scanner.next());
secondList.add(scanner.next());
// and so on
scanner.close();
} catch(FileNotFoundException e) {
e.printStackTrace();
}
}
}
This will take everything above ** and create a String out of it. If you want, you can then split the String, and grab the data from each line.
String[] split = scanner.next().split("\n");
for(String string : split) {
firstList.add(string);
}
In the first example, the regex [*]+ searches for multiple *. Learn more about regex (regular expressions) to add flexibility.
I have a Vehicle class which contains all information about Vehicle objects including get and set methods. There is also a Showroom class which maintains a list of all of the Vehicle objects, with methods to add/delete and scroll through the list.
In my main (a seperate class called VehicleDriverClass) I am trying to use I/O to write Vehicle data to a file and read in Vehicle data from a file. I can write to a file fine. I am using notepad and so a .txt file to read from. The problem I am having is with how to terminate the end of a line when reading from the file. Here is the constructor for the Vehicle class, so you know the paramaters.
public Vehicle(String man, String mod, String VIN, String dateOfMan, char taxBand, int costOfVehicle)
{
this.manufacturer = man;
this.model = mod;
this.VIN = VIN;
this.dateOfManufacture = dateOfMan;
this.taxBand = taxBand;
this.costOfVehicle = costOfVehicle;
}
This is what I have for the Input method at the moment (without trying to create the oject, just reading from file). The Showroom s being passed to it is for use later, when I create the vehicle object and add it to the showroom.
// code replaced below.
With this implementation when the dataFromFile is outputted to the console it is all on one line, rather than on new lines. Does readline() not terminate the line when '\n' is read in?
Here is how my data is stored in the input file.
Fordtest\n Focus\n frank\n ioCheck\n 09/01/1989\n 23/11/2013\n true\n d\n 1995\n
So for now, how do I get the line to terminate? So that I can then implement the creation of an object from this.
EDIT: I/O is working now. I am now having trouble with the constructor for my Vehicle object needing a the data types char and int for the last two variables. With the current method they are in a string array.
I have removed the code from above and added the new implementation below.public static void
addNewVehicleFromFile(Showroom s)
{
String dataFromFile;
String[] tokens = null;
try
{
File fileReader = new File("AddNewVehicleFromFile.txt");
FileReader fr = new FileReader(fileReader);
BufferedReader br = new BufferedReader(fr);
while ((dataFromFile = br.readLine()) != null)
{
tokens = dataFromFile.split("~");
}
System.out.println(Arrays.toString(tokens));
Vehicle inputVehicle = new Vehicle(tokens[0], tokens[1], tokens[2], tokens[3],
tokens[4], tokens[5]);
/*
Erorr above here with these two. token[4] should be a char and [5] an int
*/
s.addVehicle(inputVehicle);
System.out.println("addNewVehicleFromFile Complete");
}
catch (FileNotFoundException fnfe)
{
System.out.println("File not found exception: " + fnfe.toString());
}
catch (IOException ioe)
{
System.out.println("I/O exception: " + ioe.toString());
}
}
Should I be writing my own toChar and toInt methods to call for these two variables? Or parsing to int or similar.
I think you'll do better if you change your input data format. This is what XML and JSON were born for. If you must persist with your current arrangement, change the delimiter between data elements to something like a tilde '~' instead of \n.
So your input looks like this:
Fordtest~Focus~frank~ioCheck~09/01/1989~23/11/2013~true~d~1995
It's easy to parse now:
String [] tokens = data.split("~");
Write yourself some factory methods to create Vehicles:
public class VehicleFactory {
private static final VehicleFactory INSTANCE= new VehicleFactory();
private VehicleFactory() {}
public static VehicleFactory getInstance() { return INSTANCE; }
public static Vehicle createVehicle(String data) {
Vehicle value = null;
String [] tokens = data.split("~");
if ((tokens != null) && (tokens.length > X)) {
// Map String to int or Date here
value = new Vehicle(tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
}
return value;
}
public static List<Vehicle> createVehicles(File f) {
List<Vehicle> values = new ArrayList<Vehicle>();
// implementation left for you
return values;
}
}
readLine() terminates the line when a character matching the Java syntax of \n is read. In most text editors, this is a newline. To express a newline in a Java string, use \n in the source code, but when creating the file by hand, use:
Fordtest
Focus
frank
ioCheck
09/01/1989
23/11/2013
true
d1995