Hi, this was my previous post https://www.daniweb.com/programming/software-development/threads/504670/need-help-with-a-java-program-that-will-indent-code-from-another-java-file#post2204763

I heard it would make more sense if I put all the code on one line and worked on it from there. I already have code that will indent properly, but I need code that will properly separate the text in Code.java

This is what Code.java looks like

// Code.java import java.io.*; import java.util.*; public class Code { public static void main(String[] args) throws FileNotFoundException { Scanner input = new Scanner(new File("words.txt")); PrintStream output = new PrintStream(new File("words2.txt")); while (input.hasNextLine()) { String text = input.nextLine(); echoFixed(text, output); echoFixed(text, System.out); input.close(); } } public static void echoFixed(String text, PrintStream output) { Scanner data = new Scanner(text); if (data.hasNext()) { output.print(data.next()); while (data.hasNext()) { output.print(" " + data.next());}} output.println(); data.close(); } } 

I need it to look like this

// Code.java
import java.io.*; 
import java.util.*; 
public class Code { 
public static void main(String[] args) throws FileNotFoundException { 
Scanner input = new Scanner(new File("words.txt")); 
PrintStream output = new PrintStream(new File("words2.txt")); 
while (input.hasNextLine()) { 
String text = input.nextLine(); 
echoFixed(text, output); 
echoFixed(text, System.out); 
input.close(); 
} 
} 
public static void echoFixed(String text, PrintStream output) { 
Scanner data = new Scanner(text); 
if (data.hasNext()) { 
output.print(data.next()); 
while (data.hasNext()) { 
output.print(" " + data.next());
}
} 
output.println(); 
data.close(); 
} 
} 

So I can plug that into my program so it will look like this

// Code.java
import java.io.*;
import java.util.*;
public class Code {
    public static void main(String[] args) throws FileNotFoundException {
        Scanner input = new Scanner(new File("words.txt"));
        PrintStream output = new PrintStream(new File("words2.txt"));
        while (input.hasNextLine()) {
            String text = input.nextLine();
            echoFixed(text, output);
            echoFixed(text, System.out);
            input.close();
        }
    }
    public static void echoFixed(String text, PrintStream output) {
        Scanner data = new Scanner(text);
        if (data.hasNext()) {
            output.print(data.next());
            while (data.hasNext()) {
                output.print(" " + data.next());
            }
        }
        output.println();
        data.close();
    }
}

How would I go about doing this?

Dani AI

Generated

Do not collapse the whole file onto a single line — is correct: // comments are terminated by the original end-of-line, so flattening will silently comment out everything that follows. Follow 's suggestion and use a tiny state machine instead: read the source file line-by-line (so // stays bounded to its original line), and scan characters while tracking states (in-code, in-string, in-char, in-line-comment, in-block-comment). Also keep a parentheses-depth counter so semicolons inside for(...) headers are not treated as statement terminators.

Key rules to apply while scanning each line:

  • Ignore {, }, ; and // when inside string/char literals or comments.
  • Treat /* ... */ as a block that may span lines (track it across input lines).
  • When you see ; and parentheses depth is zero, or { or }, flush the current buffer as a separate output line (so a(); b(); becomes two lines).
  • When you see // in code state, append the rest of the source line as a single comment token and flush.
  • Handle escape sequences inside strings/chars so \" and \\ don't break detection.

A compact, practical implementation sketch (call from a reader and then feed the resulting fragments to your existing indentation routine):

