java - BufferedReader readLine stop reading when encouters empty string - java

I am using BufferedReader to read a text file line by line. Then i use a method to normalize each line text. But there is something wrong with my normalization method, after the call to it, BufferedReader object stop reading file. Can someone help me with this.
Here is my code:
public static void main(String[] args) {
String string = "";
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = br.readLine()) != null) {
string += normalize(line);
}
} catch (Exception e) {
}
System.out.println(string);
}
public static String normalize(String string) {
StringBuilder text = new StringBuilder(string.trim());
for(int i = 0; i < text.length(); i++) {
if(text.charAt(i) == ' ') {
removeWhiteSpaces(i + 1, text);
}
}
if(text.charAt(text.length() - 1) != '.') {
text.append('.');
}
text.append("\n");
return text.toString();
}
public static void removeWhiteSpaces(int index, StringBuilder text) {
int j = index;
while(text.charAt(j) == ' ') {
text.deleteCharAt(j);
}
}
and here is the text file that i use:
abc .
asd.
dasd.

I think you have problem in your removeWhiteSpaces(i + 1, text);, and if you have problem in the string process, the reader wont able to read the next line.
You don't check the empty string, and you call text.charAt(text.length()-1), it is a problem too.
Print the exception, change your catch block to write out the exception:
} catch (Exception e) {
e.printStackTrace();
}
The reason is in your while(text.charAt(j) == ' ') {, you don't examine the length of StringBuilder, but you delete it...

Try this:
while ((line = br.readLine()) != null) {
if(line.trim().isEmpty()) {
continue;
}
string += normalize(line);
}

Try ScanReader
Scanner scan = new Scanner(is);
int rowCount = 0;
while (scan.hasNextLine()) {
String temp = scan.nextLine();
if(temp.trim().length()==0){
continue;
}
}
//rest of your logic

The normalize function is causing this.
the following tweak to it shoudl fix this:
public static String normalize(String string) {
if(string.length() < 1) {
return "";
}
StringBuilder text = new StringBuilder(string.trim());
if(text.length() < 1){
return "";
}
for(int i = 0; i < text.length(); i++) {
if(text.charAt(i) == ' ') {
removeWhiteSpaces(i + 1, text);
}
}
if(text.charAt(text.length() - 1) != '.') {
text.append('.');
}
text.append("\n");
return text.toString();
}

The problem is not in your code but in the understanding of the readLine() method. In the documentation is stated:
Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.
https://docs.oracle.com/javase/7/docs/api/java/io/BufferedReader.html#readLine()
So that means that if the method finds an empty line it will stop reading and return null.
The code proposed by #tijn167 would do the workaround using BufferedReader. If you are not restraint to BufferedReader use ScanReader as #Abhishek Soni suggested.
Also, your method removeWhiteSpaces() is checking for white spaces while the empty lines are not a white space but a carry return \r or a line feed \n or both. So your condition text.charAt(j) == ' ' is never satisfied.

Second line of your file is empty, therefore the while loop stops

Related

Remove a last blank line

I have a problem with some java code.
I'm returning a text from a method, which is on a .txt file. Then, I'm storing this text to a variable "text" and writing this on another .txt file. But the problem is: this new .txt file gets a new blank line at the bottom. That's because inside my method read, the variable "text" is receiving a "\n". How can I solve this problem?
PS: I'm doing this with educational purposes.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.FileReader;
import java.io.FileWriter;
public class Arquivo {
public static void main(String[] args) {
String text = read("in.txt");
write(text, "out.txt");
System.out.println("Text created!");
}
public static String read(String arquivo) {
String text = "";
try (BufferedReader br = new BufferedReader(new FileReader(arquivo))) {
String line = br.readLine();
while (line != null) {
text += line + "\n";
line = br.readLine();
}
} catch (IOException e) {
System.err.println(e.getMessage());
}
return text;
}
public static void write(String text, String arquivo) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(arquivo))) {
bw.write(text);
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
}
My two created files "in.txt" and "out.txt".
this is
a text file.
this is
a text file.
(blank line)
please try this:
String line = br.readLine();
while (line != null) {
text += line;
line = br.readLine();
if (line!=null){
text += "\n";
}
}
you can try this variant:
String line;
while((line = br.readLine()) != null) {
text += line;
if (line!=null){
text += "\n";
}
}
A good solution to this type of problem is to add the newline before you write each additional line:
String line = br.readLine();
text += line;
while ((line = br.readLine()) != null) {
text = "\n" + line;
}
This way, you only add the newline for each additional line you write (no extraneous ones at the end). Notice the assignment (plus null check) in the while loop).
replace write(text, "out.txt"); with
write(text.substring(0,text.length()-1), "out.txt");
which will remove the last character, which is the /n before writing.
Store all the strings in a list, then join on the line feed
public static void main( String[] args ) {
String text = read( "in.txt" );
write( text, "out.txt" );
System.out.println( "Text created!" );
}
public static String read( String arquivo ) {
List<String> texts = new ArrayList<>();
try ( BufferedReader br = new BufferedReader( new FileReader( arquivo ) ) ) {
String line = br.readLine();
while ( line != null ) {
texts.add( line );
line = br.readLine();
}
} catch ( IOException e ) {
System.err.println( e.getMessage() );
}
return texts.stream().collect( Collectors.joining( "\n" ) );
}
public static void write( String text, String arquivo ) {
try ( BufferedWriter bw = new BufferedWriter( new FileWriter( arquivo ) ) ) {
bw.write( text );
} catch ( IOException e ) {
System.err.println( e.getMessage() );
}
}
String.trim()
public String trim()
Returns a copy of the string, with leading and
trailing whitespace omitted. If this String object represents an empty
character sequence, or the first and last characters of character
sequence represented by this String object both have codes greater
than '\u0020' (the space character), then a reference to this String
object is returned.
Otherwise, if there is no character with a code greater than '\u0020'
in the string, then a new String object representing an empty string
is created and returned.
Otherwise, let k be the index of the first character in the string
whose code is greater than '\u0020', and let m be the index of the
last character in the string whose code is greater than '\u0020'. A
new String object is created, representing the substring of this
string that begins with the character at index k and ends with the
character at index m-that is, the result of this.substring(k, m+1).
This method may be used to trim whitespace (as defined above) from the
beginning and end of a string.
Returns: A copy of this string with leading and trailing white space
removed, or this string if it has no leading or trailing white space.
https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim()
Simply trim the string before you return it from read.
public static String read(String arquivo) {
String text = "";
try (BufferedReader br = new BufferedReader(new FileReader(arquivo))) {
String line = br.readLine();
while (line != null) {
text += line + "\n";
line = br.readLine();
}
} catch (IOException e) {
System.err.println(e.getMessage());
}
return text.trim();
}
Just do not add \n before the last line:
String text = "";
...
String line = br.readLine();
boolean addNewLine = false;
while (line != null) {
if (addNewLine) {
text += "\n";
} else {
addNewLine = true;
}
text += line;
line = br.readLine();
}
Also, for performance improvement, consider using a StringBuilder instead of the string concatenation:
StringBuilder sb = new StringBuilder();
...
String line = br.readLine();
boolean addNewLine = false;
while (line != null) {
if (addNewLine) {
sb.append('\n');
} else {
addNewLine = true;
}
sb.append(line);
line = br.readLine();
}
...
String text = sb.toString();

