I have a program which searches through a mini-database I have created in a text file, everything works fine, except the fact that whatever is the very last line in the last line of the data is not recognized and whenever I attempt to search for it, it will fail and I am informed that the data does not exist in the database, although it very clearly does when I look at the txt file.
I managed to get a work-around for this, but adding a fake line at the very end that didn't have data, and something I would use such as "xxxxxxxxxx", and then it was able to read the data on top, which originally was the last line before. The problem with this is, I also have to be able to add data to the function straight from my java program, and it would be extremely tedious to have to first remove that fake line, add my information, then put the fake line in again, so I am trying to figure out why it is not searching the last line of my data.
Here is the code for one of my searches:
BufferedReader i = new BufferedReader (new FileReader ("Elements.txt"));
String data=i.readLine();
while (data!=null)
{
String database[]=data.split(",");
data=i.readLine();
if (data!=null)
{
for (int x=0;x<data.length(); ++x)
{
if (database[0].equalsIgnoreCase(elementName))
{
element=database[0];
symbol=database[1];
atomicNumber=database[2];
atomicMass=database[3];
valence=database[4];
found=true;
break;
}
}
}
}
Here is the data that it is searching through:
http://i.imgur.com/GeXQhTh.png
Any idea on how to fix this?
Simply remove your if(data==null) check after you get your last line. You are getting the next line, then checking if that is valid, then continuing, which is unecessary given your while loop. In essence, you are filtering out the last line (since the next line should be null)
Also, you can just get rid of the for loop which is completely superfluous because nothing changes between each invocation (you only interact with your database[] object and x is never used; i.e., you are just doing the same thing data.length() times).
Modify your code like this:
BufferedReader i = new BufferedReader(new FileReader("Elements.txt"));
String data;
while ((data = i.readLine()) != null) {
String database[] = data.split(",");
if (database[0].equalsIgnoreCase(elementName)) {
for (int x = 0; x < data.length(); ++x) {
element = database[0];
symbol = database[1];
atomicNumber = database[2];
atomicMass = database[3];
valence = database[4];
found = true;
break;
}
}
}
for reading text files, put readLine into while condition, so you
only have to write it once and no need for extra null checks and breaks
you do not have to compare database[0]
for each token, so move "if" outside of "for"
Related
I am trying to read information from a file but for each line it just returns a null
String[] quotes = new String[numberOfLines];
String myLine;
for (int i = 0; i < numberOfLines; i++)
{
myLine = readFile.readLine();
System.out.println(myLine);
quotes[i] = myLine;
}
numberOfLines in the number of lines that actually has characters on them in the file
BufferedReader.readLine returns null if and only if you have read to the end of the file / stream: See javadoc.
Therefore, you have reached the end of file.
Therefore the problem is somewhere else in your code:
how readFile is instantiated / used (e.g. have you opened the right file?), or
how you get the value for numberOfLines.
Unfortunately, we can't go further without seeing the code that does those things. Or better still, an MCVE.
UPDATE
One possibility: the code you use to count the lines has read the file via readFile and left the BufferedReader positioned at the end of file.
So here's the problem. Turn a text file into the correct formatting.
The point of the problem is that I have to read a file, a text file, which contains code in that text file. The code in that has terrible formatting. The formatting issue is that when there is a curly brace like this {, the next line is not 4 spaces to the right, it's just all to the very left. Like this:
while (blah blah blah) {
sysout(blahblahblah);
When it should be this:
while (blah blah blah) {
sysout(blahblahblah);
And there's no other differences between the 2. The only rule is to simply make it so every time there is a curly brace like this {, to make sure the next line is 4 spaces to the right. And vice versa. So every time there's a curly brace like this }, the next line should be 4 spaces to the left. I hope you guys understand this.
This is my issue. I learned how to make a program where a piece of text with multiple spaces and lines is turned into a single line with a single space every time. Wasn't too hard.
For this, though, I have to keep everything on the same line. So if there's 30 lines, the new program I make is also 30 lines. I need to keep very similar spacing, but the simple difference is the whole brace thing. So basically, I just have to make the line after a brace either 4 spaces to the right, and then do the same so it is to the left 4 spaces if it's a } curly brace.
So how do I do this exactly? I don't know how to just fix that without messing up other things. It's such a simple thing I have to do; just make the lines following the braces 4 spaces to the right or left, but I just have no idea what syntax to use to accomplish this. Thanks!
EDIT: This might have just made it easier. So, basically, all lines either end with a right curly brace, a left curly brace, or a semi-colon. No matter what. So every time one of those pops up, it is the end of a line. So maybe if you know how that makes it easier, then I'm just letting you know.
There are programs that will do this for you automatically, so you don't need to reinvent the wheel. For instance, in Eclipse, type: ctrl-a (select all) ctrl-i (auto-indent).
Here's a pseudocode you can start with:
int indentLevel = 0;
while(currentchar = nextchar != null){
printCurrentChar
if(currentchar is '{'){
indentLevel++;
}else if(currentchar is '}'){
indentLevel--;
}else if(currentchar is '\n'){
print indentLevel * 4 spaces
}
}
you might need to deal with escaped braces and other complications though
You can do this pretty easily using regular expressions. If you do not know it and planning to be a programmer, then definitely learn it. It will save for you lots of time in future.
public class TextIndentator
{
public static void main(String[] args) throws IOException
{
File uglyText = new File("ugly.txt");
System.out.println((uglyText.exists() && !uglyText.isDirectory()) ? getNiceText(uglyText) : "FILE \"ugly.txt\" at " + System.getProperty("user.dir") + " do not exists");
}
static String getNiceText(File uglyText) throws IOException
{
// Opening file
FileInputStream inputStream = new FileInputStream(uglyText);
InputStreamReader isr = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(isr);
StringBuilder builder = new StringBuilder();
StringBuffer buffer = new StringBuffer();
// Algorithm starts here
String line;
boolean checkNext = false;
while ((line = reader.readLine()) != null)
{
if(checkNext)
{
// If previous line finished with '{' (And optionally with some whitespaces after it) then, replace any amount (including zero) of whitespaces with 4 witespaces
builder.append(line.replaceFirst("\\s*", " "));
}
else
{
builder.append(line);
}
// Check if line line finishes with { (And optionally with some whitespaces after it)
if(line.matches(".*\\{\\s*")) checkNext = true;
else checkNext = false;
//Append line separator at the end of line
builder.append(System.getProperty("line.separator"));
}
return builder.toString();
}
}
For example, in my code, I have something like this:
for (int i = 0; i < arraylist.size(); i++) {
while (file.hasNext())
When the for loop goes to i = 1, will it start reading the file at the beginning again, or will the file not be read at all since it was read through at i = 0?
For i > 0, file.hasNext() will always return false since you have already read through the file at i = 0 (leaving the file pointer at the end of the file). So, nothing will happen for i > 0.
To read through the file on each iteration of the for loop, you must seek back to the start of the file after the while loop.
I am not sure what the type of file is in your question, but take a look at java.io.RandomAccessFile and its seek(long pos) method for how to accomplish this (seek(0) rewinds to the start of the file).
It will read from beginning. Does not matter whatever i is. Because you are not telling scanner to not read until some value of i is reached.
Infact, I honestly don't see this loop's significance since you are using while loop after this as well. It will just print same file's all lines once.
For example, if your file has these contents:
con1
con2
con3
and lets say your array size is 4. Then by your loop, this will be the output:
con1
con2
con3
If you want to say, start printing from second line, then use some integer for iteration reference and start printing once its 2. Something like:
int x = 0;
while(scanner.hasNext())
if(x >= 2)
System.out.println(scanner.next());
x++;
}
I don't really get what you want to do, do you want to add each word in the file to an arraylist? And then, didn't you use Scanner to read?
Scanner scanner = new Scanner(new File("path.ext"));
ArrayList<String> strings = new ArrayList<String>();
while(scanner.hasNext()) {
strings.add(scanner.next());
}
scanner.close();
was that your problem?
In this case you read each word in the file from start to end
Your code example is incomplete. If file is an instance of Scanner, hasNext only indicates that there is another token to read, but it does not advance the position in the input stream. Assuming you make a call to next in your block, then THAT call will advance, but it won't start again from the beginning unless you reinitialize your file variable to point to a new Scanner instance.
I am using 'java.util.Scanner' to read and scan for keywords and want to print the previous 5 lines and next 5 lines of the encountered keyword, below is my code
ArrayList<String> keywords = new ArrayList<String>();
keywords.add("ERROR");
keywords.add("EXCEPTION");
java.io.File file = new java.io.File(LOG_FILE);
Scanner input = null;
try {
input = new Scanner(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int count = 0;
String previousLine = null;
while(input.hasNext()){
String line = input.nextLine();
for(String keyword : keywords){
if(line.contains(keyword)){
//print prev 5 lines
system.out.println(previousLine); // this will print only last previous line ( i need last 5 previous lines)
???
//print next 5 lines
system.out.println(input.nextLine());
system.out.println(input.nextLine());
system.out.println(input.nextLine());
system.out.println(input.nextLine());
system.out.println(input.nextLine());
}
previousLine = line;
}
any pointers to print previous 5 lines..?
any pointers to print previous 5 lines..?
Save them in an Dequeue<String> such as a LinkedList<String> for its "First In First Out (FIFO)" behavior.
Either that or use 5 variables or an array of 5 Strings, manually move Strings from one slot or variable to another, and then print them.
If you use Dequeue/LinkedList, use the Dequeue's addFirst(...) method to add a new String to the beginning and removeLast() to remove the list's last String (if its size is > 5). Iterate through the LinkedList to get the current Strings it contains.
Other suggestions:
Your Scanner's check scanner.hasNextXXX() method should match the get method, scanner.nextXXX(). So you should check for hasNextLine() if you're going to call nextLine(). Otherwise you risk problems.
Please try to post real code here in your questions, not sort-of, will never compile code. i.e., system.out.println vs System.out.println. I know it's a little thing, but it means a lot when others try to play with your code.
Use ArrayList's contains(...) method to get rid of that for loop.
e.g.,
LinkedList<String> fivePrevLines = new LinkedList<>();
java.io.File file = new java.io.File(LOG_FILE);
Scanner input = null;
try {
input = new Scanner(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (input.hasNextLine()) {
String line = input.nextLine();
if (keywords.contains(line)) {
System.out.println("keyword found!");
for (String prevLine : fivePrevLines) {
System.out.println(prevLine);
}
} else {
fivePrevLines.addFirst(line);
if (fivePrevLines.size() > 5) {
fivePrevLines.removeLast();
}
}
}
if (input != null) {
input.close();
}
Edit
You state in comment:
ok i ran small test program to see if the contains(...) method works ...<unreadable unformatted code>... and this returned keyword not found...!
It's all how you use it. The contains(...) method works to check if a Collection contains another object. It won't work if you feed it a huge String that may or may not use one of the Strings in the collection, but will work on the individual Strings that comprise the larger String. For example:
ArrayList<String> temp = new ArrayList<String>();
temp.add("error");
temp.add("exception");
String s = "Internal Exception: org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object";
String[] tokens = s.split("[\\s\\.:,]+");
for (String token : tokens) {
if (temp.contains(token.toLowerCase())) {
System.out.println("keyword found: " + token);
} else {
System.out.println("keyword not found: " + token);
}
}
Also, you will want to avoid posting code in comments since they don't retain their formatting and are unreadable and untestable. Instead edit your original question and post a comment to alert us to the edit.
Edit 2
As per dspyz:
For stacks and queues, when there isn't any significant functionality/performance reason to use one over the other, you should default to ArrayDeque rather than LinkedList. It's generally faster, takes up less memory, and requires less garbage collection.
If your file is small (< a million lines) you are way better off just copying the lines into an ArrayList and then getting the next and previous 5 lines using random access into the array.
Sometimes the best solution is just plain brute force.
Your code is going to get tricky if you have two keyword hits inside your +-5 line window. Let's say you have hits two lines apart. Do you dump two 10-line windows? One 12-line window?
Random access will make implementing this stuff way easier.
I am trying to read a file line by line in java. Here is my code:
Scanner s= new Scanner(new FileReader("outputfile.txt"));
String line = null;
while (!(line = s.nextLine()).contains("OK")) {
if (line.contains("BOOK")) {
//do something
}
}
What i am trying to do is, i read the file line by line, and if the next line has "OK" in it, then i stop reading. But the problem is, since i have
!(line = s.nextLine()).contains("OK")
every time i get into the line
if (line.contains("BOOK")),
since line=s.nextLine()
i read another line and in one loop cycle i read two lines. How can i fix this?
Thanks
You're misunderstanding how the = operator works.
line = s.nextLine()
does not mean that every time you use line, it calls s.nextLine(). Rather,
line = s.nextLine()
means "call s.nextLine() once, and make line refer to what s.nextLine() returned". Thus,
if (line.contains("BOOK"))
does not cause another call to s.nextLine(). It only looks up the value stored in line by the previous assignment. The loop reads one line per iteration, not two. If you tried it, and it seemed to skip lines, that's probably because "BOOK" contains "OK", so the code in the if never runs.
Think about what you are doing here...
// LOOP
// Read the next line
// Does this line contain "OK"
// YES -> End loop
// NO -> Does the line contain "BOOK" - Obviously it cant if it didn't contain "OK"
// -> BACK TO LOOP
Let's unfold the code for clarity:
while (true) {
line = s.nextLine();
if (line == null || line.contains("OK")) break;
if (line.contains("BOOK")) { ... }
}
Unfortunately "BOOK" and "OK" inside it, so the second condition is unreachable.
You need to look a little more closely at the syntax of the file to parse this correctly.
try this
while (s.hasNextLine()) {
String line = s.nextLine();
if (line.contains("BOOK")) {
...
} else if (line.contains("OK") {
break;
}
}