method not updating original string variable [duplicate] - java

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";

Related

Generic code generation in Java

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.

How to read text file to ArrayList of different object types in java?

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.

How would I add a return statement for this, and how do I call the method?

public class InputFileData {
/**
* #param inputFile a file giving the data for an electronic
* equipment supplier’s product range
* #return an array of product details
* #throws IOException
*/
public static Product [] readProductDataFile(File inputFile) throws IOException {
// CODE GOES HERE (input data from a text file and sort into arraylists)
}
readProductDataFile is used to read a text file, and store it in an array of type Product[]. The code provided cannot be changed, I need a way that works with this code. I've managed to make file reading and sorting into array lists work in a different class, but running it in this way is giving me a couple of problems:
1) I can't call the readProductDataFile method from the Main class, as if it can't find the method (it's definitely in the correct package).
2) I can't figure out how to format the return statement, I've tried lots of different things but I just can't see how to store it as array type Product[].
I haven't provided a lot of specific code so far because I don't want the answer to be handed to me on a platter (this is part of an assignment so I don't want other people to straight up do it for me), but would anyone be able to point me in the right direction to solve this?
To give an idea of how I'm doing at the moment, the following test code worked for me:
ElectronicsEquipmentDemo class:
public class ElectronicsEquipmentDemo {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
Name inputFile = new Name();
inputFile.privateName();
}
}
Name class:
public class Name {
public String privateName() {
try {
FileReader fr = new FileReader("myOutput.txt");
BufferedReader br = new BufferedReader(fr);
String str;
while ((str = br.readLine()) != null) {
char firstLetter = str.charAt(0);
if (firstLetter == 'P') {
String[] list = str.split("/");
Arrays.toString(list);
String fullName = list[1] + " " + list[2] + " " + list[3] + "\n";
System.out.println(fullName);
}
}
br.close();
} catch (IOException e) {
System.out.println("File not found");
}
return null;
}
}
Which reads from a text file and, if the line begins with P, splits into arrays and prints out specified values (although my attempt to add a return statement made it only return the first line, so still struggling there).
This should do it:
public class Name {
public String[] privateName(){
String[] list;
try {
FileReader fr = new FileReader("myOutput.txt");
BufferedReader br = new BufferedReader(fr);
String str;
while ((str = br.readLine()) != null) {
char firstLetter = str.charAt(0);
if (firstLetter == 'P'){
list = str.split("/");
//Arrays.toString(list);
String fullName = list[1] + " " + list[2] + " "+ list[3] + "\n";
System.out.println(fullName);
}
}
br.close();
} catch (IOException e) {
out.println("File not found");
}
return list;
}
}
Edit: fixed scoping issue.
Well, for the first problem, only thing I can notice is that your method is static, so be sure you're calling it correctly.
Also, consider if static is really what you want/need.
For the second problem, return list.toArray(new String[list.size()]) should work.

How to find certain words in a text file, then find numbers in Java?

