While reading a file with a BufferedReader, I want it to skip blank lines and lines that start with '#'. Ultimately, each individual character is then added to an arraylist
inputStream = new BufferedReader(new FileReader(filename));
int c = 0;
while((c = inputStream.read()) != -1) {
char face = (char) c;
if (face == '#') {
//skip line (continue reading at first char of next line)
}
else {
faceList.add(face);
}
Unless I'm mistaken, BufferedReader skips blank lines automatically. Other than that, how would I go about doing this?
Would I just skip()? The length of the lines may vary, so I don't think that would work.
Do not attempt to read the file a character at a time.
Read in one complete line, into a String, on each iteration of your main loop. Next, check it it matches the specific patterns you want to ignore (empty, blanks only, starting with a #, etc). Once you have a line you want to process, only then iterate over the String a character at a time if you need to.
This makes checking for and ignoring blank lines and lines matching a pattern MUCH easier.
while((line=in.readline()) != null)
{
String temp = line.trim();
if (temp.isEmpty() || temp.startsWith("#"))
/* ignore line */;
else
...
}
Use continue. This will continue to the next item in any loop.
if (face == '#') {
continue;
}
else {
faceList.add(face);
}
Related
I am currently working on a program that reads through a text file and prints different lines depending on what the previous line consists of. For example if the previous line was an integer, then I print a different variation of the current line. How can I check to see whether the previous line was an integer without going through the file two lines at a time?
Here is the code so far.
public void workThroughFile(String filename) {
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = br.readLine()) != null) {
if (isInteger(line) == false && line.contains("?") == true) {
System.out.println(line);
}
if (isInteger(line) == false && line.contains("?") == false) {
System.out.println(line);
}
if (isInteger(line) == true) {
}
}
}
catch (Exception e) {
System.out.println("Did not quite work this time.");
}
}
The strategy here would be:
Save both the previous line and the current line in memory. You can declare 2 properties on the class handling the file read.
private String prevLine;
private String currLine;
Then read file lines one by one:
...
String line;
while ((line = br.readLine()) != null) {
//update line properties
prevLine = currLine;
currLine = line;
if(someConditions(prevLine)){
handleCurrLine(currLine);
}
}
You want to keep track of state. For example if you want to look at the last two lines and keep track of if they were ints or not you have 4 possible states: neither were ints, last was int, 2nd last was int, or both were ints. Just make something (ex. boolean wasLastLineInt) to keep track of the state and update it as you read lines. Booleans are probably the easiest way to keep track of the state.
wasLastLineInt = false;
was2ndLastLineInt = false;
while ((line = br.readLine()) != null) {
if(wasLastLineInt){
//do something with line if lastline was an int
}
else{
//do something with line if last line wasn't an int
}
//whatever other conditions you want
//prepare for next iteration
was2ndLastLineInt = wasLastLineInt;//condition of lastline will be condition of 2ndlastline next iteration
wasLastLineInt = line.matches("^-?\\d+$");//set last line condition for next iteration
}
It uses a regex http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html to check if the string is a positive or negative integer. however it wont catch something with a '+' sign at the front.
Make sure to update the state after you decide how to handle the current line, or you will make decisions based on the wrong lines. And keep in mind how you want to handle the first few lines, this starts with the behavior for lines -1 and -2 being nonintegers.
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.
I have this piece of code:
(this code is inside another cycle, that is cycling 3 times)
...
text = "";
while((c = is.read())!=-1){
if(prev == '\r' && c == '\n'){
break;
}
text = text + (char) c;
prev = (char) c;
}
System.out.println(text);
...
is is InputStream, c is int, prev is char
With this code I build up a string from the InputStream. The reading should stop everytime when I get \r\n. Then it start's over again. Everything works fine except one thing. The stream I get looks like this:
1233\r\n544\r\nX
There is no delimeter after this input stream
With this I get the string 1233 from the first cycle and string 544 from the second cycle. But I won't get the last X, because the cycle won't stop there - and I don't know why. I thought that with is.read()=!-1 the cycle should stop when the stream ends. But it doesn't. The program is stuck inside that cycle.
Your question is unclear but here goes:
while( ( c = is.read() ) != -1 )
{
if(prev == '\r' && c == '\n')
{
break;
}
text = text + (char) c;
prev = (char) c;
}
Notice the order of execution. Check for \r\n and exit loop then append current character to text.
Do you see anything wrong with this logic?
Also you said
the cycle should stop when the stream ends. But it doesn't. The
program is stuck inside that cycle.
If the last two bytes are never \r\n or if the stream never closes it will never end and it will drop the last \n either way!
So which is it the loop never ends or the \n never gets appended?
If you want the loop to end at the end of the stream and at when a \r\n is detected you need to re-order your logic.
Garbage In Garbage Out:
Assuming that there are actually \r\n pairs in your InputStream. Are you sure they are there?, Step debugging would tell you for certain!
public static void main(final String[] args)
{
final InputStream is = System.in;
final StringBuilder sb = new StringBuilder(1024);
try
{
int i;
while ((i = is.read()) >= 0)
{
sb.append((char)i);
if (sb.substring(sb.length()-2).equals("\r\n"))
{
break;
}
}
}
catch (final IOException e)
{
throw new RuntimeException(e);
}
System.out.print(sb.toString());
}
You need to stop and learn how to use the step debugger that is in
your IDE. This would not be a question if you just stepped through
your code and put a few break points where things were not as you
wanted or expected them.
I need to read a text file using java. Not a problem. But I need to reject the empty lines at the end of the file. The file is quite large, around a million or so lines. I need to process each line, one at a time. Even if they are empty.
But, if the empty lines are at the end of the file, then I need to reject it. Note that there can be multiple empty lines at the end of the file.
Any quick solutions? I almost want to write a FileUtility.trimEmptyLinesAndEnd(File input). But I cant help feeling that someone might have written something like this already.
Any help appreciated.
Note:
I have read this link.
Java: Find if the last line of a file is empty.
But this is not what I am trying to do. I need to reject multiple
empty lines.
When you find an empty line, increment a counter for the number of empty lines. If the next line is also empty, increment the counter. If you reach the end of the file, just continue on with what you want to do (ignoring the empty lines you found). If you reach a non-empty line, first do whatever you do to process an empty line, repeating it for each empty line you counted. Then process the non-empty line as normal, and continue through the file. Also, don't forget to reset the empty line counter to zero.
Pseudo code:
emptyLines = 0;
while (the file has a next line) {
if (line is empty) {
emptyLines++;
} else {
if (emptyLines > 0) {
for (i = 0; i < emptyLines; i++) {
process empty line;
}
emptyLines = 0;
}
process line;
}
}
You have to read all lines in your file. You can introduce a guarding that will store the value of last not empty line. At the end return the subset from zero to guardian.
In case you have a stream process.
read line
if empty
increase empty lines counter
else
if there was some empty lines
yield fake empty lines that counter store
reset counter
yield line
Thanks for all the responses. I think both Vash - Damian LeszczyĆski and forgivenson cracked the pseudocode for this problem. I have taken that forward and am providing here the Java code for people who come looking for an answer after me.
#Test
public void test() {
BufferedReader br = null;
try {
String sCurrentLine;
StringBuffer fileContent = new StringBuffer();
int consecutiveEmptyLineCounter = 0;
br = new BufferedReader(new FileReader("D:\\partha\\check.txt"));
while ((sCurrentLine = br.readLine()) != null) {
// if this is not an empty line
if (!(sCurrentLine.trim().length() == 0)) {
// if there are no empty lines before this line.
if (!(consecutiveEmptyLineCounter > 0)) {
// It is a non empty line, with non empty line prior to this
// Or it is the first line of the file.
// Don't do anything special with it.
// Appending "|" at the end just for ease of debug.
System.out.println(sCurrentLine + "|");
} else {
// This is a non empty line, but there were empty lines before this.
// The consecutiveEmptyLineCounter is > 0
// The "fileContent" already has the previous empty lines.
// Add this non empty line to "fileContent" and spit it out.
fileContent.append(sCurrentLine);
System.out.println(fileContent.toString() + "#");
// and by the way, the counter of consecutive empty lines has to be reset.
// "fileContent" has to start from a clean slate.
consecutiveEmptyLineCounter = 0;
fileContent = new StringBuffer();
}
} else {
// this is an empty line
// Don't execute anything on it.
// Just keep it in temporary "fileContent"
// And count up the consecutiveEmptyLineCounter
fileContent.append(sCurrentLine);
fileContent.append(System.getProperty("line.separator"));
consecutiveEmptyLineCounter++;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)
br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Thanks for all the help.
And, what I have provided here is just one solution. If someone comes across something more clever, please share. I can't shake the feeling off that there should be some FileUtils.trimEmptyLinesAtEnd() sort of method somewhere.
Just read the File backwards. Starting from the first line you read, refrain from processing all blank lines you encounter.
Starting with the first non-blank line you encounter, and thereafter, process all lines whether or not they're blank.
The problem is "intractable" wrt to a neat solution if you read the File forward since you can never know if at some point after a long run of blank lines there might yet be a non-blank line.
If the processing of lines in order, first-to-last, matters, then there is no neat solution and anything like what you have now is about what there is.
I am writing a program that is going to read a string from a file, and then remove anything that isn't 1-9 or A-Z or a-z. The A-Z values need to become lowercase. Everything seems to run fine, I have no errors, however my output is messed up. It seems to skip certain characters for no reason whatsoever. I've looked at it and tweaked it but nothing works. Can't figure out why it is randomly skipping certain characters because I believe my if statements are correct. Here is the code:
String dataIn;
int temp;
String newstring= "";
BufferedReader file = new BufferedReader(new FileReader("palDataIn.txt"));
while((dataIn=file.readLine())!=null)
{
newstring="";
for(int i=0;i<dataIn.length();i++)
{
temp=(int)dataIn.charAt(i);
if(temp>46&&temp<58)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>96&&temp<123)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>64&&temp<91)
{
newstring=newstring+Character.toLowerCase(dataIn.charAt(i));
}
i++;
}
System.out.println(newstring);
}
So to give you an example, the first string I read in is :
A sample line this is.
The output after my program runs through it is this:
asmlietis
So it is reading the A making it lowercase, skips the space like it is suppose to, reads the s in, but then for some reason skips the "a" and the "m" and goes to the "p".
You're incrementing i in the each of the blocks as well as in the main loop "header". Indeed, because you've got one i++; in an else statement for the last if statement, you're sometimes incrementing i twice during the loop.
Just get rid of all the i++; statements other than the one in the for statement declaration. For example:
newstring="";
for(int i=0;i<dataIn.length();i++)
{
temp=(int)dataIn.charAt(i);
if(temp>46&&temp<58)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>96&&temp<123)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>64&&temp<91)
{
newstring=newstring+Character.toLowerCase(dataIn.charAt(i));
}
}
I wouldn't stop editing there though. I'd also:
Use a char instead of an int as the local variable for the current character you're looking at
Use character literals for comparisons, to make it much clearer what's going on
Use a StringBuilder to build up the string
Declare the variable for the output string for the current line within the loop
Use if / else if to make it clear you're only expecting to go into one branch
Combine the two paths that both append the character as-is
Fix the condition for numbers (it's incorrect at the moment)
Use more whitespace for clarity
Specify a locale in toLower to avoid "the Turkey problem" with I
So:
String line;
while((line = file.readLine()) != null)
{
StringBuilder builder = new StringBuilder(line.length());
for (int i = 0; i < line.length(); i++) {
char current = line.charAt(i);
// Are you sure you want to trim 0?
if ((current >= '1' && current <= '9') ||
(current >= 'a' && current <= 'z')) {
builder.append(current);
} else if (current >= 'A' && current <= 'Z') {
builder.append(Character.toLowerCase(current, Locale.US));
}
}
System.out.println(builder);
}