I have written the following program to read from a file and skip comments, it works for single line comments, but not for multi line ones. Does anyone know why? I don't need to worry about "//" in Strings. And only java comments ie "//" and "/* */"
code:
import java.io.*;
public class IfCounter2
{
public static boolean lineAComment(String line)
{
if (line.contains("//"))
return true;
return false;
}
public static boolean multiLineCommentStart(String line)
{
if (line.contains("/*"))
return true;
return false;
}
public static boolean multiLineCommentEnd(String line)
{
if (line.contains("*/"))
return true;
return false;
}
public static void main(String[] args) throws IOException
{
String fileName = args[0];
int numArgs = args.length;
int ifCount = 0;
// create a new BufferReader
BufferedReader reader = new BufferedReader(new FileReader(fileName));
String line = null;
StringBuilder stringBuilder = new StringBuilder();
String ls = System.getProperty("line.separator");
line = reader.readLine();
// read from the text file
boolean multiLineComment = false;
while (( line = reader.readLine()) != null)
{
if (!multiLineCommentStart(line))
{
multiLineComment = true;
}
if (multiLineComment) {
if (!multiLineCommentEnd(line))
{
multiLineComment = false;
}
}
if (!lineAComment(line) && !multiLineComment)
{
stringBuilder.append(line);
stringBuilder.append(ls);
}
}
// create a new string with stringBuilder data
String tempString = stringBuilder.toString();
System.out.println(stringBuilder.toString());
}
}
You only set multiLineComment to true when !multiLineCommentStart(line) is true - that is, whenever the line does not contain /*.
Basically, your code should look sth like this (untested)
boolean multiLineComment = false;
while (( line = reader.readLine()) != null)
{
if (multiLineCommentStart(line))
{
multiLineComment = true;
}
if (multiLineComment) {
if (multiLineCommentEnd(line))
{
multiLineComment = false;
}
}
if (!lineAComment(line) && (multiLineComment == false))
{
stringBuilder.append(line);
stringBuilder.append(ls);
}
}
in that last if statement, you need to have an expression with your variable and a fixed
Andy's answer is right on the money but needs a validation in last if to make sure you are not counting */ as a valid line:
boolean multiLineComment = false;
while (( line = reader.readLine()) != null)
{
if (multiLineCommentStart(line))
{
multiLineComment = true;
}
if (multiLineComment) {
if (multiLineCommentEnd(line))
{
multiLineComment = false;
}
}
if (!lineAComment(line) && (multiLineComment == false) &&
!multiLineCommentEnd(line) )
{
stringBuilder.append(line);
stringBuilder.append(ls);
}
}
Related
I have this fast reader class:
static class FastReader {
BufferedReader br;
StringTokenizer st;
public FastReader() {
br = new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while (st == null || !st.hasMoreElements()) {
try {
st = new StringTokenizer(br.readLine());
}
catch (IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong() {
return Long.parseLong(next());
}
double nextDouble() {
return Double.parseDouble(next());
}
String nextLine() {
String str = "";
try {
str = br.readLine();
}
catch (IOException e) {
e.printStackTrace();
}
return str;
}
int[] readArray(int n) {
int[] a = new int[n];
for(int i=0; i<n; i++) {
a[i] = nextInt();
}
return a;
}
}
I want to stop reading input as soon as I reach end of file. I know this can be done using scanner hasNext() method, How can I implement the same method for my reader class?
PS. I want to read input for this question:
https://www.spoj.com/problems/COINS/
You can set a mark() then try to read a line, if it is successful you could reset() to where you set the mark and return true and false otherwise.
You would also have to check if the current tokenizer has more tokens left. For example:
boolean hasNext() {
if (st != null && st.hasMoreTokens()) {
return true;
}
String tmp;
try {
br.mark(1000);
tmp = br.readLine();
if (tmp == null) {
return false;
}
br.reset();
} catch (IOException e) {
return false;
}
return true;
}
mark() takes readAheadLimit argument to limit the number of characters that can be read while having that mark set, you could increase that if you're dealing with long lines.
You can cover your code in a while loop with the condition that the user input is not null.
Example:
BuffedReader br = new BufferedReader(new InputStreamReader(System.in);
String key = "";
while((key = br.readLine()) != null)
{
//your code
}
ADIF format is described here: http://www.adif.org/ I'm trying to make Adif parser. Here is portion of Adif file to be parsed:
ADIF 2 Export from eQSL.cc
Received eQSLs for IZ1080SWL
for QSOs between 10-Aug-2015 and 31-Dec-2035
Generated on Sunday, October 18, 2015 at 00:48:50 AM UTC
<PROGRAMID:21>eQSL.cc DownloadInBox
<ADIF_Ver:1>2
<EOH>
<CALL:6>RA1QEA<QSO_DATE:8:D>20150829<TIME_ON:4>0455<BAND:3>30m<MODE:2>CW<RST_SENT:3>SWL<RST_RCVD:0><QSL_SENT:1>Y<QSL_SENT_VIA:1>E<APP_EQSL_AG:1>Y<GRIDSQUARE:6>lo19aq<EOR>
<CALL:5>F6HKA<QSO_DATE:8:D>20150910<TIME_ON:4>0400<BAND:3>80m<MODE:2>CW<RST_SENT:3>swl<RST_RCVD:0><QSL_SENT:1>Y<QSL_SENT_VIA:1>E<QSLMSG:34>Thanks for the SWL report. 73 Bert<APP_EQSL_AG:1>Y<GRIDSQUARE:6>JN05ot<EOR>
<CALL:5>DL5ZL<QSO_DATE:8:D>20150912<TIME_ON:4>2229<BAND:3>30m<MODE:2>CW<RST_SENT:3>599<RST_RCVD:0><QSL_SENT:1>Y<QSL_SENT_VIA:1>E<QSLMSG:28>tks, paper qsl is on the way<APP_EQSL_AG:1>Y<GRIDSQUARE:6>JO51jl<EOR>
<CALL:5>4Z5ML<QSO_DATE:8:D>20150915<TIME_ON:4>0504<BAND:3>20m<MODE:2>CW<RST_SENT:3>599<RST_RCVD:0><QSL_SENT:1>Y<QSL_SENT_VIA:1>E<APP_EQSL_AG:1>Y<GRIDSQUARE:4>km72<EOR>
I try this parser:
public void read() throws IOException {
BufferedReader br = new BufferedReader(new FileReader(filePath));
int intValue;
boolean createToken = false;
boolean createSize = false;
StringBuffer token = new StringBuffer();
StringBuffer size = new StringBuffer();
Adif2Record record = new Adif2Record();
while ((intValue = br.read()) != -1) {
char cValue = (char)intValue;
if (cValue == '\n') {
continue;
}
if (cValue == '<') {
createToken = true;
continue;
}
if (cValue == ':') {
createToken = false;
createSize = true;
continue;
}
if (cValue == '>') {
if ("eor".equalsIgnoreCase(token.toString())) {
records.add(record);
record = new Adif2Record();
token.setLength(0);
size.setLength(0);
continue;
}
createSize = false;
createData(br, token.toString(), str2int(size.toString()), record);
size.setLength(0);
token.setLength(0);
}
if (createToken) {
token.append(cValue);
}
if (createSize) {
size.append(cValue);
}
}
}
but I end up only with one token "PROGRAMID" and the rest of file becomes data for this token. The portion before EOF token is a header and I would not like to slice it off completely but I don't understand why createSize is keeping true after PROGRAMID, according to idea it should reset to false after each loop. Can someone help?
You're missing logic to handle the header. Basically the header seems to be allowed to contain text including : which means you have to add a check, it a tag is being parsed to the case where you get a : char.
Furthermore you need to handle data types appropriately, since otherwise the type is simply appended to the size.
Also you should use StringBuilder instead of StringBuffer, since the latter also does synchronisation which just decreases the performance in this case without providing any benefits.
The following code also replaces some of the ifs with switch statements.
For simplicity it uses another record for the header data...
public static void createData(BufferedReader br, String token, int size, Adif2Record record) throws IOException {
StringBuilder sb = new StringBuilder(size);
for (int i = 0; i < size; i++) {
int c = br.read();
if (c == -1) {
throw new IOException("Unexpected end of input");
}
sb.appendCodePoint((char) c);
}
record.setData(token, sb.toString());
}
private List<Adif2Record> records = new ArrayList<>();
public void read() throws IOException {
BufferedReader br = new BufferedReader(new FileReader(filePath));
int intValue;
boolean createToken = false;
boolean createSize = false;
boolean createType = false;
StringBuilder token = new StringBuilder();
StringBuilder size = new StringBuilder();
Adif2Record record = new Adif2Record();
while ((intValue = br.read()) != -1) {
switch (intValue) {
case '\n':
break;
case '<':
createToken = true;
break;
case ':':
if (createToken) {
// not in header
createToken = false;
createSize = true;
} else if (createSize) {
createType = true;
createSize = false;
}
break;
case '>':
switch (token.toString().toLowerCase()) {
case "eor":
case "eoh":
records.add(record);
record = new Adif2Record();
break;
default:
createSize = false;
createType = false;
createData(br, token.toString(), str2int(size.toString()), record);
}
token.setLength(0);
size.setLength(0);
break;
default:
char cValue = (char) intValue;
if (createToken) {
token.append(cValue);
}
if (createSize) {
size.append(cValue);
}
if (createType) {
// TODO
}
}
}
}
private static int str2int(String s) {
return s.isEmpty() ? 0 : Integer.parseInt(s);
}
public class Adif2Record {
private final Map<String, String> data = new HashMap<>();
public void setData(String key, String value) {
data.put(key, value);
}
public Map<String, String> getData() {
return data;
}
}
I’m trying to print out the result from the readline method in a certain format. I also need to add two more if statements, but I’m not sure how to get the code to continue through them if the previous one is true.
public static void main(String[] args) {
String csvFile = args[0]; //name of our csv file
BufferedReader br = null;
String line = "";
String cvsSplitBy = ",";
String[] columns = new String[6];
String columnLine = "";
float notToBeBelow = 12;
try {
br = new BufferedReader(new FileReader(csvFile));
if ((columnLine = br.readLine()) != null) {
columns = columnLine.split(cvsSplitBy);
while ((line = br.readLine()) != null) {
// use comma as separator
String[] routerInfo = line.split(cvsSplitBy);
if (routerInfo[2].toLowerCase().equals("no")) {
float OSVersion = Integer.parseInt(routerInfo[3]);
if(OSVersion >= 12) {
}
}
You can do the following:
if (condition) {
} else {
if (condition2) {}
else {}
if (condition3) {}
else {}
}
You can place an if inside the else of another one.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
When i tried to run this program, it only show "Beginning of Read-in records list. But the program doesnt terminate, which means the program keep running, but it doesnt output anything. Could anyone please help?
public static void readFile(String fileName, PhoneBook book_list)
{
if(fileName == null) return;
File file = new File(fileName);
if(!file.isFile())
{
System.out.println("File not found!");
return ;
}
Person person = new Person();
boolean invalid = false;
System.out.println("\nInfo: Beginning of Read-in records list.\n");
try
{
BufferedReader input = new BufferedReader(new FileReader(file));
try
{
String line = "";
line = input.readLine();
while(line != null)
{
line = line.trim();
String[] words = line.split("\\s+");
if(invalid)
{
if(words[0].equals(""))
{
person = new Person();
invalid = false;
}
}
//refer to end of a record
else if(words[0].equals(""))
{
if(person.validation())
{
book_list.addPerson(person);
person = new Person();
}
else
{
person = new Person();
}
}
if(words[0].equalsIgnoreCase("name"))
{
if(words.length<2)
{
invalid=true;
}
else
{
String name = words[1];
for(int i=2; i<words.length;i++)
{
name = name + " " + words[i];
}
for(int i=0; i<name.length(); i++)
{
if((name.codePointAt(i) >= 97 && name.codePointAt(i) <= 122)/*a-z*/
|| (name.codePointAt(i) >= 65 && name.codePointAt(i) <= 90)/*A-z*/
|| name.codePointAt(i) == 32)/*space*/
{continue;}
else
{
invalid=true;
break;
}
}
if(!invalid)
{
person.setName(name);
}
}
}
else if(words[0].equalsIgnoreCase("birthday"))
{
if(words.length !=2)
{
invalid=true;
}
else
{
try
{
person.setBirthday(words[1]);
book_list.addPerson(person);
}
catch (ParseException e)
{
invalid = true;
}
}
}
else if(words[0].equalsIgnoreCase("phone"))
{
if(words.length != 2)
{
invalid = true;
}
else
{
String phone = Tools.parsePhone(words[1]);
if(phone!=null)
{
person.setPhone(phone);
}
else
{
invalid = true;
}
}
}
else if(words[0].equalsIgnoreCase("email"))
{
if(words.length != 2)
{
invalid = true;
}
else
{
if(Tools.validateEmail(words[1]))
{
person.setEmail(words[1]);
}
else
{
invalid = true;
}
}
}
else if(words[0].equalsIgnoreCase("address"))
{
String address = line.substring(words[0].length()).trim();
String addr="";
do
{
line = input.readLine();
if(line == null)
{
person.setAddress(address);
}
if(!invalid && person.validation())
{
book_list.addPerson(person);
}
addr = line.trim();
String[] adds = addr.split("\\s+");
if(!adds[0].equals("")
&& !adds[0].equalsIgnoreCase("name")
&& !adds[0].equalsIgnoreCase("birthday")
&& !adds[0].equalsIgnoreCase("phone")
&& !adds[0].equalsIgnoreCase("email")
&& !adds[0].equalsIgnoreCase("address"))
{
address = address + " " + addr;
}
else break;
}
while(true);
if(line == null)
break;
}
}// end of while loop
}
finally
{
input.close();
}
}
catch(IOException ex)
{
System.err.print("Error: Open records file failed");
return;
}
System.out.println("\nInfo: End of Read-in records list.\n");
return;
}
public static void main(String[] args)
{
String personFile = null; // person contact information file
String instFile = null; //instruction file
String outputFile = null; //output file name;
String reportFile = null; //report file name;
PhoneBook book_list = new PhoneBook();
FileIO2.readFile("C:/Users/phoenix/Desktop/sample_phonebook1.txt", book_list);
ArrayList<Person> a;
a = book_list.getPersonList();
System.out.println(a.size());
}
I think your problem is here:
// initializes "line" String
String line = "";
// Tells BufferedReader to read one line (the first line)
line = input.readLine();
// loops infinitely since String read from first line is not null in this specific case
while(line != null)
{
...
Try this:
// initializes "line" String
String line = "";
// tells the BufferedReader to read a new line _until_ the new line is null
// ... if new line is null we reached EOF
while ((line = input.readLine() != null) {
...
You should do:
String line = null;
while ((line = input.readLine()) != null) {
...
...
}
Instead of:
String line = "";
line = input.readLine();
while(line != null){
...
...
}
Keep reading files. Cheers! :P
You have used while & do..while loop..
And you are not reading file properly
after do..while you should include line = input.readLine()
I have created CSVReader and I am trying to read csv file from assets for that reason I should use InputStream. But my code below does not have inputstream constructor. Could anyone tell me how i could add or change something in code, so I can use inputstream.
public class CSVReader {
private BufferedReader br;
private boolean hasNext = true;
private char separator;
private char quotechar;
private int skipLines;
private boolean linesSkiped;
public int linesCount = 0;
public static final char DEFAULT_SEPARATOR = '|';
public static final char DEFAULT_QUOTE_CHARACTER = '"';
public static final int DEFAULT_SKIP_LINES = 0;
public CSVReader(Reader reader) {
this(reader, DEFAULT_SEPARATOR, DEFAULT_QUOTE_CHARACTER,
DEFAULT_SKIP_LINES);
}
public CSVReader(Reader reader, char separator, char quotechar, int line) {
this.br = new BufferedReader(reader);
this.separator = separator;
this.quotechar = quotechar;
this.skipLines = line;
}
public String[] readNext() throws IOException {
String nextLine = getNextLine();
return hasNext ? parseLine(nextLine) : null;
}
public String getNextLine() throws IOException {
if (!this.linesSkiped) {
for (int i = 0; i < skipLines; i++) {
br.readLine();
}
this.linesSkiped = true;
}
String nextLine = br.readLine();
if (nextLine == null) {
hasNext = false;
}
return hasNext ? nextLine : null;
}
public List<String[]> readAll() throws IOException {
List<String[]> allElements = new ArrayList<String[]>();
while (hasNext) {
String[] nextLineAsTokens = readNext();
if (nextLineAsTokens != null)
allElements.add(nextLineAsTokens);
}
return allElements;
}
private String[] parseLine(String nextLine) throws IOException {
if (nextLine == null) {
return null;
}
List<String> tokensOnThisLine = new ArrayList<String>();
StringBuffer sb = new StringBuffer();
boolean inQuotes = false;
do {
if (inQuotes) {
// continuing a quoted section, reappend newline
sb.append("\n");
nextLine = getNextLine();
linesCount++;
if (nextLine == null)
break;
}
for (int i = 0; i < nextLine.length(); i++) {
char c = nextLine.charAt(i);
if (c == quotechar) {
if( inQuotes
&& nextLine.length() > (i+1)
&& nextLine.charAt(i+1) == quotechar ){
sb.append(nextLine.charAt(i+1));
i++;
}else{
inQuotes = !inQuotes;
if(i>2
&& nextLine.charAt(i-1) != this.separator
&& nextLine.length()>(i+1) &&
nextLine.charAt(i+1) != this.separator
){
sb.append(c);
}
}
} else if (c == separator && !inQuotes) {
tokensOnThisLine.add(sb.toString());
sb = new StringBuffer();
} else {
sb.append(c);
}
}
} while (inQuotes);
tokensOnThisLine.add(sb.toString());
return (String[]) tokensOnThisLine.toArray(new String[0]);
}
public void close() throws IOException{
br.close();
}
}
You can construct an InputStreamReader from that InputStream
new InputStreamReader(myInputStream, encoding)
Where myInputStream is your InputStream and encoding is a String that defines the encoding used by your datasource.
You can call your CSVReader like this:
new CSVReader(new InputStreamReader(myInputStream, encoding));