finding the number of occurrences for a specific char using recursion - java

This code below is part of a program, that will find the number of occurrences of the input character in a text file
public static void main(String[] args){
[...]
java.io.File file1=new java.io.File(dirPath1);
FileInputStream fis = new FileInputStream(file1);
System.out.println(" return "+rec(sc.next().charAt(0),fis));
}
public static int rec (char ch, FileInputStream fis)throws IOException{
char current=0;
if(fis.available()==0){
return 0;
}
if(fis.read()!=-1){
current = (char) fis.read();
}
if(current==ch) {
return 1+rec(ch,fis);
}else
return rec(ch,fis);
}
}
The problem is:
If the file has one character, and ch=that one character. it returns 0, when I traced the code I found that it doesn't enter if(current==ch). Although, they are the same char.
if there is more than on character,strings some of them-the matches chars- will enter if block and others won't.
How can I fix this ?
Is there another way to find the number of occurrences recursively ?
another question: should I use try and catch in rec method to catch IOException ?
Thanks in advance
P.S. this program is from assignment,I have to use recursion and compare it with iteration.

you call fis.read() twice first one read first character and second one read nothing
this is your answer
public static int rec(char ch, FileInputStream fis) throws IOException {
char current = 0;
if (fis.available() == 0) {
return 0;
}
int read = fis.read();
if (read != -1) {
current = (char) read;
}
if (current == ch) {
return 1 + rec(ch, fis);
}
else
return rec(ch, fis);
}

My suggestion would be as follows:
Read the whole text file into a java.lang.String
Then use the library Apache Commons Lang and use this method for counting the occurrences:
http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#countMatches-java.lang.CharSequence-java.lang.CharSequence-