public static List<String> splitJavaLines(BufferedReader br) throws IOException {
    List<String> out = new ArrayList<>();
    boolean inBlock = false;
    int parenDepth = 0;
    String raw;
    while ((raw = br.readLine()) != null) {
        StringBuilder cur = new StringBuilder();
        boolean inString = false, inChar = false, inLineComment = false;
        for (int i = 0; i < raw.length(); i++) {
            char ch = raw.charAt(i);
            if (inBlock) {
                cur.append(ch);
                if (ch == '*' && i + 1 < raw.length() && raw.charAt(i + 1) == '/') {
                    cur.append('/'); i++; inBlock = false;
                }
                continue;
            }
            if (inLineComment) { cur.append(ch); continue; }
            if (inString) {
                cur.append(ch);
                if (ch == '\\' && i + 1 < raw.length()) cur.append(raw.charAt(++i));
                else if (ch == '"') inString = false;
                continue;
            }
            if (inChar) {
                cur.append(ch);
                if (ch == '\\' && i + 1 < raw.length()) cur.append(raw.charAt(++i));
                else if (ch == '\'') inChar = false;
                continue;
            }
            if (ch == '"') { inString = true; cur.append(ch); continue; }
            if (ch == '\'') { inChar = true; cur.append(ch); continue; }
            if (ch == '/' && i + 1 < raw.length()) {
                char n = raw.charAt(i + 1);
                if (n == '/') { cur.append("//"); i++; if (i + 1 < raw.length()) cur.append(raw.substring(i + 1)); inLineComment = true; break; }
                if (n == '*') { cur.append("/*"); i++; inBlock = true; continue; }
            }
            if (ch == '(') parenDepth++;
            else if (ch == ')') if (parenDepth > 0) parenDepth--;
            cur.append(ch);
            if ((ch == ';' && parenDepth == 0) || ch == '{' || ch == '}') {
                out.add(cur.toString().trim()); cur.setLength(0);
            }
        }
        if (cur.length() > 0) out.add(cur.toString().trim());
    }
    return out;
}

Troubleshooting notes: test cases should include for(...) headers, strings containing \" and escaped backslashes, char literals, and multi-line block comments. For industrial-strength correctness (full JLS parsing, annotations, generics quirks), use a parser library (Eclipse JDT or JavaParser) and then pretty-print; for a simple formatter this state-machine approach is fast and reliable. After splitting, run your existing indentation logic: decrement indent before printing lines that start with }, and increment after lines that end with {.

Recommended Answers

All 6 Replies

I think I could break your formatter with a comment since what if you ran into a commented out line of code and your new line breaker enabled that code.

How about you use your prior code and where you read a line you remove spaces and tabs from the beginning and end of each line?

In other words how would your new formatter know the end of a comment? It would have to make guesses such as "Hmm, a // might end when I find ???" I get the feeling an AI class would have to be made.

Yeah, I think you're right. Putting everything on one line isn't convenient. I'm still having a hard time checking for multiple braces and semicolons on one line though.

So, in psuedocode.

Set up your indent variables, start with 0 or what you what.
Until EOF
- read a line, strip leading and trailing white space. (tab, spaces).
- output the intended spaces or tab plus this line.
- if this line has brace, increment/decrement the indent counter for each brace.

If a line has multiple braces, well that's the coder's intention and we'll roll with that.
As to semicolons, unsure why they matter. Will have to ponder why as they don't affect the indentation.


I have indentations working. If a line has multiple braces like }}, I want one of them to go onto the next line. If a line has multiple semicolons like output.println(); data.close();, I want the two statements to show up on two different lines.

If a line has multiple braces like }}, I want one of them to go onto the next line. If a line has multiple semicolons like output.println(); data.close();, I want the two statements to show up on two different lines.

OK, in psuedo code.function linebreaker()
if semicolons (more than one) repeat until there is one semicolon
- print tabs and line up to and including the semicolon
- remove characters in line up to and including the first semicolon.
end repeat (until one semicolon.)
print tabs then what left in line.

In other words how would your new formatter know the end of a comment? It would have to make guesses such as "Hmm, a // might end when I find ???" I get the feeling an AI class would have to be made.

The JLS specifies Java's syntax with great precision. It's entirely deterministic, no AI needed. Comments beginning with 2 slashes are delimited by the next end of line, so any process that removes end of lines can corrupt the code, so you can't just put it all on one line. No amount of AI could fix that

Before looking for end comment delimiters you need to exclude literal strings.
Before looking for start comment delimiters you need to exclude literal strings and comments.
(to identify the end of a literal you need to ignore escaped literal " chars inside the literal, of course)

I think you have to process the input one or two chars at a time in a simple state machine (the important states being: in code, in a literal, in a comment) . Now you can respond to semicolons or curly brackets in code only. Also, in code only, you can replace all runs of white space by a simple blank char. Once you have that then breaking statements onto separate lines, and indenting by the right amount is simple.

commented: From AI to aiyee! +10
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.