How to read lines above and below a particular linenumber in java? - java

I need to parse a log file which is in txt format.
I need to match the String and read above and below lines of the matched String.
I need to do something similar to grep -A 30 -B 50 'hello'.
If You have any other suggestions to do it you are welcome.

Read the file line by line, and match your string (either regexp or String.indexOf("")). Keep the previous n lines in memory so when you've matched your string you can print them. Use BuffereReader.readLine() to read the file line by line (note that using the BufferedReader is actually more complicated because you cannot jump back).
Or for more flexibility RandomAccessFile. With this method you can mark your position, print the next m lines and then jump back to continue your search from where you left it.

pseudocode:
initialize a Queue
for each line
if line matches regex
read/show lines from queue;
read/show next lines;
else {
if queue size > 30
queue.remove() // removes head of the queue
add this line to queue;
}
You can use BufferedReader to read a file line by line, Pattern to check the line against a regular expression, and Queue to store previous lines.

You may use following code(uses java 5 api java.util.Scanner):
Scanner scanner = new Scanner(new File("YourFilePath"));
String prev = null;
String current;
while (scanner.hasNextLine())
{
current = scanner.nextLine();
if (current.contains("YourRegEx"))
break;
else
prev = current;
}
String next = scanner.nextLine();
You may want to add additional checks for prev being not null and Calling scanner.hasNextLine() before String next = scanner.nextLine()

Related

Java Scanner, No such element exception while reading mulitple lines

I am trying to read multiple line from a file using java scanner. Each line has strings separated using comma, but there is no comma at the end of line. My text file contains value like below
98792203000000005091,89065012012341234100000000000167,084952103900000015
98792203000000005091,89065012012341234100000000000167,084952103900000015
The scanner is throwing a no element exception, it works fine if I add a comma t the end of line, but the original file will not have a comma. How do I make work
Scanner sc = new Scanner(outPutFile);
int outputDataStart = Integer.parseInt(outputDataStartLine);
skipLines(sc, outputDataStart);
sc.useDelimiter(",");
while(sc.hasNext())
{
OutputVariables outputVariables = new OutputVariables();
outputVariables.setIccid(sc.next());
outputVariables.setImsi(sc.next());
outputVariables.setKey(sc.next());
outputVariables.setPIN1(sc.next());
outputVariables.setPUK1(sc.next());
outputVariables.setPIN2(sc.next());
outputVariables.setPUK2(sc.next());
outputVariables.setPINAdm(sc.next());
outputVariables.setAccount(sc.next());
outputVariables.setKIC(sc.next());
outputVariables.setKID(sc.next());
outputVariables.setKIK(sc.next());
outputVariables.setOPCKey(sc.next());
OutputVariableList.add(outputVariables);
}
Insteard of using sc.useDelimiter(",") use sc.useDelimiter(",|\\n") it would break by both , and new line
You're asking the scanner to parse more values from a line of text than there are values. This is happening because you're calling next() without first checking hasNext(). Since you've told it to use the comma as the delimeter, it's hitting the end of the line continuing on to the next line until it finds the next comma.
Consider this CSV:
A,B,C,D
If you call next() after you parse the "D", the scanner will throw a NoSuchElementException.
It is not clear what you're attempting to do. If you're attempting to convert what is effectively a CSV into an object, then your best bet would be to use the Scanner to read each line, and then a String.split() call to split that line into parts.
If you're trying to parse multiple lines into an object, you'll of course need to figure out where your boundary is -- every fifteen comma separated values? every three lines? -- and apply that logic while collecting your segments.
As a simplified example, consider this collection of lines:
A,B,C,D
E,F,G,H
I,J,K
You would first use the Scanner to read line-by-line, and then use split each line apart and create the individual objects. Notice the last line is malformed -- you'll need to trap for that and catch it to avoid the NoSuchElementException.
Scanner sc = new Scanner(file);
while(sc.hasNext()) {
String line = sc.next();
String[] parts = line.split(",");
if(parts.length != 4) {
System.err.println("Invalid line: " + line);
continue; // skip this record, it is bad
}
// create your object here from parts
Pojo example = new Pojo(parts[0], parts[1], parts[2], parts[3]);
// etc
}
Alternatively if you're just trying to create a single massive object -- eg all lines belong to the same record -- you could tell it to consider a newline as a delimeter in addition to a comma. That way, after you hit the last comma in the first line, you would call next() and it would parse until the end of the line; and then when you called next() again, it would parse starting on the next line until it reached a comma or the end of the line, whichever came first.
I suggest you to use BufferedReader
it has a method named readLine()
first read a String then through the string.split(",") you can get the array of String

