I'm writing a simple program to reformat source code using new line style curly brace to end of line curly brace style. I'm having trouble manipulating strings to then pass them to an arraylist.
My specific problem is when I find a line which has a new line curly brace, I then get the index of the line before, set the new line to the element in the previous index and append a "{", I am having trouble removing the previous line.
I've tried doing .remove(previousIndex) but it did not work
Sample input:
public class Reformat
{
public static void main(String[] args)
{
System.out.println("Test 1");
System.out.println("Test 2");
}
}
This is my code so far:
public class Reform {
public static void main(String[] arg) throws FileNotFoundException {
// Pass source file to File object
File sourceFile = new File(arg[0]);
// Create AL of type String to hold tokens
ArrayList<String> code = new ArrayList<String>();
Scanner input = null;
// Try-catch block to handle any errors while opening the file
try {
input = new Scanner(sourceFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
while (input.hasNextLine()) {
String currentLine = input.nextLine();
if (currentLine.isEmpty()) {
continue;
} else if (currentLine.contains("{") && code.size() != 0) {
int previousIndex = code.size() - 1;
code.add(code.set(previousIndex, code.get(previousIndex) + "{"));
} else {
code.add(currentLine);
}
}//end of while
for (String line : code)
System.out.println(line);
}//end of finally
input.close();
}//end of main
}//end of class
I played around with the code in question and was able to resolve by arranging in this manner:
else if (currentLine.contains("{") && code.size() != 0) {
int previousIndex = code.size() - 1;
String newLine = code.set(previousIndex, code.get(previousIndex) + "{");
code.add(previousIndex, newLine);
code.remove(previousIndex);
Not 100% sure why it worked in this way and not the other attempts. I would appreciate an explanation. The worst type of solutions are the ones you don't understand.
This is wrong:
code.add(code.set(previousIndex, code.get(previousIndex) + "{"));
It should be:
code.set(previousIndex, code.get(previousIndex) + "{");
Related
When I use FileInputStream to input text from my spawn.txt file for a tile-based map, it adds extra whitespace in-between each line.
package mapInit;
import java.io.FileInputStream;
public class SpawnMap {
static char[][] spawnWorld = new char[30][30];
public static void main(String[] args) {
try {
FileInputStream spawn = new FileInputStream("Resources/Map/spawn.txt");
int i = 0;
int h = 0;
int k = 0;
while((i=spawn.read())!=-1){
if(h == 30) {
h = 0;
k++;
}
spawnWorld[k][h] = (char)i;
h++;
}
spawn.close();
} catch (Exception e) {
}
for (int i=0; i<30; i++) {
for (int j=0;j<30;j++) {
System.out.println(spawnWorld[i][j]);
}
}
}
}
This is the result of the output loop:
This is a picture of the text file:
GitHub Link: https://github.com/WeaponGod243/Machlandia
I think Scanner class it's more suitable for your task
Scanner class in Java is found in the java.util package. Java provides
various ways to read input from the keyboard, the java.util.Scanner
class is one of them.
The Java Scanner class breaks the input into tokens using a delimiter
which is whitespace by default. It provides many methods to read and
parse various primitive values.
The Java Scanner class is widely used to parse text for strings and
primitive types using a regular expression. It is the simplest way to
get input in Java. By the help of Scanner in Java, we can get input
from the user in primitive types such as int, long, double, byte,
float, short, etc.
The Java Scanner class extends Object class and implements Iterator
and Closeable interfaces.
The Java Scanner class provides nextXXX() methods to return the type
of value such as nextInt(), nextByte(), nextShort(), next(),
nextLine(), nextDouble(), nextFloat(), nextBoolean(), etc. To get a
single character from the scanner, you can call next().charAt(0)
method which returns a single character.
Source
Scanner Java Doc
public static void main(String arg[]) {
try (Scanner sc = new Scanner(new File("Resources/Map/spawn.txt"))) {
// Checking if sc has another token in the file
while(sc.hasNext()) {
// Print line
System.out.println(sc.next());
}
} catch (Exception ex) {
// Use a Logger to log exceptions in real projects
ex.printStackTrace();
}
}
You could use Apache Commons IO library too
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class ReadTextFile {
public static void main(String[] args) throws IOException {
try {
File f = new File("Resources/Map/spawn.txt");
List<String> lines = FileUtils.readLines(f, "UTF-8");
for (String line : lines) {
System.out.println(line);
}
} catch (IOException e) {
// Use a Logger to log exceptions in real projects
e.printStackTrace();
}
}
}
Change the System.out.println inside your loop to just System.out.print.
System.out.println will automatically add a newline character every time, even if you're only printing a single character. System.out.print will take the String you pass in, and print it as is.
Here's a link to the official Javadoc:
https://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html#print-java.lang.String-
Also, unless it's on purpose, verify you're not printing the \n (newline character) at the end of each line. If you actually want to start a new line at the end of each line, simply put a System.out.println(); line after the end of the innermost loop.
I have looked at your codes. It seems by using this I have detected that by using FileInputStream it will produce an empty space in between the values.
static char[][] spawnWorld = new char[30][30];
public static void main(String[] args) {
try {
FileInputStream spawn = new FileInputStream("C:/Daniel/spawn.txt");
int i = 0;
int h = 0;
int k = 0;
while ((i = spawn.read()) != -1) {
if (h == 30) {
h = 0;
k++;
}
spawnWorld[k][h] = (char) i;
if (h == 19) System.out.println((char) i);
System.out.println("[" + k + "][" + h + "] : " + i);
h++;
}
spawn.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Start Printing");
for (int i = 0; i < 30; i++) {
for (int j = 0; j < 30; j++) {
System.out.println("[" + i + "][" + j + "] : " + spawnWorld[i][j]);
}
}
System.exit(0);
}
From then on you may debug it accordingly.
At line 19, your 'i' returns a blank space or char value i.
I would suggest to use the Scanner as your way to read the file instead.
A text file is made up of characters on a line followed by end-of-line sequences, typically newlines or carriage returns followed by newlines. (These can also be thought of as line separators rather than line endings, and the last line might not be followed by one, depending on how the file was created.) You are reading the file character by character but you make no allowance for these end of line characters.
It doesn't make any difference whether you use FileInputStream or Scanner; the problem is, you read the file one character at a time but don't account for carriage return and newline.
For example:
while ((i=spawn.read()) != -1) {
if (Character.isWhitespace((char)i)) {
continue;
}
if (h == 30) {
h = 0;
k++;
}
spawnWorld[k][h] = (char)i;
h++;
}
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 wrote this code.
I am new to Java and willing to develop my skills,so I wrote this code,in order to learn Arrays,one developer suggested HashSet,I am looking forward for new suggestions.
import java.io.*;
public class dictionary
{
public static void main(String args[])
{
String[] MyArrayE=new String[5];
String[] MyArrayS=new String[5];
MyArrayE[0]="Language";
MyArrayE[1]="Computer";
MyArrayE[2]="Engineer";
MyArrayE[3]="Home";
MyArrayE[4]="Table";
MyArrayS[0]="Lingua";
MyArrayS[1]="Computador";
MyArrayS[2]="Ing.";
MyArrayS[3]="Casa";
MyArrayS[4]="Mesa";
System.out.println("Please enter a word");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String word= null;
try {
word= br.readLine();
} catch (IOException e) {
System.out.println("Error!");
System.exit(1);
}
System.out.println("Your word is " + word);
for(int i=0; i<MyArrayE.length; i++)
{
if(word.equals(MyArrayS[i]))
{
System.out.println(MyArrayE[i]);
}
}
}
}
My Question: What about if the user inputs a word not in MyArrayS, I want to check that and print a statement like "Word does not exist".
I think that it might look like:
if(word!=MyArrayS)
{
System.out.println("Word does not exist");
}
Thanks
You can simply use the .Contains(String) method to determine whether the word is contained within the array.
You have to check every element of the array to see that it's not there. So your code would actually look like:
int c;
boolean found = false;
for(c = 0;c < MyArrayS.length;c++) {
if(MyArrayS.compareTo(word) == 0) {
found = true;
}
}
if(!found) {
System.out.println("Word does not exist");
}
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("/\\*.*\\*/"," ");
I'm writing a program to delete duplicate consecutive words from a text file, then replaces that text file without the duplicates. I know that my current code does not handle the case where a duplicate word is at the end of one line, and at the beginning of the next line since I read each line into an ArrayList, find the duplicate, and remove it. After writing it though, I wasn't sure if this was an 'ok' way to do it since now I don't know how to write it back out. I'm not sure how I can keep track of the punctuation for beginning and end of line sentences, as well as the correct spacing, and when there are line returns in the original text file. Is there a way to handle those things (spacing, punctuation, etc) with what I have so far? Or, do I need to do a redesign? The other thing I thought I could do is return an array of what indices of words I need deleted, but then I wasn't sure if that's much better. Anyway, here is my code: (thanks in advance!)
/** Removes consecutive duplicate words from text files.
It accepts only one argument, that argument being a text file
or a directory. It finds all text files in the directory and
its subdirectories and moves duplicate words from those files
as well. It replaces the original file. */
import java.io.*;
import java.util.*;
public class RemoveDuplicates {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Program accepts one command-line argument. Exiting!");
System.exit(1);
}
File f = new File(args[0]);
if (!f.exists()) {
System.out.println("Does not exist!");
}
else if (f.isDirectory()) {
System.out.println("is directory");
}
else if (f.isFile()) {
System.out.println("is file");
String fileName = f.toString();
RemoveDuplicates dup = new RemoveDuplicates(f);
dup.showTextFile();
List<String> noDuplicates = dup.doDeleteDuplicates();
showTextFile(noDuplicates);
//writeOutputFile(fileName, noDuplicates);
}
else {
System.out.println("Shouldn't happen");
}
}
/** Reads in each line of the passed in .txt file into the lineOfWords array. */
public RemoveDuplicates(File fin) {
lineOfWords = new ArrayList<String>();
try {
BufferedReader in = new BufferedReader(new FileReader(fin));
for (String s = null; (s = in.readLine()) != null; ) {
lineOfWords.add(s);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
public void showTextFile() {
for (String s : lineOfWords) {
System.out.println(s);
}
}
public static void showTextFile(List<String> list) {
for (String s : list) {
System.out.print(s);
}
}
public List<String> doDeleteDuplicates() {
List<String> noDup = new ArrayList<String>(); // List to be returned without duplicates
// go through each line and split each word into end string array
for (String s : lineOfWords) {
String endString[] = s.split("[\\s+\\p{Punct}]");
// add each word to the arraylist
for (String word : endString) {
noDup.add(word);
}
}
for (int i = 0; i < noDup.size() - 1; i++) {
if (noDup.get(i).toUpperCase().equals(noDup.get(i + 1).toUpperCase())) {
System.out.println("Removing: " + noDup.get(i+1));
noDup.remove(i + 1);
i--;
}
}
return noDup;
}
public static void writeOutputFile(String fileName, List<String> newData) {
try {
PrintWriter outputFile = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
for (String str : newData) {
outputFile.print(str + " ");
}
outputFile.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
private List<String> lineOfWords;
}
An example.txt:
Hello hello this is a test test in order
order to see if it deletes duplicates Duplicates words.
How about something like this? In this case, I assume it is case insensitive.
Pattern p = Pattern.compile("(\\w+) \\1");
String line = "Hello hello this is a test test in order\norder to see if it deletes duplicates Duplicates words.";
Matcher m = p.matcher(line.toUpperCase());
StringBuilder sb = new StringBuilder(1000);
int idx = 0;
while (m.find()) {
sb.append(line.substring(idx, m.end(1)));
idx = m.end();
}
sb.append(line.substring(idx));
System.out.println(sb.toString());
Here's the output:-
Hello this a test in order
order to see if it deletes duplicates words.