Making changes to every line in a file - Java

I am working on a program that reads 5 different files containing code that is improperly indented. I have to write a method that properly indents the code and prints it to the console and a new file, given a tab size and the names of the input and output files as parameters. My code so far runs through and indents every line and then tries to determine when to indent another tab or unindent.
public static void justifyJava( String inputFileName, String outputFileName,
int tabSize ) throws FileNotFoundException {
String one_tab = "";
for (int i = 0; i < tabSize; i++) {
one_tab += " ";
}
Scanner input = new Scanner( new File (inputFileName));
PrintStream out = new PrintStream ( new File (outputFileName));
int lineCount = 0;
while ( input.hasNextLine() ) {
String line = input.nextLine();
line = one_tab + line.trim();
lineCount++;
if (lineCount == 1){
line = line.substring(tabSize);
}
else if (lineCount == 2){
Scanner lineScan = new Scanner(line);
while (lineScan.hasNext()) {
String token = lineScan.next();
if (token.length() <= 2) {
line = line.substring(tabSize);
}
}
}
else if (line.contains("{") && lineCount > 2){
System.out.println(line);
out.println(line);
line = one_tab + input.nextLine();
while(!(line.contains("}"))){
line = one_tab + line;
System.out.println(line);
out.println(line);
line = input.nextLine();
}
line = one_tab + line;
}
else if (line.contains("}") && input.hasNextLine()){
line = one_tab + line;
}
else if (!(input.hasNextLine())) {
line = line.substring(tabSize);
}
System.out.println(line);
out.println(line);
}
}
This way is becoming very tedious because of how many situations i have to account for especially since the code in these files use different curly brace styles. Essentially all I'm trying to do is indent every line that follows an opening curly brace by one tab and unindent every line that follows a closing curly brace by one tab. Is there an easier way to do this?
Determining "how many times" you have to indent a line is the same as knowing how many blocks of code opened before this line. To this end, you detect a new block of code if:
The string contains an opening bracket {.
The string contains a control statement, e.g. if.
The second approach is harder, since you have to determine if the string is actually a control statement and not part of a variable name.
Hence, a simple program, that does not cover every possible coding standard, but will work pretty decently works like this:
Search for an opening bracket that does not belong to a comment.
When you find it, recursively call the method passing the new indentation size.
Return after finding the end of the code block.
Here goes a MWE that works for most simple cases. It is able to detect opening and closing brackets outside strings, and does not search inside comment lines.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Scanner;
public class JavaIndent {
public static void main(String[] args) {
try {
JavaIndent.justify("path/to/input.java", "path/to/output.java", 4);
} catch (FileNotFoundException ex) {
System.out.println("File not found...");
}
}
public static void justify(String inputFileName, String outputFileName,
int tabSize) throws FileNotFoundException {
String one_tab = "";
for (int i = 0; i < tabSize; i++) {
one_tab += " ";
}
Scanner input = new Scanner(new File(inputFileName));
PrintStream out = new PrintStream(new File(outputFileName));
JavaIndent.justifyRecursion(one_tab, "", input, out);
}
private static String justifyRecursion(String base_tab, String tab, Scanner input, PrintStream out) {
String line;
boolean flag_open, flag_close, flag_comment, flag_empty;
while (input.hasNextLine()) {
line = input.nextLine().trim();
flag_open = JavaIndent.contains(line, "{");
flag_close = JavaIndent.contains(line, "}");
flag_empty = line.length() == 0;
flag_comment = (flag_empty) ? false : line.charAt(0) == '/';
if (flag_comment || flag_empty) {
out.println(tab + line);
} else if (flag_close) {
return line;
} else if (flag_open) {
out.println(tab + line + "ENTERED OPEN");
line = JavaIndent.justifyRecursion(base_tab, tab + base_tab, input, out);
out.println(tab + line);
// Handles statements like } else { and sequences of these.
flag_open = JavaIndent.contains(line, "{");
while (flag_open) {
line = JavaIndent.justifyRecursion(base_tab, tab + base_tab, input, out);
out.println(tab + line);
flag_open = JavaIndent.contains(line, "{");
}
} else {
// Just a regular line, nothing special
out.println(tab + line);
}
}
return "";
}
private static boolean contains(String line, String sequence) {
String current = "";
char ch, last_ch = ' ';
int count_quotation = 0;
ArrayList<String> code_without_strings = new ArrayList<>();
for (int k = 0; k < line.length(); ++k) {
ch = line.charAt(k);
if (ch == '"' && count_quotation == 0 && last_ch != '\'') {
code_without_strings.add(current);
current = "";
++count_quotation;
} else if (ch == '"' && count_quotation == 1) {
if (last_ch != '\\') {
count_quotation = 0;
}
}
if (count_quotation == 0) {
current += ch;
}
last_ch = ch;
}
code_without_strings.add(current);
for (String code : code_without_strings) {
if (code.contains(sequence))
return true;
}
return false;
}
}
However, one still needs to consider statements such as this:
if (condition)
System.out.println("This should be indented, but it won't be...");
and this:
/**
* This is just a comment, but the program will indent from here on {.
*/
Try using JavaIndent to indent JavaIndent.java and verify that at the very end you will get
if (code.contains(sequence))
return true;
instead of
if (code.contains(sequence))
return true;

How can I ignore comments statements /*.....*/ when i reading java file?

How can i ignore the comment statements that begin with "/*" and ends with
"*/" for example: /*the problem is..*/ or
/* problem is very difficult */ ,,i want to remove these statement when i reading java file line by line
public class filename1 {
public static void main (String args[])
{
try {
fileName = "C:\\NetBeansProjects\\filename\\src\\filename\\filename.java";
FileReader fr = new FileReader(fileName);
BufferedReader br = new BufferedReader(fr);
line = br.readLine();
while (line !=null) {
for( int i=0;i<line.length();i++)
{
b=line.indexOf("/",i);
ee=line.indexOf("*",i);
if(b!=-1 && ee!=-1)
v=line.indexOf("*/",i);
if (v==-1)
line=" ";
}
System.out.println(line);
line = br.readLine();
}}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Simply include:
int index = str.indexOf("/*");
while(index != -1) {
str = str.substring(0, index) + str.substring(str.indexOf("*/")+2);
index = str.indexOf("/*");
}
Edit:
Assuming that you have to account for fragments where you have a comment interrupted by the start or end of the string:
Edit2:
Now.. Also assuming that you have to take into account for literal string "/*" or "*/"
str = str.replace("\"/*\"", "literal_string_open_comment");
str = str.replace("\"*/\"", "literal_string_close_comment");
int start = str.indexOf("/*"), end = str.indexOf("*/");
while(start > -1 || end > -1) {
if(start != -1) {
if(end != -1) {
if(end < start) {
str = str.substring(end+2);
} else {
str = str.substring(0, start) + str.substring(end+2);
}
} else {
str = str.substring(0, start);
}
} else {
str = str.substring(end+2);
}
start = str.indexOf("/*");
end = str.indexOf("*/");
}
str = str.replace("literal_string_open_comment", "\"/*\"");
str = str.replace("literal_string_close_comment", "\"*/\"");

Java: Alternative to BufferedReader

I'm having issues with BufferedWriter/BufferedReader.
Basically, whenever I try to read a file with BufferedReader.readLine() it reads everything up to the new line character (i.e. The new line character is omitted).
For instance:
String temp;
File f = new File(path.toURI());
BufferedReader reader = new BufferedReader(new FileReader(f));
while ((temp = reader.readLine()) != null) {
//Work with temp
}
I know about the existence of BufferedReader#newLine(), but it appears that it does not exactly get the newline (delimiter?) that was previously omitted.
From my understanding if I were to readline the following:
abcd\n
efgh\r\n
ijkl\r
It will return:
abcd\n
efgh\n
ijkl\n
What I am asking is, is there any class that is able to read characters without omitting them like BufferedInputStream, while retaining the ability to read line like BufferedReader#readLine()
\n is a linux/unix line ending while \r\n is windows line ending.
if there is such a file that has both line ending it should be reformatted.
My suggestion would be if you ever come across such file, just reformat it to either use \n or \r\n (depending on your OS not that it matter nowadays). it makes your life easier so the life of the next person that is going to use it next.
Alternatively (please don't use this :/) you can override BufferReader.readLine(Boolean b) to this:
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
bufferLoop:
for (;;) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) { /* EOF */
if (s != null && s.length() > 0){
if(skipLF=='\r'){
return s.toString() + "\r\n";
}else{
return s.toString() + "\n";
}
}
else
return null;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '\n', if necessary */
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
if(skipLF=='\r'){
return str + "\r\n";
}else{
return str + "\n";
}
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
SOURCE CODE edited from:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/io/BufferedReader.java#BufferedReader.readLine%28boolean%29
It probably won't be too much trouble to extend BufferedReader to include a \n or \r in the return from readLine(). In fact, the package-protected readLine(boolean ignoreLF) function is all you'd need to override:
Reads a line of text. A line is considered to be terminated by any one
of a line feed ('\n'), a carriage return ('\r') delimiter in the result, or a carriage return
followed immediately by a linefeed.
Parameters: ignoreLF If true, the
next '\n' will be skipped
Returns: A String containing the contents of
the line, not including any line-termination characters, or null if
the end of the stream has been reached
Throws: IOException If an I/O
error occurs
See also: LineNumberReader.readLine()
One solution could be to extend from BufferedReader and override the readLine() method (as it was already proposed in other answers).
Take this simplified example only as a PoC.
class MyReader extends BufferedReader {
int size = 8192;
public MyReader(Reader in) {
super(in);
}
public MyReader(Reader in, int sz) {
super(in, sz);
this.size = sz;
}
#Override
public String readLine() throws IOException {
StringBuilder sb = new StringBuilder(this.size);
for (int read = super.read(); read >= 0 && read != '\n'; read = super.read()) {
sb.append((char) read);
}
// in case you want also to preserve the line feed character
// sb.append('\n');
return sb.toString();
}
}
.
public class MyReaderDemo{
public static void main(String[] args) throws FileNotFoundException, IOException {
String text = "abcd\n"
+ "efgh\r\n"
+ "ijkl\r";
ByteArrayInputStream bis = new ByteArrayInputStream(
text.getBytes(StandardCharsets.ISO_8859_1)
);
// BufferedReader in = new BufferedReader(new InputStreamReader(bis));
BufferedReader in = new MyReader(new InputStreamReader(bis));
System.out.println(Arrays.toString(in.readLine().getBytes()));
System.out.println(Arrays.toString(in.readLine().getBytes()));
System.out.println(Arrays.toString(in.readLine().getBytes()));
}
}
output with BufferedReader
[97, 98, 99, 100]
[101, 102, 103, 104]
[105, 106, 107, 108]
output with MyReader
[97, 98, 99, 100]
[101, 102, 103, 104, 13]
[105, 106, 107, 108, 13]

java.util.NoSuchElementException: No line found*

I keep getting this error
java.util.NoSuchElementException No line found
when I use this method
public boolean hasMoreCommands() {
if (input.hasNextLine()) {
return true;
} else {
//input.close();
return false;
}
}
public void advance() {
String str;
if(hasMoreCommands() == true){
do {
str = input.nextLine().trim();
// Strip out any comments
if (str.contains("//")) {
str = (str.substring(0, str.indexOf("//"))).trim();
}
} while (str.startsWith("//") || str.isEmpty() || hasMoreCommands());
command = str;
}
}
I have main code here:
public class Ptest
{
public Ptest(String fileName)
{
String line = null;
String nName = fileName.replace(".vm", ".asm");
Parser p = new Parser();
try{
File neF = new File(nName);
if(!neF.exists()){
neF.createNewFile();
}
File tempFile = new File("temp.txt");
if(!tempFile.exists()){
tempFile.createNewFile();
}
FileReader fr = new FileReader(fileName);
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter(nName);
BufferedWriter bw = new BufferedWriter(fw);
FileWriter writR = new FileWriter(tempFile);
BufferedWriter buffR = new BufferedWriter(writR);
while((line = br.readLine()) != null) {
buffR.write(line+ "\n");
//System.out.println(line);
}
buffR.flush();
buffR.close();
p.insertTitle(tempFile);
String ctype = p.commandType();
int len = ctype.length();
int spaces = 13 - len;
String sp = " ";
String asp = " ";
String a1 = null;
int a2;
int alen;
boolean t = false;
while(p.hasMoreCommands()){
for(int i= 0; i < spaces; i++){
sp += " ";
}
t = p.hasMoreCommands();
a1 = p.arg1();
alen = (10 - a1.length());
for(int i= 0; i < alen; i++){
asp += " ";
}
//a2 = p.arg2();
if (ctype == "C_PUSH" || ctype == "C_POP" || ctype == "C_FUNCTION" || ctype == "C_CALL") {
a2 = p.arg2();
bw.write(ctype + sp + a1 + asp + a2);
}
else {
bw.write(ctype + sp + a1);
}
p.advance();
ctype = p.commandType();
len = ctype.length();
spaces = 13 - len;
}
bw.flush();
bw.close();
}
catch(FileNotFoundException ex){
System.out.println("File not found!");
}
catch(IOException ex){
System.out.println("Error reading file '" + fileName + "'");
}
}
}
I went through debugger and it literally goes the entire file then gives me an error when its finished.
Like #hfontanez I think your problem is in this code:
if(hasMoreCommands() == true){
do {
str = input.nextLine().trim();
// Strip out any comments
if (str.contains("//")) {
str = (str.substring(0, str.indexOf("//"))).trim();
}
} while (str.startsWith("//") || str.isEmpty() || hasMoreCommands());
command = str;
}
However, my solution is to change the while clause to while (str.isEmpty() && hasMoreCommands());
I'm assuming that "advance" ought to return the next non-comment / blank line.
If the string from the previous pass is empty (after stripping any comment) it will go round the loop again provided that wasn't the last line. But, if that was the last line or str still has something in it, then it will exit the loop. Comments should have been stripped so don't need tested for in the while.
I think if you just test for hasNextLine within the loop then it will never exit the loop if the last line was comment / blank.
My guess is that your problem is here:
if(hasMoreCommands() == true){
do {
str = input.nextLine().trim();
// Strip out any comments
if (str.contains("//")) {
str = (str.substring(0, str.indexOf("//"))).trim();
}
} while (str.startsWith("//") || str.isEmpty() || hasMoreCommands());
command = str;
}
The exception you encountered (NoSuchElementException) typically occurs when someone tries to iterate though something (String tokens, a map, etc) without checking first if there are any more elements to get. The first time the code above is executed, it checks to see if it has more commands, THEN it gets in a loop. The first time it should work fine, however, if the test done by the while() succeeds, the next iteration will blow up when it tries to do input.nextLine(). You have to check is there is a next line to be got before calling this method. Surround this line with an if(input.hasNextLine()) and I think you should be fine.

Categories