Is there a way around not advancing a line with Scanner (Java)

Okay so I'm having a slight problem with scanner advancing an extra line. I have a file that has many lines containing integers each separated by one space. Somewhere in the file there is a line with no integers and just the word "done".
When done is found we exit the loop and print out the largest prime integer that is less than each given integer in each line(if integer is already prime do nothing to it). We do this all the way up until the line with "done".
My problem: lets say the file contains 6 lines and on the 6th line is the word done. My output would skip lines 1, 3 and 5. It would only return the correct values for line 2 and 4.
Here's a snippet of code where I read the values in:
Scanner in = new Scanner(
new InputStreamReader(socket.getInputStream()));
PrintStream out = new PrintStream(socket.getOutputStream());
while(in.nextLine() != "done"){
String[] arr = in.nextLine().split(" ");
Now I sense the problem is that the nextLine call in my loop advances the line and then the nextline.split call also advances the line. Thus, all odd number lines will be lost. Would there be another way to check for "done" without advancing a line or is there a possible command I could call to somehow reset the scanner back to the start of the loop?
The problem is you have 2 calls to nextLine() try something like this
String line = in.nextLine();
while (!"done".equals(line)) {
String[] arr = line.split(" ");
// Process the line
if (!in.hasNextLine()) {
// Error reached end of file without finding done
}
line = in.nextLine();
}
Also note I fixed the check for "done" you should be using equals().
I think you are looking for this
while(in.hasNextLine()){
String str = in.nextLine();
if(str.trim().equals("done"){
break;
}else{
String[] arr = str.split("\\s+");
//then do whatever you want to do
}
}

Why aren't my words coming out less than 8 characters?

public String compWord() throws IOException, ClassNotFoundException
{
// Local constants
final int MAX_COUNT = 8;
// Local variables
BufferedReader reader = new BufferedReader(new FileReader("dictionary.txt")); // Create a new BufferedReader, looking for dictionary.txt
List<String> lines = new ArrayList<String>(); // New ArrayList to keep track of the lines
String line; // Current line
Random rand = new Random(); // New random object
String word; // The computer's word
/********************* Start compWord *********************/
// Start reading the txt file
line = reader.readLine();
// WHILE the line isn't null
while(line != null)
{
// Add the line to lines list
lines.add(line);
// Go to the next line
line = reader.readLine();
}
// Set the computers word to a random word in the list
word = lines.get(rand.nextInt(lines.size()));
if(word.length() > MAX_COUNT)
compWord();
// Return the computer's word
return word;
}
From what I understand it should only be returning words less than 8 characters? Any idea what I am doing wrong? The if statement should recall compWord until the word is less than 8 characters. But for some reason I'm still get words from 10-15 chars.
Look at this code:
if(word.length() > MAX_COUNT)
compWord();
return word;
If the word that is picked is longer than your limit, you're calling compWord recursively - but ignoring the return value, and just returning the "too long" word anyway.
Personally I would suggest that you avoid the recursion, and instead just use a do/while loop:
String word;
do
{
word = lines.get(rand.nextInt(lines.size());
} while (word.length() > MAX_COUNT);
return word;
Alternatively, filter earlier while you read the lines:
while(line != null) {
if (line.length <= MAX_COUNT) {
lines.add(line);
}
line = reader.readLine();
}
return lines.get(rand.nextInt(lines.size()));
That way you're only picking out of the valid lines to start with.
Note that using Files.readAllLines is a rather simpler way of reading all the lines from a text file, by the way - and currently you're not closing the file afterwards...
If the word is longer than 8 characters, you simply call your method again, continue, and nothing changes.
So:
You are getting all the words from the file,
Then getting a random word from the List, and putting it in the word String,
And if the word is is longer than 8 characters, the method runs again.
But, at the end, it will always return the word it picked first. The problem is that you just call the method recursively, and you do nothing with the return value. You are calling a method, and it will do something, and the caller method will continue, and in this case return your word. It does not matter if this method is recursive or not.
Instead, I would recommend you use a non-recursive solution, as Skeet recommended, or learn a bit about recursion and how to use it.

What's an elegant way to parse this text in java?

Disclaimer:
The parsing-problem described in here is very simple. This question does not simply ask for a way to achieve the parsing. - That's almost straightforward - Instead, it asks for an elegant way. That elegant way would probably be one which does not first read line-wise and then parse each line on its own, as this is obviously not necessary. However, is this elegant way possible with ready to use standard classes?
Question:
I have to parse text of the following form in java (there is more than these 3 records; records can have way more lines than these examples):
5
Dominik 3
Markus 3 2
Reiner 1 2
Samantha 4
Thomas 3
4
Babette 1 4
Diana 3 4
Magan 2
Thomas 2 4
The first number n is the number of lines in the record directly following. Each record consists of a name and then 0 to n integers.
I thought that using java.util.Scanner is a natural choice, but it leads to the nastiness that when using hasNextInt() and hasNext() to determine if a line is started, I can't distinguish if a read number is the header of the next record or it's the last number behind the last name of the previous record. Example from above:
...
Thomas 3
4
...
Here, I don't know how to tell if the 3 and the 4 is a header or belongs to the current line of Thomas.
Sure I can first read line by line, put them into another Scanner, and then read them again, but this effectively parses the whole data twice, which looks ugly to me. Is there a better way?
I would need something like a flag which tells me if a line break was encountered during the last delimiter skipping operation.
Read the file using FileReader and BufferedReader and then start checking :
outer loop -->while readLine is not null
if line matches //d+ --> read value of number and put it into count
from 0 to count do what you want to do // inner loop
Instead of reading into a separate scanner, you can read to end of line, and use String.split, like this:
while (scanner.hasNextInt()) {
int count = scanner.nextInt();
for (int i = 0 ; i != count ; i++) {
if (!scanner.hasNext()) throw new IllegalStateException("expected a name");
String name = scanner.next();
List<Integer> numbers = new ArrayList<Integer>();
for (String numStr : scanner.readLine().split(" ")) {
numbers.add(Integer.parseInt(numStr));
}
... // Do something with name and numbers
}
}
This approach avoids the need to detect the difference between the last int on a line vs. the first integer on next line by calling readLine() after reading a name, i.e. in the middle of reading a line.
File file = new File("records.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = null;
/* Read file one line at a time */
while((line = reader.readLine()) != null){
int noOfRecords = Integer.parseInt(line);
/* read the next n lines in a loop */
while(noOfRecords != 0){
line = reader.readLine();
String[] tokens = line.split(" ");
noOfRecords--;
// do what you need to do with names and numbers
}
}
Here we're reading one line at a time, so the first time we read a line it will be an int (call it as n), from there read the next n lines in some inner loop. Once it's done with this inner loop it will come outside and the next time you read a line it's definitely another int or EOF. That way you don't have to deal with integer parsing exceptions and we'll read all the lines only once :)

How to print previous and next lines to compare strings when reading line by line

I am reading a csv file line by line and I am trying to compare previous, current and next lines. I know I need to save three string variables as I am reading a line. But I am stuck as to how to save my three variables so that when I read line 4 to be able to print line 3 and line 5.
String prev = null;
String curr = null;
String next = null;
Scanner sc = new Scanner(new File("thefile.csv"));
while(sc.hasNextLine()) {
prev = curr;
curr = next;
next = sc.nextLine();
// now process those lines
}
Save them in an array. Then use -1 and +1 relative to the index number while looping through. Don't forget to check if -1 and +1 actually exist, and catch exceptions just in case.

Categories

Resources