I'm working on a project for university and I'm having some problems when it comes to understand how does a class with a method to read given by our professor works.
We are supposed to be able to use that method to read words in lines from a text file. However, I don't really understand how it works. If anyone could help me, as well as explaining to me how can I use it to read the files, I'd be so grateful.
Here's the class with the method called read() as well as the methods and variables used by it :
public static final char blank = ' ';
public static final char endOfSequence = '\n'; //the lines in the file end with '\n'
private static final int MAX = 20;
public static char[] letters;
public static int length;
private static char letter = ' ';
private static char[] phrase = null;
private static int index;
public Word() {
letters = new char[MAX];
length = 0;
}
public static Word read() {
Word wd = new Word();
jumpBlanks();
while ((letter != endOfSequence) && // Sequence hasn't finished
(letter != blank)) {
wd.letters[wd.length] = letter;
letter = readCharKeyB();
}
return wd;
}
public static void jumpBlanks() { //reading blanks until finding a word
while (letter == blank) {
letter = readCharKeyB();
}
}
static public char readCharKeyB() {
char res = '.';
if (phrase != null) {
res = phrase[index++];
}
return res;
}
I have to use it, as I said, to read lines from a file that looks like this:
t1 #n name #d address
t2 #n name #d address
...
I have to check first how the line starts (t1, t2, t3) then I have to read the name, between #n and #d, and then the address, between #d and \n. And I have to use that class above with those methods.
This is what I have so far, but doesn't work:
public static void generador_de_cartas() throws Exception {
FileReader fr = new FileReader("datos_clientes.txt");
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
char [] linea = line.toCharArray();
while (line != null){
linea=Word.leer(); //I don't know how to use it properly
line=br.readLine();
}
br.close();
fr.close();
}
Please, could someone explain to me how the method works and how can I make it work for reading a file so I can figure out how to use it?
Thanks!
Related
and thank you for helping me.
So my question is i need a code that asks you for a String like "1234 567" (input), then returns the string numbers like "1 2 3 4 5 6 7" (output) once more
my current code is:
public class StringComEspaços {
public static String formatNumberWithSpaces(String inputString) {
String outputString = "222";
return outputString;
}
public static void main(String[] args) {
System.out.println(formatNumberWithSpaces("123 222 2222"));
}
}
thanks for the help, and sorry for bad english :).
There are many possible ways to solve your problem.
You can do it in an OO way with StringBuilder:
public static String formatNumberWithSpaces(String inputString) {
StringBuilder output = new StringBuilder();
for (char c : inputString.toCharArray()) // Iterate over every char
if (c != ' ') // Get rid of spaces
output.append(c).append(' '); // Append the char and a space
return output.toString();
}
Which you can also do with a String instead of the StringBuilder by simply using the + operator instead of the .append() method.
Or you can do it a more "modern" way by using Java 8 features - which in my opinion is fun doing, but not the best way - e.g. like this:
public static String formatNumberWithSpaces(String inputString) {
return Arrays.stream(input.split("")) // Convert to stream of every char
.map(String::trim) // Convert spaces to empty strings
.filter(s -> !s.isEmpty()) // Remove empty strings
.reduce((l, r) -> l + " " + r) // build the new string with spaces between every character
.get(); // Get the actual string from the optional
}
Just try something that works for you.
Try out this function:
public static String formatNumberWithSpaces(String inputString){
String outputString = ""; //Declare an empty String
for (int i = 0;i < inputString.length(); i++){ //Iterate through the String passed as function argument
if (inputString.charAt(i) != ' '){ //Use the charAt function which returns the char representation of specified string index(i variable)
outputString+=inputString.charAt(i); //Same as 'outputString = outputString + inputString.charAt(i);'. So now we collect the char and append it to empty string
outputString+=' '; //We need to separate the next char using ' '
} //We do above instruction in loop till the end of string is reached
}
return outputString.substring(0, outputString.length()-1);
}
Just call it by:
System.out.println(formatNumberWithSpaces("123 222 2222"));
EDIT:
Or if you want to ask user for input, try:
Scanner in = new Scanner(System.in);
System.out.println("Give me your string to parse");
String input = in.nextLine(); //it moves the scanner position to the next line and returns the value as a string.
System.out.println(formatNumberWithSpaces(input)); // Here you print the returned value of formatNumberWithSpaces function
Don't forget to import, so you will be able to read user input :
import java.util.Scanner;
There are various ways to read input from the keyboard, the java.util.Scanner class is one of them.
EDIT2:
I changed:
return outputString;
..to: return outputString.substring(0, outputString.length()-1);
Just because outputString+=' '; was also appending empty space at the end of string, which is useless. Didn't add an if inside for loop which wouldn't add space when last char is parsed, just because of its low performance inside for loop.
use this code.
public class StringComEspaços {
public static void main(String[] args) {
System.out.println(formatNumberWithSpaces("123 222 2222"));
}
private static String formatNumberWithSpaces(String string) {
String lineWithoutSpaces = string.replaceAll("\\s+", "");
String[] s = lineWithoutSpaces.split("");
String os = "";
for (int i = 0; i < s.length; i++) {
os = os + s[i] + " ";
}
return os;
}
}
This is my method for adding each line of code:
public static void String(){
File f = new File("src/testClass.java");
try {
Scanner s = new Scanner(f);
s.useDelimiter("\\n");
while(s.hasNextLine()){
String st = s.next();
if(!st.equals("\\p{Space}")) System.out.println(st);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Here is the testClass.java
public class testClass {
public static void main (String[] args){
int someNum = 1; //comment
String someStr = "haha";
/* final double pi = 3.14159;
*
*/
}
public static void uselessMethod(int someNum){
boolean isUseless1 = true;
}
}
When I use this class to test my parser, it doesn't skip over the blank space after the brace underneath the closing bracket for main. What needs to be done to not get it to be stored? What is the more appropriate if statement to get it to not store that blank line, while acknowledging that it is a line rather than skipping over it completely? I want to keep track of the line number while not storing the blank lines.
You want to use the matches() method instead of equals():
if(!st.matches("^\\p{Space}*$")) System.out.println(st);
I've also modified your regular expression a little bit. It should now exclude all lines that are empty or contain only whitespace.
I usually just skip empty line:
public static List<String> fileToList(String patch) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(patch));
String line ="";
List<String> result = new ArrayList<>();
while ((line = br.readLine()) != null) {
/*
* Just skip empty line
*/
if (line.isEmpty()) {
continue;
} else {
result.add(line);
}
}
return result;
}
I need help with decompressing method. I have a working Compress method. Any suggestions as far as what I need to consider? Do I need parseInt or else....? Appreciate the advice. Here is what I have so far. If s = "ab3cca4bc", then it should return "abbbccaaaabc", for example of decompress.
class RunLengthCode {
private String pText, cText;
public RunLengthCode () {
pText = "";
cText = "";
}
public void setPText (String newPText) {
pText = newPText;
}
public void setCText (String newCText) {
cText = newCText;
}
public String getPText () {
return pText;
}
public String getCText () {
return cText;
}
public void compress () { // compresses pText to cText
String ans = "";
for (int i = 0; i < pText.length(); i++) {
char current = pText.charAt(i);
int cnt = 1;
String temp = "";
temp = temp + current;
while (i < pText.length() - 1 && (current == pText.charAt(i + 1))) {
cnt++;
i++;
temp = temp + current;
}
if (cnt > 2) {
ans = ans + current;
ans = ans + cnt;
}
else
ans = ans + temp;
setCText(ans);
}
}
public void decompress () {
}
}
public class {
public static void main(String [] args) {
Scanner in = new Scanner(System.in);
RunLengthCode myC = new RunLengthCode();
String pText, cText;
System.out.print("Enter a plain text consisting of only lower-case alphabets and spaces:");
pText = in.nextLine();
myC.setPText(pText);
myC.compress();
System.out.println(pText+" => "+myC.getCText());
System.out.print("Enter a compressed text consisting of only lower-case alphabets, spaces and digits:");
cText = in.nextLine();
myC.setCText(cText);
myC.decompress();
System.out.println(cText+" => "+myC.getPText());
}
}
You could create break the string into regx groups and combine them.
The following pattern works
(([A-Za-z]+[\d]*))
This will break your string "ab3cca4bc" into groups of
"ab3", "cca4", "bc"
So in a loop if the last character is a digit, you could multiply the character before it that many times.
Ok, so you've got an input string that looks like ab3cca4bc
1.) Loop over the length of the input String
2.) During each loop iteration, use the String.charAt(int) method to pick up the individual character
3.) The Character class has an isDigit(char) function that you can use to determine if a character is a number or not. You can then safely use Integer.parseInt(String) (you can use myChar+"" to convert a char into a String)
4.) If the char in question is a number, then you'll need to have an inner loop to repeat the previous character the correct number of times. How will you know what the last character was? Maybe have a variable that's instantiated outside the loop that you update each time you add a character on the end?
This is the question from my assignment that I am unsure of:
The class is to contain a public method nextWord(). When a new line is read, use the String method .split("\s+") to create an array of the words that are on the line. Each call to the nextWord() method is to return the next word in the array. When all of the words in the array have been processed, read the next line in the file. The nextWord()method returns the value null when the end of the file is reached.
I have read the file, and stored each individual string in an array called tokenz.
I'm not sure how I can have a method called "nextWord" which returns each individual word from tokenz one at a time. Maybe I don't understand the question?
The last part of the question is:
In your main class, write a method named processWords() which instantiates the MyReader class (using the String "A2Q2in.txt"). Then write a loop that obtains one word at a time from the MyReader class using the nextWord() method and prints each word on a new line.
I've thought of ways to do this but I'm not sure how to return each word from the nextWord method i'm supposed to write. I can't increase a count because after the String is returned, anything after the return statement cannot be reached because the method is done processing.
Any help would be appreciated, maybe I'm going about this the wrong way?
Can't use array lists or anything like that.
Here is my code.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class A2Q2
{
public static void main (String [] args)
{
processWords();
}
public static void processWords()
{
MyReader reader = new MyReader("A2Q2.txt");
String[] words = new String[174];
words[0] = reader.nextWord();
System.out.println(words[0]);
}
}
class MyReader
{
static String name;
static BufferedReader fileIn;
static String inputLine;
static int tokensLength = 0;
static String[] tokens;
static int counter = 0;
// constructor.
public MyReader(String name)
{
this.name = name;
}
public static String[] readFile()
{
String[] tokenz = new String[174];
int tokensLength = 0;
try
{
fileIn = new BufferedReader (new FileReader(name));
inputLine = fileIn.readLine();
while(inputLine !=null)
{
tokens = inputLine.split("\\s+");
for (int i = 0 ; i < tokens.length; i++)
{
int j = i + tokensLength;
tokenz[j] = tokens[i];
}
tokensLength = tokensLength + tokens.length;
inputLine = fileIn.readLine();
}
fileIn.close();
}
catch (IOException ioe)
{
System.out.println(ioe.getMessage());
ioe.printStackTrace();
}
//FULL ARRAY OF STRINGS IN TOKENZ
return tokenz;
}
public static String nextWord()
{
String[] tokenzz = readFile();
//????
return tokenzz[0];
}
}
Here's a conceptual model for you.
Keep track of your MyReader's state to know which value to return next.
the following example uses tokenIndex to decide where to read at next.
class MyReader
{
String[] tokens;
int tokenIndex = 0;
public String nextWord()
{
if(tokens == null || tokens.length <= tokenIndex)
{
// feel free to replace this line with whatever logic you want to
// use to fill in a new line.
tokens = readNextLine();
tokenIndex = 0;
}
String retVal = tokens[tokenIndex];
tokenIndex++;
return retval;
}
}
Mind you, this isn't a complete solution(it doesn't check for the end of file for instance), only a demonstration of the concept. You might have to elaborate a bit.
Use a loop and process each element in the array, printing them one at a time?
I'd like to do a function which gets a string and in case it has inline comments it removes it. I know it sounds pretty simple but i wanna make sure im doing this right, for example:
private String filterString(String code) {
// lets say code = "some code //comment inside"
// return the string "some code" (without the comment)
}
I thought about 2 ways: feel free to advice otherwise
Iterating the string and finding double inline brackets and using substring method.
regex way.. (im not so sure bout it)
can u tell me what's the best way and show me how it should be done? (please don't advice too advanced solutions)
edited: can this be done somehow with Scanner object? (im using this object anyway)
If you want a more efficient regex to really match all types of comments, use this one :
replaceAll("(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)|(?://.*)","");
source : http://ostermiller.org/findcomment.html
EDIT:
Another solution, if you're not sure about using regex is to design a small automata like follows :
public static String removeComments(String code){
final int outsideComment=0;
final int insideLineComment=1;
final int insideblockComment=2;
final int insideblockComment_noNewLineYet=3; // we want to have at least one new line in the result if the block is not inline.
int currentState=outsideComment;
String endResult="";
Scanner s= new Scanner(code);
s.useDelimiter("");
while(s.hasNext()){
String c=s.next();
switch(currentState){
case outsideComment:
if(c.equals("/") && s.hasNext()){
String c2=s.next();
if(c2.equals("/"))
currentState=insideLineComment;
else if(c2.equals("*")){
currentState=insideblockComment_noNewLineYet;
}
else
endResult+=c+c2;
}
else
endResult+=c;
break;
case insideLineComment:
if(c.equals("\n")){
currentState=outsideComment;
endResult+="\n";
}
break;
case insideblockComment_noNewLineYet:
if(c.equals("\n")){
endResult+="\n";
currentState=insideblockComment;
}
case insideblockComment:
while(c.equals("*") && s.hasNext()){
String c2=s.next();
if(c2.equals("/")){
currentState=outsideComment;
break;
}
}
}
}
s.close();
return endResult;
}
The best way to do this is to use regular expressions.
At first to find the /**/ comments and then remove all // commnets. For example:
private String filterString(String code) {
String partialFiltered = code.replaceAll("/\\*.*\\*/", "");
String fullFiltered = partialFiltered.replaceAll("//.*(?=\\n)", "")
}
Just use the replaceAll method from the String class, combined with a simple regular expression. Here's how to do it:
import java.util.*;
import java.lang.*;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
String s = "private String filterString(String code) {\n" +
" // lets say code = \"some code //comment inside\"\n" +
" // return the string \"some code\" (without the comment)\n}";
s = s.replaceAll("//.*?\n","\n");
System.out.println("s=" + s);
}
}
The key is the line:
s = s.replaceAll("//.*?\n","\n");
The regex //.*?\n matches strings starting with // until the end of the line.
And if you want to see this code in action, go here: http://www.ideone.com/e26Ve
Hope it helps!
To find the substring before a constant substring using a regular expression replacement is a bit much.
You can do it using indexOf() to check for the position of the comment start and substring() to get the first part, something like:
String code = "some code // comment";
int offset = code.indexOf("//");
if (-1 != offset) {
code = code.substring(0, offset);
}
#Christian Hujer has been correctly pointing out that many or all of the solutions posted fail if the comments occur within a string.
#Loïc Gammaitoni suggests that his automata approach could easily be extended to handle that case. Here is that extension.
enum State { outsideComment, insideLineComment, insideblockComment, insideblockComment_noNewLineYet, insideString };
public static String removeComments(String code) {
State state = State.outsideComment;
StringBuilder result = new StringBuilder();
Scanner s = new Scanner(code);
s.useDelimiter("");
while (s.hasNext()) {
String c = s.next();
switch (state) {
case outsideComment:
if (c.equals("/") && s.hasNext()) {
String c2 = s.next();
if (c2.equals("/"))
state = State.insideLineComment;
else if (c2.equals("*")) {
state = State.insideblockComment_noNewLineYet;
} else {
result.append(c).append(c2);
}
} else {
result.append(c);
if (c.equals("\"")) {
state = State.insideString;
}
}
break;
case insideString:
result.append(c);
if (c.equals("\"")) {
state = State.outsideComment;
} else if (c.equals("\\") && s.hasNext()) {
result.append(s.next());
}
break;
case insideLineComment:
if (c.equals("\n")) {
state = State.outsideComment;
result.append("\n");
}
break;
case insideblockComment_noNewLineYet:
if (c.equals("\n")) {
result.append("\n");
state = State.insideblockComment;
}
case insideblockComment:
while (c.equals("*") && s.hasNext()) {
String c2 = s.next();
if (c2.equals("/")) {
state = State.outsideComment;
break;
}
}
}
}
s.close();
return result.toString();
}
I made an open source library (on GitHub) for this purpose , its called CommentRemover you can remove single line and multiple line Java Comments.
It supports remove or NOT remove TODO's.
Also it supports JavaScript , HTML , CSS , Properties , JSP and XML Comments too.
Little code snippet how to use it (There is 2 type usage):
First way InternalPath
public static void main(String[] args) throws CommentRemoverException {
// root dir is: /Users/user/Projects/MyProject
// example for startInternalPath
CommentRemover commentRemover = new CommentRemover.CommentRemoverBuilder()
.removeJava(true) // Remove Java file Comments....
.removeJavaScript(true) // Remove JavaScript file Comments....
.removeJSP(true) // etc.. goes like that
.removeTodos(false) // Do Not Touch Todos (leave them alone)
.removeSingleLines(true) // Remove single line type comments
.removeMultiLines(true) // Remove multiple type comments
.startInternalPath("src.main.app") // Starts from {rootDir}/src/main/app , leave it empty string when you want to start from root dir
.setExcludePackages(new String[]{"src.main.java.app.pattern"}) // Refers to {rootDir}/src/main/java/app/pattern and skips this directory
.build();
CommentProcessor commentProcessor = new CommentProcessor(commentRemover);
commentProcessor.start();
}
Second way ExternalPath
public static void main(String[] args) throws CommentRemoverException {
// example for externalPath
CommentRemover commentRemover = new CommentRemover.CommentRemoverBuilder()
.removeJava(true) // Remove Java file Comments....
.removeJavaScript(true) // Remove JavaScript file Comments....
.removeJSP(true) // etc..
.removeTodos(true) // Remove todos
.removeSingleLines(false) // Do not remove single line type comments
.removeMultiLines(true) // Remove multiple type comments
.startExternalPath("/Users/user/Projects/MyOtherProject")// Give it full path for external directories
.setExcludePackages(new String[]{"src.main.java.model"}) // Refers to /Users/user/Projects/MyOtherProject/src/main/java/model and skips this directory.
.build();
CommentProcessor commentProcessor = new CommentProcessor(commentRemover);
commentProcessor.start();
}
for scanner, use a delimiter,
delimiter example.
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
public class MainClass {
public static void main(String args[]) throws IOException {
FileWriter fout = new FileWriter("test.txt");
fout.write("2, 3.4, 5,6, 7.4, 9.1, 10.5, done");
fout.close();
FileReader fin = new FileReader("Test.txt");
Scanner src = new Scanner(fin);
// Set delimiters to space and comma.
// ", *" tells Scanner to match a comma and zero or more spaces as
// delimiters.
src.useDelimiter(", *");
// Read and sum numbers.
while (src.hasNext()) {
if (src.hasNextDouble()) {
System.out.println(src.nextDouble());
} else {
break;
}
}
fin.close();
}
}
Use a tokenizer for a normal string
tokenizer:
// start with a String of space-separated words
String tags = "pizza pepperoni food cheese";
// convert each tag to a token
StringTokenizer st = new StringTokenizer(tags," ");
while ( st.hasMoreTokens() )
{
String token = (String)st.nextToken();
System.out.println(token);
}
http://www.devdaily.com/blog/post/java/java-faq-stringtokenizer-example
It will be better if code handles single line comment and multi line comment separately . Any suggestions ?
public class RemovingCommentsFromFile {
public static void main(String[] args) throws IOException {
BufferedReader fin = new BufferedReader(new FileReader("/home/pathtofilewithcomments/File"));
BufferedWriter fout = new BufferedWriter(new FileWriter("/home/result/File1"));
boolean multilinecomment = false;
boolean singlelinecomment = false;
int len,j;
String s = null;
while ((s = fin.readLine()) != null) {
StringBuilder obj = new StringBuilder(s);
len = obj.length();
for (int i = 0; i < len; i++) {
for (j = i; j < len; j++) {
if (obj.charAt(j) == '/' && obj.charAt(j + 1) == '*') {
j += 2;
multilinecomment = true;
continue;
} else if (obj.charAt(j) == '/' && obj.charAt(j + 1) == '/') {
singlelinecomment = true;
j = len;
break;
} else if (obj.charAt(j) == '*' && obj.charAt(j + 1) == '/') {
j += 2;
multilinecomment = false;
break;
} else if (multilinecomment == true)
continue;
else
break;
}
if (j == len)
{
singlelinecomment=false;
break;
}
else
i = j;
System.out.print((char)obj.charAt(i));
fout.write((char)obj.charAt(i));
}
System.out.println();
fout.write((char)10);
}
fin.close();
fout.close();
}
Easy solution that doesn't remove extra parts of code (like those above)
// works for any reader, you can also iterate over list of strings instead
String str="";
String s;
while ((s = reader.readLine()) != null)
{
s=s.replaceAll("//.*","\n");
str+=s;
}
str=str.replaceAll("/\\*.*\\*/"," ");