You should use FileReader to read chars from text file.
Reader reader = new FileReader("MyFile.txt");
I think using while ((i=reader.read()) != -1) is a better approach instead of three if and an else.
So you can achieve this with fewer lines of code:
public static int rec (char ch, Reader reader)throws IOException{
char current=0;
int i;
while ((i=reader.read()) != -1) {
current = (char) i;
if(current==ch) {
return 1+rec(ch,reader);
}else
return rec(ch,reader);
}
return 0;
}
I think there is no need to use try and catch in rec method to catch IOException. I have used it here:
try {
Reader reader = new FileReader("MyFile.txt");
System.out.println(" return " + rec('a', reader));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Related

Read last n lines in reverse order

I am trying to read last n lines of a file in reverse order. Is this the most efficient way to do it? My file is not big but it could eventually grow to several GB. Also, I am trying to read last 10 lines but this one only returns last 9. Anything I am missing?
// Read n lines from the end of the file
public void readFromLast(File file, int lines) {
int readLines = 0;
StringBuilder builder = new StringBuilder();
RandomAccessFile randomAccessFile = null;
try {
randomAccessFile = new RandomAccessFile(file, "r");
long fileLength = file.length() - 1;
// Set the pointer at the last of the file
randomAccessFile.seek(fileLength);
for (long pointer = fileLength; pointer >= 0; pointer--) {
randomAccessFile.seek(pointer);
char c = (char) randomAccessFile.read();
builder.append(c);
if(c == '\n'){
builder = builder.reverse();
System.out.print(builder.toString());
readLines++;
builder = null;
builder = new StringBuilder();
if (readLines == lines + 1){
break;
}
}
}
} catch (FileNotFoundException e) {
log.info("FileNotFound " +e.getMessage()+ "occured while reading last n lines");
e.printStackTrace();
} catch (IOException e) {
log.info("IOException" + e.getMessage() +" occured while reading last n lines");
} finally {
if (randomAccessFile != null) {
try {
randomAccessFile.close();
} catch (IOException e) {
log.info("IOException" + e.getMessage() +" occured while closing the file reading last n lines");
}
}
}
}
Your code is fine. I am pretty sure it is reading 1 more line than it should, not 1 less. You are probably reading file that does not have enough lines?
If you want to correct it remove +1 from if (readLines == lines + 1){ and it will be fine.
Also a tip instead of setting StringBuilder to null and creating it again you can use
bulder.setLength(0);
it is a bit cleaner

How to put read and cast into a char array

I have a source txt file and I am trying to read the characters using the .read() method of the FileReader class. I have got the integer values that come out the .read and cast them to char and looped the output to check this is working. The problem is that when I try to store them in an array, the array prints empty.
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReversedQuotation {
public static void main(String[] args) {
char[] charArray = new char[1000];
char[] sortedQuote = new char[1000];
int counter = 999;
int secondCounter = 0;
FileReader fr = null;
try {
fr = new FileReader("/Users/cal/Desktop/backwards.txt");
while(true) {
try {
int charInt = fr.read();
if(charInt == -1) break;
charArray[counter] = (char)charInt;
counter--;
System.out.print(charArray[counter]);
System.out.print((char)charInt); // just to check the characters are correct.
charArray[counter] = sortedQuote[secondCounter];
secondCounter++;
System.out.print(sortedQuote[secondCounter]);
}
catch (IOException e) {
System.out.println("IO Error in reading document");
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
System.out.println("Error finding document.");
} finally {
try {
fr.close();
} catch(IOException e) {
System.out.println("Error in closing the File Reader.");
}
}
}
}
First:
charArray[counter] = (char)charInt; // say counter = 999
counter--;
System.out.print(charArray[counter]); // charArray[998]
This will print the value at decremented index(which is essentially empty) and not the assigned index.
charArray[counter] = (char)charInt;
System.out.print(charArray[counter]);
counter--;
This should print what you have assigned.
Second:
sortedQuote[secondCounter] is never assigned and
charArray[counter] = sortedQuote[secondCounter] assignment seems to have no purpose.

Why isn't my array filled correctly?

I am writing code for a game in Java. Specificly I'm working on the level creation using a character array filled by characters from a .txt file. My problem is that the array is not filled as it should be and the final line remains empty. I can't work this out so any kind of help will be gladly accepted, here's the problematic block of code :
public static void main(String[] args) throws IOException{
char background[][] = new char [14][20];
try {
FileInputStream fileinput = new FileInputStream("background.txt");
int r;
for(int i=0;i<=13;i++){
for(int j=0;j<19;j++){
while((r = fileinput.read()) != -1){
char c = (char) r;
background[i][j] = c;
break;
}
}
}
fileinput.close();
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i=0;i<=13;i++){
for(int j=0;j<=19;j++){
System.out.print(background[i][j]);
}
}
}
Also the code as a whole can be found in the following link: http://pastebin.com/HtwMpsjm
Here's the .txt file too!
You accidentally one of your conditions, i've commented on the changed line.
As someone has mentioned in the comments, you might find it beneficial to treat your loops conditions as for(int i=0;i<20;i++) rather than for(int i=0i<=19;i++) it makes the code a little more readable.
public static void main(String[] args) throws IOException{
char background[][] = new char [14][20];
try {
FileInputStream fileinput = new FileInputStream("background.txt");
int r;
for(int i=0;i<=13;i++){
for(int j=0;j<=19;j++){//<<THIS LINE WAS CHANGED
while((r = fileinput.read()) != -1){
char c = (char) r;
background[i][j] = c;
break;
}
}
}
fileinput.close();
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i=0;i<=13;i++){
for(int j=0;j<=19;j++){
System.out.print(background[i][j]);
}
}
}
Why do we need multiple for loops here. If you want to read characters from a file you could use buffered reader and the this matrix could be created in one line of code like while((bufferedReader.read(background[i]) != -1) && (++i < 14)){ }. Also you are using a while loop to read one char and then an unconditional break statment inside is not a good practice (in my opinion). Try
public static void main(String[] args) throws IOException {
char background[][] = new char[14][20];
try {
FileReader fileReader = new FileReader("background.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
int i=0;
while((bufferedReader.read(background[i]) != -1) && (++i < 14)){ } // This like created your 2D array
bufferedReader.close();
fileReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
for (int i = 0; i <= 13; i++) {
for (int j = 0; j <= 19; j++) {
System.out.print(background[i][j]);
}
}
}

How to convert binary text into useable file

So I use the following methods
(File is converted to Byte Array through 'convertFileToByteArray()', then written to .txt file by 'convertByteArrayToBitTextFile()'
to convert any kind of file into a Binary Text file (and by that I mean only 1's and 0's in human readable form.)
public static byte[] convertFileToByteArray(String path) throws IOException
{
File file = new File(path);
byte[] fileData;
fileData = new byte[(int)file.length()];
FileInputStream in = new FileInputStream(file);
in.read(fileData);
in.close();
return fileData;
}
public static boolean convertByteArrayToBitTextFile(String path, byte[] bytes)
{
String content = convertByteArrayToBitString(bytes);
try
{
PrintWriter out = new PrintWriter(path);
out.println(content);
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static String convertByteArrayToBitString(byte[] bytes)
{
String content = "";
for (int i = 0; i < bytes.length; i++)
{
content += String.format("%8s", Integer.toBinaryString(bytes[i] & 0xFF)).replace(' ', '0');
}
return content;
}
Edit: Additional Code:
public static byte[] convertFileToByteArray(String path) throws IOException
{
File file = new File(path);
byte[] fileData;
fileData = new byte[(int)file.length()];
FileInputStream in = new FileInputStream(file);
in.read(fileData);
in.close();
return fileData;
}
public static boolean convertByteArrayToBitTextFile(String path, byte[] bytes)
{
try
{
PrintWriter out = new PrintWriter(path);
for (int i = 0; i < bytes.length; i++)
{
out.print(String.format("%8s", Integer.toBinaryString(bytes[i] & 0xFF)).replace(' ', '0'));
}
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static boolean convertByteArrayToByteTextFile(String path, byte[] bytes)
{
try
{
PrintWriter out = new PrintWriter(path);
for(int i = 0; i < bytes.length; i++)
{
out.print(bytes[i]);
}
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static boolean convertByteArrayToRegularFile(String path, byte[] bytes)
{
try
{
PrintWriter out = new PrintWriter(path);
for(int i = 0; i < bytes.length; i++)
{
out.write(bytes[i]);
}
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static boolean convertBitFileToByteTextFile(String path)
{
try
{
byte[] b = convertFileToByteArray(path);
convertByteArrayToByteTextFile(path, b);
return true;
}
catch (IOException e)
{
return false;
}
}
I do this to try methods of compression on a very fundamental level, so please let's not discuss why use human-readable form.
Now this works quite well so far, however I got two problems.
1)
It takes foreeeever (>20 Minutes for 230KB into binary text). Is this just a by-product of the relatively complicated conversion or are there other methods to do this faster?
2) and main problem:
I have no idea how to convert the files back to what they used to be. Renaming from .txt to .exe does not work (not too surprising as the resulting file is two times larger than the original)
Is this still possible or did I lose Information about what the file is supposed to represent by converting it to a human-readable text file?
If so, do you know any alternative that prevents this?
Any help is appreciated.
The thing that'll cost you most time is the construction of an ever increasing String. A better approach would be to write the data as soon as you have it.
The other problem is very easy. You know that every sequence of eight characters ('0' or '1') was made from a byte. Hence, you know the values of each character in an 8-character block:
01001010
^----- 0*1
^------ 1*2
^------- 0*4
^-------- 1*8
^--------- 0*16
^---------- 0*32
^----------- 1*64
^------------ 0*128
-----
64+8+2 = 74
You only need to add the values where an '1' is present.
You can do it in Java like this, without even knowing the individual bit values:
String sbyte = "01001010";
int bytevalue = 0;
for (i=0; i<8; i++) {
bytevalue *= 2; // shifts the bit pattern to the left 1 position
if (sbyte.charAt(i) == '1') bytevalue += 1;
}
Use StringBuilder to avoid generating enormous numbers of unused String instances.
Better yet, write directly to the PrintWriter instead of building it in-memory at all.
Loop through every 8-character subsequence and call Byte.parseByte(text, 2) to parse it back to a byte.

logic help for creating csv files from plain text file

Actually I had a .rtf file and from that I was trying to create a csv file. While searching I saw that I have convert it into plain text and then to csv file. But right now I am kind of stuck with logic. I am not getting idea what to apply to move forward.
I have below data which I want to convert to csv.
Input :
Search Target Redmond40_MAS Log Written 01/18/2013 9:13:19 Number of attempts 1
Search Target Redmond41_MAS Log Written 01/19/2013 9:15:16 Number of attempts 0
Output :
Search Target,Log Written,Number of attempts
Redmond40_MAS,01/18/2013 9:13:19,1
Redmond41_MAS,01/19/2013 9:15:16,0
If there was any delimiter then I would have done it but in this case I know are the "keys" i.e. header values but not getting the idea how to extract corresponding contents.
Any suggestion will help.
import java.io.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.rtf.RTFEditorKit;
public class Rtf2Csv {
public static void main(String[] args) {
RTFEditorKit rtf = new RTFEditorKit();
Document document = rtf.createDefaultDocument();
try {
FileInputStream fi = new FileInputStream("test.rtf");
rtf.read(fi, document, 0);
} catch (FileNotFoundException e) {
System.out.println("File not found");
} catch (IOException e) {
System.out.println("I/O error");
} catch (BadLocationException e) {
}
String output = "Search Target,Log Written,Number of attempts";
try {
String text = document.getText(0, document.getLength());
text = text.replace('\n', ' ').trim();
String[] textHeaders = text
.split("===================================================================================");
String[] header = { "Search Target", "Log Written",
"Number of attempts"};
System.out.println(textHeaders.length);
int headLen = header.length;
int textLen = textHeaders.length;
for (int i = 0; i < textLen; i++) {
String finalString = "";
String partString = textHeaders[i];
for (int j = 0; j < headLen; j++) {
int len = header[j].length();
if (j + 1 < header.length)
finalString += partString.substring(
partString.indexOf(header[j]) + len,
partString.indexOf(header[j + 1])).trim()
+ ",";
else
finalString += partString.substring(
partString.indexOf(header[j]) + len).trim();
}
output += "\n" + finalString;
}
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
FileWriter writer = new FileWriter("output.csv");
writer.append(output);
writer.flush();
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I have written this code. Is there any better way to improve it?
If you are sure it is fixed width, then just calculate the length of the fields. Otherwise, I would recommend writing a simple parser. You might get lucky with the correct regular expression, but from my experience this can be a lot of trail and error.
It should not be too hard to parse it...
I would suggest using Scanner or StringTokenizer. There is an in depth explanation here:
Scanner vs. StringTokenizer vs. String.Split
Something like this should do it:
StringTokenizer s = new StringTokenizer("Search Target Redmond40_MAS Log Written 01/18/2013 9:13:19 Number of attempts 1"
);
String out = new String();
while (s.hasMoreTokens()) {
out = s.nextToken() + "," + out ;
}
If the columns you are interested in are of a fixed width, you may open the txt file in Excel and place column dividers where desired.
It would be simple to export from Excel as a csv.
If you want to read it in line by line you can use something like this:
public int countLines(File inFile)
{
int count = 0;
Scanner fileScanner = new Scanner(inFile);
while(fileScanner.hasNextLine()) //if you are trying to count lines
{ //you should use hasNextLine()
fileScanner.nextLine() //advance the inputstream
count++;
}
return count;
}
Does this answer your question?

Categories