I am learning Java (and Swing), and am developing a small code generator that generates Java classes after asking you some information.
The first window asks the class name (mandatory), mother-class name, and asks if you wish to generate a default constructor. Once you press Generate, a JDialog opens up with the generated class.
But my issue comes to the generic side of my code generation.
Once the information about the class is saved, I call my generateCode function that looks like such:
private String generateCode(Information info) {
String code = "";
// info contains all the information inputed by the user
if (info.motherClass.equals("") && info.generateDefaultConstructor == false) {
code = "public class " + info.name + "{\n\n}";
} else {
}
return code;
}
As you can see, I only handle the case where only the class name is given.
How should I code it in order to handle other options? Should it be with a block of conditions handling everything one by one? I truly want to make my code as generic as possible in order to add more features later on.
Thank you.
First of all I would recommend making all the none static fields of Information private or protected add getters and setters.
Then add a few methods that can check and / or manipulate Strings like:
public static String removeSpaces(String input) {
if (input == null) {
return "";
}
String enter = (char) (13) + (char) (10) + "";
String tab = (char) (9) + "";
String space = (char) (32) + "";
String empty = "";
return input.replace(enter, empty).replace(tab, empty).replace(space, empty);
}
public static String newLine(){
return (char) (13) + (char) (10) + "";
}
public static String tab(){
return (char) (9) + "";
}
Then split the generateCode method into something like:
private String generateCode(Information info) {
StringBuilder code = new StringBuilder();
code.append(getClassCode(info.getMotherClass()));
code.append(newLine());
code.append(tab());
code.append(getConstructor(info));
return code.toString();
}
public static String getClassCode(String className){
StringBuilder code = new StringBuilder();
code.append("public class ");
if (!removeSpaces(className).isEmpty()){
code.append(className);
} else {
code.append(Information.getDefaultClass());//have a default static name for a class like "Application"
}
code.append("{");
code.append(newLine());
return code.toString();
}
public static String getConstructor(Information info){
StringBuilder code = new StringBuilder();
if(!info.isGenerateDefaultConstructor()) {
code.append("public ");
code.append(info.getMotherClass());
code.append("(){");
code.append(newLine());
code.append(tab());
code.append(info.getConstructorContent());//what will be in the constructor
code.append(newLine());
code.append(tab());
code.append("}");
}
code.append(newLine());
return code.toString();
}
And then you can keep going by adding bits and pieces here and there.
You could make info as a string list and iterate through it skipping code generation where the list is an empty string.
Related
I have been tasked with creating a game called Taboo. It consists of a main word and 3 banned words. The aim of the game is for the words to display on the screen and the user then has to describe the main word without using the word itself or the banned words.
I have so far been able to read in the data that I have stored in a CSV and have it so that when I choose to output BannedWords, it does so. The problem now, is that when it outputs either MainWord or BannedWord1, etc... it outputs the data for each record in the CSV.
Below is the data from my CSV (it is just a test with few records so that when it works I can introduce the rest).
Tree,Brown,Green,Nature
Lake,Blue,Water,Wet
Apple,Green,Fruit,Healthy
If I chose to output MainWord, which is the first word, it outputs like this:
Tree
Lake
Apple
I need to somehow store the data being read in from the CSV individually in a collection so that when I need to use them, they output properly and they in a such a way that I can display them later on in a GUI JLabel.
It might also be useful to note that I am using NetBeans so I am able to use any of the built in functions as well.
public class Card
{
private String sMainWord;
private String sBannedWord1;
private String sBannedWord2;
private String sBannedWord3;
public Card(String sMW, String sBW1, String sBW2,String sBW3)
{
sMainWord = sMW;
sBannedWord1 = sBW1;
sBannedWord2 = sBW2;
sBannedWord3 = sBW3;
}
public void setsMainWord(String sMW)
{
sMainWord = sMW;
}
public String getsMainWord()
{
return sMainWord;
}
public void setsBannedWord1(String sBW1)
{
sBannedWord1 = sBW1;
}
public String getsBannedWord1()
{
return sBannedWord1;
}
public void setsBannedWord2(String sBW2)
{
sBannedWord2 = sBW2;
}
public String getsBannedWord2()
{
return sBannedWord2;
}
public void setsBannedWord3(String sBW3)
{
sBannedWord3 = sBW3;
}
public String getsBannedWord3()
{
return sBannedWord3;
}
public static void main(String[] args) throws FileNotFoundException
{
String fileNameDefined = "/Users/student/NetBeansProjects/TabooGameComplete/CSData.csv";
File file = new File(fileNameDefined);
try
{
Scanner inputStream = new Scanner(file);
while(inputStream.hasNext() != false)
{
String TabooCardWords = inputStream.nextLine();
String[] information = TabooCardWords.split(",");
String MainWord = information[0];
String BannedWord1 = information[1];
String BannedWord2 = information[2];
String BannedWord3 = information[3];
Card TBC = new Card (MainWord, BannedWord1, BannedWord2, BannedWord3);
System.out.println("*" + BannedWord1 + "*");
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
You are executing the output statement in the loop that generates your Cards so that everytime a card is created, you are outputting its BannedWord1. As you are creating them all, one after another, they will all output, one after another.
i.e.
//For each line in file
while(inputStream.hasNext() != false)
{
//Create Card
//Output BannedWord1 used to create Card
}
If you want to output one element of one Card, you will need to keep the Card objects you create to be used outside the loop:-
Card[] cards = new Cards[3];
int i=0;
//For each line in file
while(inputStream.hasNext() != false)
{
//Create Card
cards[i++] = newlyCreatedCardObject; //Store card object for later
//Output BannedWord1 used to create Card
}
//Output BannedWord1 from the Card created from the second line
System.out.println(cards[1].getsBannedWord1());
Additional Point
By convention, java variables begin with lowercase letters and classes with uppercase, so this can be confusing
String TabooCardWords; //Should really be 'tabooCardWords'
...
String MainWord = information[0]; //-> 'mainWord'
String BannedWord1 = information[1]; //-> 'bannedWord1'
String BannedWord2 = information[2]; //-> 'bannedWord2'
String BannedWord3 = information[3]; //-> 'bannedWord3'
I'm a beginner to programming and I need some help trying to read from a text file into an ArrayList that contains objects of different types. I've created a program that controls an inventory of videos which I currently have hard coded into an ArrayList in the program but I would like to change this so every time the program runs, the program reads from the text file which contains the inventory and converts that into an ArrayList instead of reading from the ArrayList that is already in the program. I've already added a function that writes the inventory to the text file once the program has quit but I can't seem to get it to read from the text file.
The problem I'm having is that my ArrayList (videos) contains (String, String, Character, String). I don't know how to change the code I have so that scanner splits each line in the text file into the appropriate chunks (for title, type, availability and return date) and then inserts each individual chunk into the appropriate place in the ArrayList. I hope that made sense.
I've tried creating a CSV and using the split() function but I couldn't figure out how to use that to insert into an ArrayList as I end up with four strings in a line rather than (String, String, Character, String). I've even tried changing my current ArrayList so that every element is a string but I still wasn't sure how to make that work.
Any help would be really appreciated. Let me know if you need further information.
EDIT: To sum up, my question is: if I have a text file as seen below, how do I split that into 4 lines and then each line into 4 strings (or 3 strings and 1 character) and insert each string into an ArrayList so that I end up with an ArrayList of four InventoryRow's like this:
("Casablanca", "Old", 'Y', null)
Inventory Row Class:
class InventoryRow {
private String name;
private String type;
private Character availability;
private String returndate;
public InventoryRow(String name, String type, Character availability,
String returndate) {
this.name = name;
this.type = type;
this.availability = availability;
this.returndate = returndate;
}
public String getReturndate() {
return returndate;
}
public void setReturndate(String returndate) {
this.returndate = returndate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Character getAvailability() {
return availability;
}
public void setAvailability(Character availability) {
this.availability = availability;
}
public String toString() {
return name + " " + type + " " + availability + " " + returndate;
}
}
Main method (including my current code which doesn't work):
public class InventorySort {
public static void main(String[] args) throws ParseException, JSONException, FileNotFoundException {
/*
* List<InventoryRow> videos = new ArrayList<InventoryRow>();
*
* videos.add(new InventoryRow("Casablanca", "Old", 'Y', null));
* videos.add(new InventoryRow("Jurassic Park", "Regular", 'N',
* "31/07/2015")); videos.add(new InventoryRow("2012", "Regular", 'Y',
* null)); videos.add(new InventoryRow("Ant-Man", "New", 'Y', null));
*/
// Get's today's date and adds three to it = return date
Calendar cal = Calendar.getInstance();
SimpleDateFormat dateReturn = new SimpleDateFormat("dd/MM/yyyy", Locale.UK);
cal.add(Calendar.DATE, 3);
Scanner input = new Scanner(System.in);
boolean run = true;
while (run) {
// Read from text file
Scanner s = new Scanner(new File("videos.txt"));
List<InventoryRow> videos = new ArrayList<InventoryRow>();
while (s.hasNext()) {
videos.add(new InventoryRow(s.next(), null, null, null));
}
s.close();
// Output the prompt
System.out.println("Do you want to list, rent, check, return, add, delete or quit?");
// Wait for the user to enter a line of text
String line = input.nextLine();
// List, rent and check functions
// List function
if (line.equals("list")) {
// Sort videos alphabetically
list(videos);
// Rent function
} else if (line.equals("rent")) {
rent(videos, cal, dateReturn, input);
// Check function
} else if (line.equals("check")) {
check(videos, input);
// If anything else is entered
} else if (line.equals("return")) {
returnVideo(videos, input);
} else if (line.equals("add")) {
add(videos, input);
} else if (line.equals("delete")) {
delete(videos, input);
} else if (line.equals("quit")) {
run = false;
writeFile(videos);
} else {
other();
}
}
}
The code I have for writing to the text file:
private static void writeFile(List<InventoryRow> videos) {
String fileName = "videos.txt";
try {
FileWriter fileWriter = new FileWriter(fileName);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
for (InventoryRow ir : videos) {
bufferedWriter.write(ir.toString() + System.getProperty("line.separator"));
}
bufferedWriter.close();
} catch (IOException ex) {
System.out.println("Error writing to file '" + fileName + "'");
}
}
My text file looks like this:
2012 Regular Y null
Ant-Man New Y null
Casablanca Old Y null
Jurassic Park Regular N 31/07/2015
You probably need something like this:
List<InventoryRow> videos = new ArrayList<InventoryRow>();
while (s.hasNextLine()) {
String[] split = s.nextLine().split(" ");
// TODO: make sure the split has correct format
// x.charAt(0) returns the first char of the string "x"
videos.add(new InventoryRow(split[0], split[1], split[2].charAt(0), split[3]));
}
It looks like you are trying to do basic serialization & deserialization.
I will focus on your while(run) loop so that you are able to populate the ArrayList from the file. Your InventoryRow class is good enough and the array list is correctly parameterized.
//This creates an object to read the file
Scanner s = new Scanner(new File("videos.txt"));
while (s.hasNext()) {
//This is where the problem is:
videos.add(new InventoryRow(s.next(), null, null, null));
}
s.next() will return a String like:
"name;type;a;date" you need to split this on your separator character by doing something like:
String line = s.next();
String[] fields = line.split(","); //use your choice of separator here & check how to use the split method.
Create a InventoryRow object with the obtained fields and then add that to the ArrayList in your while loop. Unless you specifically want the availability to be a character you could leave it as a string.
This question already has answers here:
Immutability of Strings in Java
(26 answers)
Closed 8 years ago.
I'm having problem with this code that i wrote to convert the string....the string is not being updated throughout the code...
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class PigLatin {
private static String str = "pig";
private char[] vowels = { 'a', 'e', 'i', 'o', 'u' };
private Character firstChar, secondChar;
public void inputString(String str) {
try {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader input = new BufferedReader(isr);
str = input.readLine();
} catch (Exception e) {
// TODO: handle exception
System.out.println("unable to input String");
e.printStackTrace();
}
firstChar = str.charAt(0);
secondChar = str.charAt(1);
System.out.println(firstChar);
System.out.println(secondChar);
}
public static void main(String[] args) {
PigLatin pl = new PigLatin();
System.out.println("Enter an english word to convert to PigLatin");
pl.inputString(str);
System.out.println(str);
pl.convert(str);
}
public void convert(String lowerCase) {
// TODO Auto-generated method stub
System.out.println("Original string:" + str);
if (isVowel())
str.concat("yay");
else {
String suffix = firstChar.toString() + "ay";
// String suffix = String.valueOf(str.charAt(0))+"ay";
str = str.substring(1) + suffix;
}
System.out.println("PigLatin:" + str);
}
public boolean isVowel() {
// TODO Auto-generated method stub
for (char ch : vowels) {
if (firstChar.equals(ch)) {
if (firstChar.equals('v') && secondChar.equals('q'))
return false;
return true;
}
if (firstChar.equals('y') && !secondChar.equals(ch))
return true;
}
return false;
}
}
The output is as follows:
Enter an english word to convert to PigLatin
kite
k "first character"
i "second character"
pig
Original string:pig
PigLatin:igkay
Why is the string not being updated even if I'm giving the input in the command line evn though the first and second characters are correctly read from the string that I input..Please help....
if (isVowel())
str.concat("yay");
Strings are immutable in java, so you have to update str:
if (isVowel())
str = str.concat("yay");
If you don't want to reassign str everytime, you can declare str as StringBuilder and update it via the append method:
private static StringBuilder str = new StringBuilder("pig");
//other code...
public void convert(String lowerCase) {
//other code...
if (isVowel())
str.append("yay"); // this will modify the current object, as it is
// a StringBuilder and not a string
//other code...
}
str.concat("yay")
should be
str = str.concat("yay") or shorthand str += "yay"
as Strings are immutable in Java. This means that their value can't be changed.
pl.inputString(str);
The above statement doesnt change pl.str, hence pl.str = pig
pl.convert(str);
executes below code (for 'kite' as input)
String suffix = firstChar.toString() + "ay"; // result = kay
str = str.substring(1) + suffix; // str=pig, hence ig + kay = igkay
The above code doesnt reassign pl.str in inputString()
UPDATE: (same as comments)
Either static or instance variable doesnt matter in your code because in the method inputString(String str), you are assigning the local variable passed in argument and not the static variable str.
Since Java is pass by value, pl.inputString(str) will result in a reference copy. You are reassigning the local reference in that method. That means local-reference str and PigLatin.str references are different and referring to different objects. To update PigLatin.str, It is not possible to change the string object value since it is immutable. Use a StringBuilder instead and assign the same in inputString(str)
if (isVowel())
str.concat("yay");
You can change this to..
if (isVowel())
str=str+"yay";
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.
I'm working on a project which reads from csv file, then uses StringTokenizer to chop up the elements and place them into JLabels. So far I have that part down. I have buttons to scroll through each position, but I'm not sure about how I can type in the fields and add on to the array ?
This is the main part of my program so far
// program reads in csvfile.
private void loadCarList() {
try{
BufferedReader CSVFile = new BufferedReader(new FileReader("car.txt"));
String dataRow = CSVFile.readLine();
while(dataRow != null){
carList.add(dataRow);
dataRow = CSVFile.readLine();
}
}catch(Exception e){
System.out.println("Exception while reading csv file: " + e);
}
}
}
//this will click cycle through the elements in the Jlabels.
private void loadNextElement(){
try {
StringTokenizer st = new StringTokenizer((String)carList.get(position), ",");
while(st.hasMoreTokens() && position <= carList.size() -1) {
position ++;
String CarID = st.nextToken();
String DealerShipID = st.nextToken();
String ColorID = st.nextToken();
String Year = st.nextToken();
String Price = st.nextToken();
String Quantity = st.nextToken();
tCarID.setText(CarID);
tDealerShip.setText(DealerShipID);
tColor.setText(ColorID);
tYear.setText(Year);
tPrice.setText(Price);
tQuantity.setText(Quantity);
}
} catch(Exception e){
JOptionPane.showMessageDialog(null, "youve reached the end of the list");
}
}
Is there a simpler way where I can just type in the jlabels I have laid out and add onto the array?
I'm kind of lost at this point, and am unsure how to go further with this.
Your problem appears to be that you're trying to do too much inside one class. It's possible to do, but not very well organized.
Create a separate class for holding a single Car record. It should be simple "bean" or "POJO" class typically composed of some private properties and public getters and setters (aka accessors and mutators). Your List of Cars will be composed of these objects.
public class Car {
private String carID;
...
private Integer quantity;
public getCarID() {
return this.carID;
}
...
public setQuantity(Integer quantity) {
this.quantity=quantity;
}
}
Define your list of Cars as a property of your current class, and each time you add a Car to your list, construct it from your Car class.
Car car=new Car();
car.setCarID(st.nextToken());
...
car.setQuantity(Integer.valueOf(st.nextToken()));
this.carList.add(car);