I need some help with understanding why my code won't let me put in a filename for it to read, which it then processes. I will paste the code below. I also wonder about one thing: I need the code to check an entire text-file, check an array whether the word is already in it, and then add +1 to a counter-array I got. I haven't been able to test it, so I hope it works! But it would be awesome if someone could just take a quick glance and see if there is anything screaming error in their faces. :)
Code:
import java.util.*;
import java.io.*;
class Oblig3A{
public static void main(String[]args){
//The problem is here somewhere I believe:
OrdAnalyse oa = new OrdAnalyse();
String filArgs=args[0];
oa.analyseMetode(filArgs);
}
}
class OrdAnalyse{
void analyseMetode(String filArgs){
//Begynner med aa opprette alle variabler som trengs, disse deklareres rett under. De ligger her oppe bare for at jeg skal ha oversikten over de.
Scanner input, innfil;
String[] ord, fortelling;
int[] antall;
int antUnikeOrd;
PrintWriter utfil;
//Variables..
input=new Scanner(System.in);
ord=new String[5000];
antall=new int[5000];
antUnikeOrd=0;
try{
innfil=new Scanner(filArgs);
//Naa skal jeg dele opp prosessen litt for aa faa inn funksjonaliteten for aa for eksempel sette alle ord til lowercase.
//Here it says that as long as the file is longer, it will continue the while-loop, and for every line it will set
the words to all lowercase, split the line on blanks, and then fill it into an array called fortelling.
It will then run two nested for-loops which will make it check the entire ord-array for matches for every word in the fortelling-array,
and if it finds a match it will increase the count-array antall +1 in the index where the word is found.
Does it not find anything, it will save the word to the (hopefully) last index in the array, increase that index in antall with 1, and then increase the uniquewordcounter (antUnikeOrd) with 1.
I hope this part will work out, but I must first be able to get the file...
while(innfil.hasNext()){
fortelling=innfil.nextLine().toLowerCase().split(" ");
for(int i=0; i<fortelling.length; i++){
for(int j=0; j<5000; j++){
if(fortelling[i]==ord[j]){
antall[j]+=1;
}else if(!fortelling[i].contains(ord[j])){
ord[j]=fortelling[i];
antall[j]+=1;
antUnikeOrd+=1;
}
System.out.print(fortelling[i]);
System.out.print(fortelling.length);
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
It seems completely unable to open the file... And I don't know why. This will eventually write out all info to another file it creates, but I havent written this part yet.
3 issues
Use a File argument in the constructor of Scanner so that you're not using a String source
innfil = new Scanner(new File(filArgs));
Use .equals to compare String content. The == operator is used to Object references.
if (fortelling[i].equals(ord[j])) {
Lastly this statement
} else if (!fortelling[i].contains(ord[j])) {
will throw an NPE as the ord array is never populated before being checked. I suggest using a Map<String, Integer> rather than an array to store the occurrences of words.
Related
Task is to read an article of text from outside file and put each word (no signs) into and Array List as a separate String.
Although I´m sure my path is correct and readable(I can for example perform character count), no matter what I do my Array List of words from that article comes out as empty. I may be struggling with a way how to separate words from each other and other signs. Also with storing the result of reading.
I´ve been googling for the last 2 hours and reading similar answers here but no success. So decided for the first time to ask a question.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import org.w3c.dom.Text;
public class PlaceForErrors {
public static void main(String[] args) {
Scanner scan = null;
try {
scan = new Scanner(new File("\\Users\\marga\\Desktop\\objekt program\\oo2021\\w05_kontrolltoo1\\textHere.txt")).useDelimiter(" \\$ |[\\r\\n]+");
String token1 = "";
ArrayList<String> text = new ArrayList<String>();
while (scan.hasNext()) {
token1 = scan.next();
text.add(token1);
}
String[] textArray = text.toArray(new String[0]);
for(String element : textArray){
System.out.println(element);
}
//Controlling if the ArrayList is empty and it is
boolean tellme = text.isEmpty();
System.out.println(tellme);
} catch (FileNotFoundException exception) {
System.out.println(exception);
}
finally{
scan.close();
}
}
}
String[] textArray = text.toArray(new String[0]);
This line is your problem. You're trying to allocate the ArrayList into a String array of size 0, resulting in it appearing empty.
I would modify the array declaration to initialize using the ArrayList size, like so:
String[] textArray = text.toArray(new String[text.size()]);
Then you can see if your token delimiter works.
Quick recap of your steps
Your program does a lot. I counted 9 steps:
opens a (text) file as (text) input-stream to read from
create a scanner for tokens from this input-stream using a regular-expression as delimiter (= tokenizer)
scan for and iterate over each subsequent token (if any found) using a while-loop
each of this iteration adds the token to a list
if no more tokens, then iteration ends (or never started!): converts the list to array
loop over each array element using a for-each-loop and print it
check if originally collected list is empty and print true or false
catch the exception if file was not found and print the it
finally close any opened resources: the file that was read from
Now let's start to look for the step where something potentially could go wrong: the places for errors 😏️
Analysis: What can go wrong?
Look at the listed steps above and think of each from a what-could-go-wrong perspective, a quick check list (not correlated to the step-numbers above!):
Can your text-file be found, does it exist and is readable? Yes, otherwise any IOException like FileNotFoundException would have been thrown and printed.
Is the opened file empty with a size of 0 bytes? You can check using:
File textFile = new File("\\Users\\marga\\Desktop\\objekt program\\oo2021\\w05_kontrolltoo1\\textHere.txt");
System.out.println( "File size: " + textFile.length() );
// before passing the extracted file-variable to scanner
scan = new Scanner( textFile ).useDelimiter(" \\$ |[\\r\\n]+");
Does the delimiter/regex properly split/tokenize an example input string? Try:
// Just a separate test: same delimiter, with test-input
String delimiterRegex = " \\$ |[\\r\\n]+";
String testInput = " $ Hello\r\nWorld !\n\nBye.";
// so we create a new scanner
Scanner testScanner = new Scanner( testInput ).useDelimiter(delimiterRegex);
int tokenCount = 0;
while( testScanner.hasNext() ) {
tokenCount++;
System.out.println("Token " + tokenCount + ": " + testScanner.next() );
}
testScanner.close();
Should print 3 tokens (Hello, World !, Bye.) on 3 lines in console. The special sequence $ (space-dollar-space), any \n or \r (newline or carriage-return) are omitted and have split the tokens.
We should check the list directly after the while-loop:
// Not only checking if the ArrayList is empty, but its size (is 0 if empty)
System.out.println("Scanned tokens in list: " + text.size());
If it is empty, then we neither need to fill the array, nor loop to print will start (because nothing to loop).
Hope these explanations help you to perform the analysis (debugging/testing) yourself.
Let me know if it helped you to catch the issue.
Takeaway: Divide and conquer!
Why did I count the steps, above? Because all are potential places for errors.
In developer jargon we also say this main method of class PlaceForErrors has many responsibilities: counted 9.
And there is a golden principle called Single Responsibility Principle (SRP).
Put simply: It is always good to split a large problem or program (here: your large main method) into smaller pieces. These smaller pieces are easier to work with (mentally), easier to test, easier to debug if errors or unexpected happens. Divide & conquer!
If it works, start improving
You can split up this long method doing 9 steps into smaller methods.
Benefit: each method can be tested in isolation, like the testScanner.
If your program finally works as expected and your manual test went green.
Then you should post the working code to the sister-site: CodeReview.
Be curious and ask again, e.g. how to split up the methods, how to make testable, etc.
You'll get lot's of experienced advise on how to improve it even more.
Thank you for your input everyone!
Regarding the code, I went and checked everything step by step and on the way learned more about delimiters and scanner. I fixed my delimiter and everything worked just fine now.
Beside the fact that I made a newbie mistake and didn´t show the full code, as I though it would take away the attention from the main problem. I had two conflicting scanners in my main function(one I showed you and the other one was scanning again and counting letters A). And they both worked great separately(when one or the other is commented out), but refused to work together. So I found a way to combine them and use scanner only once. I will share my full code for reference now.
I learned my mistake, and will provide the my full code always in the future.
If someone is curious the full task was the following:
Read the text from a separate file using scanner and store it in an Array List.
Count how many letters "A" (small or big) there were and how big of % they made out of all the letters in the text.
Count how many words had one letter A, two letters A in them, etc.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class Trying {
public static void main(String[] args) {
Scanner scan = null;
try {
//SCANNING FILE AND CREATING AN ARRAYLIST
scan = new Scanner(new File("\\Users\\marga\\Desktop\\objekt program\\oo2021\\w05_kontrolltoo1\\textHere.txt")).useDelimiter("[.,:;()?!\"\\s]+");
int aCount = 0;
int letterCount =0;
String token1 = "";
int wordWithAtLeastOneA = 0;
int wordWithA = 0;
int word1A = 0;
int word2A = 0;
int word3A = 0;
int word4OrMoreA = 0;
ArrayList<String> text = new ArrayList<String>();
// SCANNING EVERY WORD INTO AN ARRAY LIST
while(scan.hasNext()){
token1 = scan.next();
text.add(token1);
}
System.out.println("Amount of words in the scanned list is : " + text.size());
//COUNTING HOW MANY LETTERS 'A' TEXT HAS
for(String element : text){
for (int i=0;i<=element.length()-1;i++){
if (element.charAt(i) == 'A' || element.charAt(i) == 'a') {
aCount++;
}
}
}
System.out.println("There are "+aCount+" letters 'A'. ");
//HOW MANY LETTERS IN TOTAL TEXT HAS
for(String element : text){
for (int i=0;i<=element.length()-1;i++){
letterCount++;
}
}
//COUNTING HOW MANY WORDS HAVE 'A' LETTER IN THEM
for(String element : text){
for (int i=0;i<=element.length()-1;i++){
if (element.charAt(i) == 'A' || element.charAt(i) == 'a') {
wordWithAtLeastOneA++;;
break;
}
}
}
System.out.println("There are "+wordWithAtLeastOneA+" words that have at least one letter 'A' in them.");
System.out.println();
//COUNTING NUMBER OF WORDS THAT HAVE 1/2/3 or more 'A' LETTER IN THEM
for(String element : text){
wordWithA = 0;
for (int i=0;i<=element.length()-1;i++){
if (element.charAt(i) == 'A' || element.charAt(i) == 'a') {
wordWithA++;
if(wordWithA == 1){
word1A++;
}else if (wordWithA == 2){
word2A++;
}else if (wordWithA == 3){
word3A++;
}else if (wordWithA >= 4){
word4OrMoreA++;
}
}
}
}
System.out.println("There were "+ word1A+ " words, that had one letter 'A' in them." );
System.out.println("There were "+ word2A+ " words, that had two letters 'A' in them." );
System.out.println("There were "+ word3A+ " words, that had three letters 'A' in them." );
System.out.println("There were "+ word4OrMoreA+ " words, that had 4 or more letters 'A' in them." );
//COUNTING HOW MANY LETTERS THERE ARE IN TOTAL, COMPARE TO NUMBER OF "A" LETTERS
int percentOfA = aCount*100/letterCount;
System.out.println();
System.out.println("The entire number of letters is "+ letterCount+" and letter 'A' makes " + percentOfA+ "% out of them or " +aCount+ " letters.");
// for(String element : textArray){
// System.out.println(element);
// }
} catch (FileNotFoundException exception) {
System.out.println(exception);
}
finally{
scan.close();
}
}
}
And the text is:
Computer programming is an enormously flexible tool that you can use to do amazing things that are otherwise either manual and laborsome or are just impossible.
If you are using a smartphone, a chat app or if you are unlocking your car with the push of a button,
then you must know that all these things are using some kind of programming.
You are already immersed in the programs of different types.
In fact, software is running your life. What if you learn and start running these programs according to your will?
And the output is:
There are 35 words that have at least one letter 'A' in them.
There were 35 words, that had one letter 'A' in them.
There were 3 words, that had two letters 'A' in them.
There were 0 words, that had three letters 'A' in them.
There were 0 words, that had 4 or more letters 'A' in them.
The entire number of letters is 416 and letter 'A' makes 9% out of them or 38 letters.
Trying to populate an array with input through the scanner .nextLine() function. The problem specifications give a sample input as follows:
3 5 4
abc
bca
dac
dbc
cba
(ab)(bc)(ca)
abc
(abc)(abc)(abc)
(zyx)bc
Just as I copied and pasted that whole chunk into this box, I'd like to do the same with my code, but when I try, the code only reads in the last line. I want each line to be read in and stored in it's own index in the array, NOT a multi-line string in one index or only the last line being read in and stored (which is what is happening now).
This is my method for initializing the array, which I've tested and it works when I feed in the input line by line, but that's just really annoying to be honest.
public static void initialize_array(String [] arr)
{
Scanner kbreader = new Scanner(System.in);
for (int i = 0 ; i < arr.length ; i++)
{
arr[i] = kbreader.nextLine();
System.out.println("this is just loading in: " + arr[i]);
}
}
When I run the program, (it also takes in 3 integers at the top and I print them just to test them, but that's not important) it only registers the last line.
A screenshot:
enter image description here
I think I've done something like this in C, but that might be because I used scanf() and C is relatively low level so it literally had to walk through the entire chunk.
It might not be possible, but I figured I'd ask to see.
Also, just so you know this is for practice, not an actual graded assignment or anything important, so don't hold anything back. :)
If you know the exact length of the array, then this would work:
Scanner scn = new Scanner(System.in);
scn.useDeliminator("\n");
for (int i = 0 ; i < arr.length ; i++)
{
arr[i] = scn.next();
System.out.println("this is just loading in: " + arr[i]);
}
The key here is the useDeliminator method call. The next methods reads from the stream until it reaches the deliminator pattern. In this case, it is \n, a new line. Please use the new line character of your OS.
This may be off point, but have you tried just using array.add(scanner.next()) and looping until scanner.hasNext() returns false?
So I have an assignment from an online course to create a program that can scan a massive document. What this document contains is hundreds of pairs of letters that include GB GG BB BG and each set of two letters has its own line. What I have to do is figure out how many lines there are and then figure out how many of the different sets of two letters there are. I've attempted the code but I am currently stuck. The code that I have compiles but when I run it in BlueJ an output window doesn't even pop up. This is what I have so far:
/**
* This program sorts through a file and
* determines the composition of various families.
* Timothy Pierce
* 1/2/2016
*/
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
public class Family
{
public static void main(String [ ] args) throws IOException
{
boolean isTwoBoys;
boolean isTwoGirls;
boolean isBoyGirl;
int twoBoysCounter = 1;
int twoGirlsCounter = 1;
int boyGirlCounter = 1;
String line = "";
Scanner inFile = new Scanner(new File ("C:\\Users\\TEM\\Desktop\\Projects\\Family\\Document\\test1.txt"));
while (inFile.hasNextLine ())
{
isTwoBoys = (line.equals("BB"));
isTwoGirls = (line.equals("GG"));
isBoyGirl = (line.equals("BG")||line.equals("GB"));
if(isTwoBoys)
{
twoBoysCounter++;
}
else if(isTwoGirls)
{
twoGirlsCounter++;
}
else if(isBoyGirl)
{
boyGirlCounter++;
}
}
System.out.println();
System.out.println("Two Boys: " + twoBoysCounter);
System.out.println("One Boy One Girl: " + boyGirlCounter);
System.out.println("Two Girls: " + twoGirlsCounter);
inFile.close();
}
}
I've tried for several hours but I cant seem to get it to work. I haven't even been able to count how many line there are. Any help would be very appreciated! Thanks!
You never read the next line, so you're stuck in an infinite while loop
I suggest that you look into Files.readAllLines function for this case.
It loads all the lines in a List over which you can easily iterate and do what you need.
Example: Files.readAllLines(Paths.get("C:\\Users\\TEM\\Desktop\\Projects\\Family\\Document\\test1.txt", Charsets.default()) will load what you need
your while loop is inifinite as stated above since inFile.hasNextLine () is a boolean statement that returns true or false but it doesnt advance the scanner to the next line, you need to add to each of the if statements a :
inFile.nextLine() //advance the inputstream
Skipping over the "no readNextLine" issue pointed out by others, your basic technique is terrible.
Use a Map<String, Integer>.
Store the character pair as the key.
Every time you read a new pair,
attempt to retrieve it from the map.
If you get null, then the pair does not already have a counter,
so store 1 as the value.
If you get a non-null value, add 1 and store the new count.
When finished reading,
you have a map of character pairs to number of times encountered.
I have a text file like this;
7-Georgia
1-Andrew
6-John
8-Luke
9-Erica
3-Kim
2-Jude
5-Phil
4-Leo
The first column is id and second is name. How can I get these id's and names? So far I wrote this;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
public class Main {
#SuppressWarnings("resource")
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
#SuppressWarnings("unused")
Scanner fromFile = new Scanner(new File("id_name.txt"));
fromFile.useDelimiter("-");
while(fromFile.hasNext()){
String temp = fromFile.next();
System.out.println(temp);
}
while(fromFile.hasNext()){
String temp= fromFile.next();
int[] fileID;
fileID= new int[9];
for(int i=0; i<9; i++){
fileID[i]= Integer.parseInt(temp);
}
System.out.println(fileID);
}
}
}
But this doesn't get the id's. I'm not sure how to fix this, I'd be grateful if you help me.
You have two while loops in your code. Typically one while loop will go through every item until the condition is no longer true. I think you need to rework this to have a better "flow of control" which might mean using only one while loop (with sections to grab the number and then the name.
I imagine that you are looking for results from the second while loop, but by the time you get to it, the first while loop will have exhausted all of your data.
Finally, printing an array will print out the array reference identifier. If you want to actually print the contents of the array, you need a loop over the elements within the array, and you need to print out each array element explicitly.
As an alternative to the array printing technique above (which you should master), you can also use the Arrays.toString(<insert array here>) method call. However, in many cases it will give you a format that is not desired. That's why you need to know the above technique too.
Also, you have one hidden issue. You (in the second while loop) make the assumption that there are only nine inputs. Pay close attention to what you are writing. Every time you have to reach for a number, consider whether it is a "magic" number. Magic numbers are numbers that are in your code with no explanation or reason why they exist. They are indicators of errors in the code made by assumptions that probably won't last the test of time.
For example, you are using the number 9 because you have seen the input file. The next input file will probably not have nine entries in it, and your program will probably not work right if you gave it an input with eight entries, or an input with ten entries. Perhaps you should rewrite the loop to remove the magic number, by making the logic process while there is still (some) input.
Try this on for size
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
try {
Scanner fromFile = new Scanner(new File("id_name.txt"));
} catch (FileNotFoundException e) {
System.err.println("File not found");
}
String[] arr = new String[9];
String[] oth = new String[9];
int i = 0;
while(fromFile.hasNextLine()) {
String temp = fromFile.nextLine();
oth[i] = temp.substring(0,1);
arr[i] = temp.substring(2);
i++;
}
int[] fileID;
fileID = new int[9];
for(int j = 0; j < 9; j++) {
fileID[j] = Integer.parseInt(oth[j]);
}
}
}
this should go through and retrieve the numbers(.substring(0,1)) and then the names(.substring(2)), and then converting the numbers to int values.
Try the following:
File file=new File("id_name.txt");
int[] fileID;
fileID= new int[9];
String[] result = file.nextLine().split("-");
for (int x = 0; x < result.length; x++){
if (Character.isDigit(result[x])) { // use the isDigit method to get the ids
System.out.println("this is an id");
fileID[i]= Integer.parseInt(result[x]);
}
Actually my friend, there are several mistakes here.
1) When the first while loop completes, it leaves fromfile.hasNext() as false Hence the second loop never starts.
>> To fix this, You need to put it all in one while loop.
2) fileID is an array. You cannot print it using System.out.println(fileID).
>> You have to tell what kind of output you want. The code will depend on that. For simply printing all the values, you need to make a for loop that prints each value separartely. You should use fileID.length for the no. of times you need to loop it.
3) Basically, fromfile.next() is not the way to do it.
>> You need to use fromfile.nextLine().
In my program, it reads a file called datafile.txt... inside the datafile.txt is a random 3 lines of words. What my program does is reads the file the user types in and then they can type in a Line # and Word # and it will tell them the word that is in that location.. for example..
What is the file to read from?
datafile.txt
Please enter the line number and word number (the first line is 1).
2 2
The word is: the
My problem is that my program reads the 3 lines in the txt doc as 0, 1 ,2 and the words start from 0. So to read the first word in the first line they would have to type 0,0 instead of 1,1. What I am trying to do is make it work so they can type 1,1 instead of 0,0. Not sure what my problem is right now, here is my code....
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class readingFile {
/**
* #param args
* #throws IOException
* #throws validException
*/
public static void main(String[] args) throws IOException, checkException
{
System.out.println("Enter file name: " );
Scanner keyboard = new Scanner(System.in);
BufferedReader inputStream = null;
ArrayList<String> file = new ArrayList<String>();
String fileName = keyboard.next();
System.out.println ("The file " + fileName +
" has the following lines below: ");
System.out.println();
try
{
inputStream = new BufferedReader(new FileReader(fileName));
ArrayList<String> lines = new ArrayList<String>();
while(true)
{
String line = inputStream.readLine();
if(line ==null)
{
break;
}
Scanner itemnize = new Scanner(line);
while(itemnize.hasNext())
{
lines.add(itemnize.next());
}
lines.addAll(lines);
System.out.println(lines+"\n");
}
System.out.println("Please enter the line number and word number");
int index1 = keyboard.nextInt();
int index = keyboard.nextInt();
System.out.println("The word is: "+ lines.get(index));
}
catch(FileNotFoundException e)
{
System.out.println("Error opening the file " + fileName);
}
inputStream.close();
}
private static void checkValid(ArrayList<String> items, int index) throws checkException
{
throw new checkException("Not Found");
}
}
The obvious solution to adapt 1-based user input to 0-based internal representation is to subtract one at some point. Seeing that you don't even use index1, writing
lines.get(index - 1)
isn't going to solve your problem completely. But I guess you can take it from there, and do something similar for the word index.
As I assume you are just learning to program I will point out 3 areas of improvement
Much like how mathematics has BIDMAS which determines the order of evaluation of an expression Java and other program languages evaluate statements in a particulate way. This means within the Parentheses of a function you may include a statment instead of a variable or constant. This will be evaluated with the result (or return) been passed into the called function. This is why MvG says you can do lines.get(index - 1)
Not all exceptions you should consider and plan around will the compiler inform you about. For example in your code an invalid input for line number or word number is entered you will get a Runtime Exception (array index out of bound)
Naming of variables should be useful, you have index and index1. What's the difference? I assume from reading your code one should be the user selected index of the line number and the second should be the index of the word on said line. May I suggest requestedLineIndex and requestedWordIndex.
On a final note this is not a usual StackOverflow question hence why your question has been 'voted down'. If you are learning as part of a course is there a course forum or Virtual Learning Environment (VLE) you can post questions on? The support of your peers at the same level of learning tends to help with exploring the basics of a language.