I have the following text file (answers.txt):
Problem A: 23|47|32|20
Problem B: 40|50|30|45
Problem C: 5|8|11|14
Problem D: 20|23|25|30
What I need is something that will read the problem that I tell it(Problem A, Problem B), then read the numbers after it, which are separated by the lines, and print it out like this:
Answers for Problem A: a.23 b.47 c.32 d.20
Does anyone know how this can be done? I've been stuck on it for a while.
Read the lines one by one, split the lines at " " first. The you will get an array with three parts "Problem", "A:" and "23|47|32|20". Then split the third part at "|" so you will get a second array with four parts "23,"47","32","20".
Combine all to get the output you want.
If you want info on how to read lines from a file, or spilt strings then there are billions of tutorials online on how to do that so I wont go into detail on how its done. IM sure you can find them.
Check out this code!
It assumes that you have such file format:
Problem A:
23|7|32|20
Problem B:
40|50|30|45
Problem C:
5|8|11|14
Problem D:
20|23|25|30
because you wrote "numbers after it, which are separated by the lines"
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) throws FileNotFoundException {
Scanner sc = new Scanner(new File("answers.txt"));
List<String> dataList = new ArrayList<String>();
while(sc.hasNextLine()){
dataList.add(sc.nextLine());
}
System.out.println(dataList);
Map<String,String> map = new HashMap<String,String>();
for(int i=0;i<dataList.size();i=i+2){
map.put(dataList.get(i),dataList.get(i+1));
}
for(Entry<String,String> en:map.entrySet()){
System.out.println(en.getKey()+" : "+en.getValue());
}
String problemC = map.get("Problem C:");
String splitted[] = problemC.split("\\|");
System.out.println("Get me problem C: "+String.format("a:%s, b:%s, c:%s, d:%s",splitted[0],splitted[1],splitted[2],splitted[3]));
}
}
Hope this helps!
public static void main(String args[])
{
BufferedReader br = new BufferedReader(new FileReader(new File("answers.txt")));
String lineRead = null;
String problem = "Problem A";//Get this from user Input
List<String> numberData = new ArrayList<String>();
while((lineRead = br.readLine())!=null)
{
if(lineRead.contains(problem))
{
StringTokenizer st = new StringTokenizer(lineRead,":");
String problemPart = st.nextToken();
String numbersPart = st.nextToken();
st = new StringTokenizer(lineRead,"|");
while(st.hasMoreTokens())
{
String number = st.nextToken();
System.out.println("Number is: " + number);
numberData.add(number);
}
break;
}
}
System.out.println("Answers for " + problem + " : " + numberData );
}
Read the lines one by one, split the lines with :. The you will get an array with two parts "Problem A:" and "23|47|32|20". Then split the second part at "|" so you will get a second array with four parts "23,"47","32","20".
Combining all this you will get the output you want.
Cheers!
Use java.util.Scanner and you can filter the integers in the file.
Scanner s = new Scanner (new File ("answers.txt")).useDelimiter("\\s+");
while (s.hasNext()) {
if (s.hasNextInt()) { // check if next token is integer
System.out.print(s.nextInt());
} else {
s.next(); // else read the next token
}
}
Do you know how to read line by line ? If not , chect it How to read a large text file line by line in java?
To sub your string data there have many ways to do. You can sub as you wish. Here for my code..
String data = yourReader.readLine();
String problem = data.substring("Problem".length(), data.indexOf(":"));
System.err.println("Problem is " + problem);
data = data.substring(data.indexOf(":") + 2, data.length());
String[] temp = data.split("\\|");
for (String result : temp) {
System.out.println(result);
}
Assuming there are always four possible answers as in your Example:
// read complete file in fileAsString
String regex = "^(Problem \\w+): (\\d+)\\|(\\d+)\\|(\\d+)\\|(\\d+)$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(fileAsString);
//and so on, read all the Problems using matcher.find() and matcher.group(int) to get the parts
// put in a Map maybe?
// output the one you want...
I might suggest creating a simple data type for the purpose of organization:
public class ProblemAnswer {
private final String problem;
private final String[] answers;
public ProblemAnswer(String problem, String[] answers) {
this.problem = problem;
this.answers = new String[answers.length];
for (int i = 0; i < answers.length; i++) {
this.answers[i] = answers[i];
}
}
public String getProblem() {
return this.problem;
}
public String[] getAnswers() {
return this.answers;
}
public String getA() {
return this.answers[0];
}
public String getB() {
return this.answers[1];
}
public String getC() {
return this.answers[2];
}
public String getD() {
return this.answers[3];
}
}
Then the reading from the text file would look something like this:
public void read() {
Scanner s = new Scanner("answers.txt");
ArrayList<String> lines = new ArrayList<String>();
while (s.hasNext()) {
lines.add(s.nextLine());//first separate by line
}
ProblemAnswer[] answerKey = new ProblemAnswer[lines.size()];
for (int i = 0; i < lines.size(); i++) {
String[] divide = lines.get(i).split(": "); //0 is the problem name, 1 is the list
//of answers
String[] answers = divide[1].split("|"); //an array of the answers to a given
//question
answerKey[i] = new ProblemAnswer(divide[0], answers); //add a new ProblemAnswer
//object to the key
}
}
Now that leaves you with an answer key with ProblemAnswer objects which is easily checked
with a simple .equals() comparison on the getProblem() method, and whatever index is matched, you have all the answers neatly arranged right within that same object.

ArrayList confusion

The code below is my attempt to read from a file of strings, read through each line until a ':' is found then store + print everything after that. however The print function prints out everything that I read in from the file. Can someone spot where I'm going wrong? thanks
edit: every line is in this format "Some text here:More text here"
public void openFile() {
try {
scanner = new BufferedReader(new FileReader("calendar.ics"));
} catch (Exception e) {
System.out.println("Could not open file");
}
}
public void readFile() {
ArrayList<String> vals = new ArrayList<String>();
String test;
try {
while ((line = scanner.readLine()) != null)
{
int indexOfComma = line.indexOf("\\:"); // returns firstIndexOf ':'
test = line.substring(indexOfComma+1); // test to be everything after ':'
vals.add(test); // add values to vals
}
} catch(Exception ex){ }
for(int i=0; i<vals.size(); i++){
System.out.println(vals.get(i));
}
}
You don't need to escape your colon.
line.indexOf("\\:");
Change the above line to: -
line.indexOf(":");
Because, that will search for \\:, and if not found return the value -1.
test = line.substring(indexOfComma+1);
So, if your indexComma is -1, which will certainly be, if your string does not contain - \\:, then your above line becomes: -
line.substring(0); // same as whole string
As a suggestion, you should have abstract type as the type of reference when declaring your list. So, you should use List instead of ArrayList on the LHS of the List declaration: -
List<String> vals = new ArrayList<String>();

Categories

Resources