Hướng dẫn làm bài tập tự động căn dòng cho đoạn text

Write a program for pretty printing Java programs; that is, for printing programs with consistent use of indentation, the number of spaces between tokens such as key words, parentheses, brackets, operators, the number of blank lines between blocks of code (classes, methods, etc.), aligning braces with key words, aligning else statements with the corresponding if statements, and so on. The program takes as input a Java file and prints code in this file according to the rules incorporated in the pretty printing program. For example, the code

image

e có bài tập như thế này mà hiện tại e chưa có hướng giải quyết xin ae nào giỏi thuật toán hướng dẫn giúp e với ạ. em cảm ơn

Tự làm đi em bài này dễ mà

2 Likes

Đầu tiên bạn tìm hiểu quy luật lùi đầu dòng (tab hay space?) và các từ khóa. Sau đó ghi ra giấy từng loại ngoặc, toán tử, từ khóa. Làm bằng tay trước.

5 Likes
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package DAO;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author 【=◈︿◈=】 それはキミへのうたなんだ~ Jdev
 */
public class FileDAO {

    public static void existedFile(File file) { // kiểm tra file 
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (Exception ex) {
                Logger.getLogger(FileDAO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public static String readFile(String filename) {  // đọc file
        String vls = "";
        File file = new File(filename);
        existedFile(file);
        FileReader f = null;
        BufferedReader bf = null;
        try {
            f = new FileReader(file);
            bf = new BufferedReader(f);
            while (bf.ready()) {
                String sline = bf.readLine();
                vls = vls + sline.trim();
                //  System.out.println(vls);
            }
        } catch (Exception e) {
            System.out.println("File Fail");
        } finally {
            try {
                if (f != null) {
                    f.close();
                }
                if (bf != null) {
                    bf.close();
                }

            } catch (Exception e) {
            }
        }
        return vls;
    }

    public static boolean writeFile(String filename, ArrayList<String> arr) {  // ghi file
        if (arr == null) {
            return false;
        }
        PrintWriter w = null;
        try {
            w = new PrintWriter(filename);
            for (String string : arr) {
                w.println(string);
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            try {
                if (w != null) {
                    w.close();
                }
            } catch (Exception e) {
            }
        }
        return true;
    }
    public static ArrayList<String> Format(String vls) { 
      String[] sub1 = vls.split("\\{");                              // lọc lượt 1 : "{"  
        String[] sub1new = new String[sub1.length];
        for (int i = 0; i < sub1new.length; i++) {
            sub1new[i] = sub1[i] + "{";
        }
//   dòng này mình k biết giải thích sao, bạn thử ẩn nó đi rồi chạy thử sẽ hiểu  
        sub1new[sub1new.length - 1] = sub1new[sub1new.length - 1].replace("{", ""); 


        for (String string : sub1new) { // sau khi lọc lần 1 
            System.out.println(string);
        }
        ArrayList<String> arr = new ArrayList<>();  // lọc lượt 2 : ";"  
        ArrayList<String> arrFinal = new ArrayList<>();
        for (String string : sub1new) {
            String[] tmp = string.split(";");
            arr.addAll(Arrays.asList(tmp));
        }
   

     for (String string : arr) {
            if (!string.contains("{")) {
                arrFinal.add(string + ";");
            } else {
                arrFinal.add(string);
            }
        }

        System.out.println("\n\n"); 

        for (String string : arrFinal) {
            System.out.println(string);
        }
        return arrFinal;

    }

    public static void main(String[] args) {
        String input = "C:\\Users\\Jeff\\Desktop\\inp.txt";
        String output = "‪‪outp.txt";
        String notsub = FileDAO.readFile(input);
        ArrayList<String> formatted = FileDAO.Format(notsub);

        if (FileDAO.writeFile(output, formatted)) {
            System.out.println("thanh cong");
        } else {
            System.out.println("that bai");
        }
    }

}

đây là ý tưởng chữa cháy của mình, mình duyệt “{” trước sau đó duyệt “;” , còn phần “}” nữa chưa làm xong vì deadline sát đít r :smile: chúc bạn pass CSD201

3 Likes

Mình làm đc rồi!!! cơ mà dù sao cũng cảm ơn vì sự nhiệt tình của bạn <3

Switch case thì sao bạn?
Rồi split (";") thì bạn xử lý case for(*;*;) chưa nhỉ?

2 Likes

Tôi là Đức, xin chào các fan hâm mộ

Bài này chỉ cần để ý như sau:
Có 2 loại statement:

  • Loại 1 kết thúc bởi dấu ;
  • Loại 2 không kết thúc bởi dấu ; là các statement khai báo hàm, lặp, điều khiển blah blah.
    Giả sử ta có 1 code block gồm cả loại 1 và loại 2, thấy rằng với loại 1 ta chỉ việc in ra theo indent là 2 (hoặc 4) còn loại 2 thì tự nó sẽ tạo ra 1 code block mới với indent = indent trước đó + 2 hoặc 4.
    Như vậy, ta thấy với 1 code block, ta chỉ cần duyệt qua các dòng trong block đó, với loại 1 thì ta cứ in ra còn loại 2 thì gọi đệ quy để giải quyết cái code block mới.

Về vấn đề xác định xem 1 code block bắt đầu và kết thúc tại đâu, tương ứng với bài toán ghép cặp các dấu ngoặc ‘{’ và ‘}’ trong 1 dãy (Vì 1 code block bắt đầu bởi 1 xâu kết thúc bởi ‘{’ và kết thúc bởi 1 xâu đúng bằng ‘}’ (trừ do {} while (cond);
Tất nhiên là nếu xét cả switch case vào (1 case bắt đầu và kết thúc tại đâu) thì bài toán rắc rối hơn nhưng vẫn giải được và giải được trong O(n).

Các vấn đề còn lại như: tách ‘{’, ‘}’, ‘:’, ‘;’, và tách làm sao phải bỏ qua các trường hợp là những dấu đó lại là 1 ký tự hằng, nối các chuỗi đã tách nếu cần thiết, xử lý dấu tab ‘\t’…chỉ đơn thuần là những vấn đề kỹ thuật nhưng muốn xử lý trọn vẹn thì tương đối khó.

Người thảo luận để tìm ra cách giải hay cho một bài toán khó sẽ trở thành lập trình viên giỏi. Người hay hỏi bài tập thì không. Còn bạn thì sao?

4 Likes

Mình có ý tưởng build bài này bằng Abstract Syntax Tree nhưng không rõ lý thuyết cây cho lắm, không biết nên định nghĩa node của cây là dạng nào. Bạn giải đáp dùm mình được không?

Bạn thử xem qua cuốn “Appel and Palsberg. Modern Compiler Implementation in Java”.
Chúc bạn thành công.

3 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?