Code xóa comment trong file code

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUF_SIZE 64 

int main(int argc, char **argv)
{
	FILE *inFilePtr;
    char fileName[BUF_SIZE];
    char previous_char = ' ';
    char current_char;
    int is_quote_opening = 0; 
    int is_comment_opening = 0;
    puts("Enter file name for checking comments: "); 
    scanf("%s", &fileName);
    int line = 1; //Mục đích là để xuất ra vị trí bắt đầu của comment trong trường hợp không đóng comment
    
    if((inFilePtr = fopen(fileName, "r")) != NULL)
    {
        
        FILE *outFilePtr;
        
        if((outFilePtr = fopen("result.txt", "w")) != NULL)
        {
            while((current_char = fgetc(inFilePtr)) != EOF)
            {
                if(current_char == '"' && is_comment_opening == 0)
                {
                   if(is_quote_opening == 0)
                   {
                       fputc(current_char, outFilePtr);
                       is_quote_opening = 1; 
                   }
                   else if(is_quote_opening == 1)
                   {
                       fputc(current_char, outFilePtr);
                       is_quote_opening = 0;
                   }
                   
                }
                else if(current_char == '*' && previous_char == '/')
                {
                    is_comment_opening = 1;
                  
                }
                else if(current_char == '/' && previous_char == '*')
                {
                    is_comment_opening = 0;
                    
                }
                else
                {
                    if(is_quote_opening == 1)
                    {
                        fputc(current_char, outFilePtr);
                    }
                    else if(is_comment_opening == 1)
                    {
                        //Don't do anything
                    }
                    else if(current_char == '/')
                    {
                        //Temporarily skip
                        previous_char = current_char;
                        continue;
                        
                    }
                    else
                    {
                        if(previous_char == '/')
                        {
                            fputc(previous_char, outFilePtr);
                        }
                        
                        fputc(current_char, outFilePtr);
                    }
                    
                    
                }
                
                previous_char = current_char;
            }
            fclose(outFilePtr);
            if(is_quote_opening == 1)
            {
                puts("Error, quotes doesn't close");
            }
            if(is_comment_opening == 1)
            {
                puts("Error, comments doesn't close");
            }
            fclose(inFilePtr);
        }
        else
        {
            
        }
    }
    else
    {
        //Báo lỗi
    }
               
}

Em đang thử tiếp cận theo cách anh nói để giải quyết tiếp.
Theo diễn giải thì em nghĩ là nếu vị trí current_char = ‘/’ thì em đã tạm thời chuyển previous_char = current_char, sau đó continue vòng lặp mà không xét đến if cuối cùng.
Bởi vì nếu xét ở giai đoạn này thì is_comment_opening sẽ luôn đúng.
Khi đến trường hợp là mở block comment, thì is_comment_opening đã bắt đầu chuyển sang giá trị 1 nên sẽ an toàn, nếu trong trường hợp không phải mở block thì em đã yêu cầu xuất giá trị phía trước vào file mới như anh bảo.
Kết quả: some / stuff từ some/*d crazy d*/ stuff

Em cảm ơn anh nhiều ạ.
Em nghĩ code hiện tại đã hoàn thiện. So với code em làm trước đó thì quả nhiên tốt hơn nhiều.
Đúng là ban đầu em muốn hoàn thành code đó vì nghĩ đã gần xong rồi mà bỏ thì không được.
Em nghĩ nếu bạn nào có cùng vấn đề có thể tham khảo thử

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUF_SIZE 64 

int main(int argc, char **argv)
{
	FILE *inFilePtr;
    char fileName[BUF_SIZE];
    char previous_char = ' ';
    char current_char;
    int is_quote_opening = 0; 
    int is_comment_opening = 0;
    int is_comment_closing = 1;
    puts("Enter file name for checking comments: "); 
    scanf("%s", &fileName);
    int line = 1; //Mục đích là để xuất ra vị trí bắt đầu của comment trong trường hợp không đóng comment
    
    if((inFilePtr = fopen(fileName, "r")) != NULL)
    {
        
        FILE *outFilePtr;
        
        if((outFilePtr = fopen("result.txt", "w")) != NULL)
        {
            while((current_char = fgetc(inFilePtr)) != EOF)
            {
                if(current_char == '\n')
                {
                    line++;
                }
                if(current_char == '"' && is_comment_opening == 0)
                {
                   if(is_quote_opening == 0)
                   {
                       fputc(current_char, outFilePtr);
                       is_quote_opening = 1; 
                   }
                   else if(is_quote_opening == 1)
                   {
                       fputc(current_char, outFilePtr);
                       is_quote_opening = 0;
                   }
                   
                }
                else if(current_char == '*' && previous_char == '/')
                {
                    is_comment_opening = 1;
                    is_comment_closing = 0;
                  
                }
                else if(current_char == '/' && previous_char == '*')
                {
                    is_comment_opening = 0;
                    is_comment_closing = 1;
                    
                }
                else
                {
                    if(is_quote_opening == 1)
                    {
                        fputc(current_char, outFilePtr);
                    }
                    else if(is_comment_opening == 1)
                    {
                        //Don't do anything
                    }
                    else if(current_char == '/')
                    {
                        //Temporarily skip
                        
                        
                    }
                    else
                    {
                        if(previous_char == '/' && is_comment_closing != 1)
                        {
                            puts("Je");
                            fputc(previous_char, outFilePtr);
                        }
                        
                        fputc(current_char, outFilePtr);
                    }
                    
                    
                }
                
                previous_char = current_char;
            }
            fclose(outFilePtr);
            if(is_quote_opening == 1)
            {
                puts("Error, quotes doesn't close");
            }
            if(is_comment_opening == 1)
            {
                puts("Error: Unterminated comment");
                printf("Comment began at line %d", line);
            }
            fclose(inFilePtr);
        }
        else
        {
            puts("Problem occurred when creating file for new input");
        }
    }
    else
    {
        printf("File \"%s\" couldn't be opened\n", fileName);
    }
               
}

Nguyên nhân some / stuff từ some/*d crazy d*/ stuff là em nghĩ cần phải thêm 1 biến signal is_comment_blocking.
Tại vì mình phải loại trừ trường hợp khi current char = ‘/’ nhưng kí tự trước nó là ‘*’, vậy thì điều kiện ở đây phải là is_comment_blocking.
Tại sao không dùng is_comment_opening, vì biến này khi trải qua giá trị phía trước, sẽ trở thành 0
[Ủa khoan, sao em đọc cứ thấy nó thừa thừa chỗ nào]
Như tổng kết lại thì đúng là em rút ra:

  1. Code ban đầu quá tệ, nếu trong làm việc nhóm thì em nghĩ nhiều khi không thể trao đổi được.
  2. Em vẫn hơi thắc mắc về lợi thế của việc bắt đầu bằng current_char sẽ hiệu quả hơn so với next_char
  3. Như cách em trình bày và giải quyết code từ đầu đến giờ thì anh thấy em đang ở trong tình trạng khá tệ không :3 Và nếu được anh có khuyên em nên luyện thêm hay bổ sung phần kiến thức nào để sau này thực hiện triển khai code 1 cách gọi là “đỡ khờ” hơn không.

Đa tạ anh đã dành thời gian dẫn em đến cách giải quyết cuối cùng

P/s: Hình như em vẫn sửa chưa xong case some/*crazy /*crazy*/*/stuff

1 Like

Anh có thể gợi ý giúp em phần xử lý ngoại lệ cuối cùng cho case kép không */ */
Em đang suy nghĩ là tạo thêm 1 biến signal nữa. Em nghĩ xài while loop có khi oke

Không sao, phát hiện rất hay đó bạn. Đôi khi sẽ xảy ra trường hợp bắt được 1 comment block rồi mà lại còn dư / đầu tiên như vậy, cần phải xử lý kỹ hơn một chút. Bạn đã xử lý được nó, chứng tỏ bạn có thể tư duy một cách tinh tế.

Cái bạn cần là luyện cách code cho đơn giản và mạch lạc hơn.

Trả lời câu hỏi số 2, ở đây mình tư duy theo hướng “chuyển trạng thái”. Ở đây bạn đang đọc trực tiếp từng ký tự để xử lý, có thể gọi là “xử lý online”. Giả sử bạn đã xử lý m kí tự, vậy khi gặp 1 kí tự mới, bạn cần phải xác định kí tự đó làm thay đổi trạng thái hiện tại như thế nào; giống như trong cuộc sống, việc gì đến thì bạn mới xử lý, không biết phía trước là gì. Trừ khi bạn “xử lý offline” (đọc toàn bộ file vào 1 string rồi xử lý) thì bạn mới biết kí tự phía sau là gì.

Còn câu 3 thì trước mắt bạn cần học Toán rời rạc đã :kissing:

2 Likes

Em nghĩ nguyên nhân some/*crazy /*crazy*/*/stuff chỉ ra somestuff bởi vì khi đã đóng comment tại vị trí crazy*/ , kí tự current sẽ chuyển đến * và previous là /, ở đây sẽ trở thành sự trùng lặp khi comment phía trước lại được cân nhắc và trở thành 1 commnt mới, sau đó nó tiếp tục chuyển đến vị trí / và previous là *. Từ đó dẫn đến bị mất kí tự cuối */, nhưng em thấy trường hợp này hơi hóc với em rồi. Em vừa thử thêm nhiều biến signal và while loop nhưng thấy hơi rối nên em đang thử lại cách khác.

Một ý tưởng em nghĩ ra đó là nếu đã là phát hiện của /* hoặc */ thì nên đẩy vị trí current và previous lên 2 lần ? Nhưng nếu như vậy thì coi như cái xử lý phía trên của em trở nên vô dụng (?)

Không biết anh gợi ý giúp em hướng tiếp cận nào dễ để em có thể hoàn thiện không, chứ em hơi đuối rồi.

Sau khi kết thúc 1 block comment, bạn thử gán previous = ' ' (xoá trạng thái trước đó) đi xem sao.

1 Like
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUF_SIZE 64 

int main(int argc, char **argv)
{
	FILE *inFilePtr;
    char fileName[BUF_SIZE];
    char previous_char = ' ';
    char current_char;
    int is_quote_opening = 0; 
    int is_comment_opening = 0;
    int is_comment_closing = 1;
    puts("Enter file name for checking comments: "); 
    scanf("%s", &fileName);
    int line = 1; 
    
    if((inFilePtr = fopen(fileName, "r")) != NULL)
    {
        
        FILE *outFilePtr;
        
        if((outFilePtr = fopen("result.txt", "w")) != NULL)
        {
            while((current_char = fgetc(inFilePtr)) != EOF)
            {
                if(current_char == '\n')
                {
                    line++;
                }
                if(current_char == '"' && is_comment_opening == 0)
                {
                   if(is_quote_opening == 0)
                   {
                       fputc(current_char, outFilePtr);
                       is_quote_opening = 1; 
                   }
                   else if(is_quote_opening == 1)
                   {
                       fputc(current_char, outFilePtr);
                       is_quote_opening = 0;
                   }
                   
                }
                else if(current_char == '*' && previous_char == '/')
                {
                    is_comment_opening = 1;
                    is_comment_closing = 0;
                    previous_char = ' ';
                    continue;
                    
                  
                }
                else if(current_char == '/' && previous_char == '*')
                {
                    is_comment_opening = 0;
                    is_comment_closing = 1;
                    previous_char = ' ';
                    continue;
                }
                else
                {
//                    if(is_quote_opening == 1)
//                    {
//                        fputc(current_char, outFilePtr);
//                    }
                    if(is_comment_opening == 1)
                    {
                        //Don't do anything
                    }
                    else if(current_char == '/')
                    {
                        //Temporarily skip
                        
                        
                    }
                    else
                    {
                        if(previous_char == '/' && is_comment_closing != 1)
                        {
                            
                            fputc(previous_char, outFilePtr);
                        }
                        
                        fputc(current_char, outFilePtr);
                    }
                    
                    
                }
                
                previous_char = current_char;
            }
            fclose(outFilePtr);
            if(is_quote_opening == 1)
            {
                puts("Error, quotes doesn't close");
            }
            if(is_comment_opening == 1)
            {
                puts("Error: Unterminated comment");
                printf("Comment began at line %d", line);
            }
            fclose(inFilePtr);
        }
        else
        {
            puts("Problem occurred when creating file for new input");
        }
    }
    else
    {
        printf("File \"%s\" couldn't be opened\n", fileName);
    }
               
}

Như vậy em sẽ ra KQ là some*stuff.
Vì sao không ra some*/stuff? Bởi vì khi kết thúc block comment, biến signal is_comment closing sẽ bằng 1.
Khi xét current char là “s”, previous char là “/”, kí tự / trước đó sẽ không được ghi lại bởi vì is_comment_closing = 1 (chỉ ghi khi khác 1, điều này để loại bỏ trường hợp kí tự previous trước đó là ‘/’ mà anh đã hướng dẫn em fix).
Em có thử một cách này nhưng không được (trước khi anh giới thiệu cách previous_char = " ").
Đó là em thử mỗi lần mở hoặc đóng comment xác nhận, em sẽ đẩy current char lên 1 kí tự, sau đó ngoài cái if để previous_char = current_char, khi đó khi while được thực hiện lại thì nó đã hoàn toàn đẩy lên cụm kí tự mới.

[Em có nói sảng chỗ nào anh thông cảm, do giờ mấy cái này em diễn giải ra mới thấy em hóc chỗ nào]

À ha :v
Em tìm ra rồi nha. Hóa ra là điều kiện cho trường hợp current character là một kí được xét trong trường hợp else.
Bởi vì

  • Khi previous_char = ‘/’ mà kí tự tiếp theo là “a” chẳng hạn, thì mình phải xét là liệu is_comment_opening có mở ra không?
  • Khi previous_char = ‘*’ mà kí tự tiếp theo là “a” chẳng hạn, thì mình lại xét is_comment_closing có bằng 0 hay không?

Hay được diễn tả bằng code sẽ như sau:

if(previous_char == '/' && is_comment_opening == 0 && is_quote_opening == 0)
{
    
    fputc(previous_char, outFilePtr);
}
if(previous_char == '*' && is_comment_closing == 1 && is_quote_opening == 0)
{
    fputc(previous_char, outFilePtr);
}
fputc(current_char, outFilePtr);

CODE TỔNG QUÁT:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUF_SIZE 64 

int main(int argc, char **argv)
{
    FILE *inFilePtr;
    char fileName[BUF_SIZE];
    char previous_char = ' ';
    char current_char;
    int is_quote_opening = 0; 
    int is_comment_opening = 0;
    int is_comment_closing = 1;
    puts("Enter file name for checking comments: "); 
    scanf("%s", &fileName);
    int line = 1; 
    
    if((inFilePtr = fopen(fileName, "r")) != NULL)
    {
        
        FILE *outFilePtr;
        
        if((outFilePtr = fopen("result.txt", "w")) != NULL)
        {
            while((current_char = fgetc(inFilePtr)) != EOF)
            {
                if(current_char == '\n')
                {
                    line++;
                }
                if(current_char == '"' && is_comment_opening == 0)
                {
                   if(is_quote_opening == 0)
                   {
                       fputc(current_char, outFilePtr);
                       is_quote_opening = 1; 
                   }
                   else if(is_quote_opening == 1)
                   {
                       fputc(current_char, outFilePtr);
                       is_quote_opening = 0;
                   }
                   
                }
                else if(current_char == '*' && previous_char == '/' && is_quote_opening == 0)
                {
                    is_comment_opening = 1;
                    is_comment_closing = 0;
                    previous_char = ' ';
                    continue;
                    
                  
                }
                else if(current_char == '/' && previous_char == '*' && is_comment_opening == 1 && is_quote_opening == 0)
                {
                    is_comment_opening = 0;
                    is_comment_closing = 1;
                    previous_char = ' ';
                    continue;
                }
                else
                {

                    if(is_comment_opening == 1)
                    {
                        //Don't do anything
                    }
                    else if(current_char == '/')
                    {
                        //Temporarily skip
                        
                        
                    }
                    else
                    {
                        if(previous_char == '/' && is_comment_opening == 0 && is_quote_opening == 0)
                        {
                            
                            fputc(previous_char, outFilePtr);
                        }
                        if(previous_char == '*' && is_comment_closing == 1 && is_quote_opening == 0)
                        {
                            fputc(previous_char, outFilePtr);
                        }
                        fputc(current_char, outFilePtr);
                    }
                    
                    
                }
                
                previous_char = current_char;
            }
            fclose(outFilePtr);
            if(is_quote_opening == 1)
            {
                puts("Error, quotes doesn't close");
            }
            if(is_comment_opening == 1)
            {
                puts("Error: Unterminated comment");
                printf("Comment began at line %d", line);
            }
            fclose(inFilePtr);
        }
        else
        {
            puts("Problem occurred when creating file for new input");
        }
    }
    else
    {
        printf("File \"%s\" couldn't be opened\n", fileName);
    }
               
}

Về các testing em nghĩ là OK rồi (theo suy nghĩ của em :v).
Nhưng cảm nhận về sự tối ưu thì cũng chưa. Có gì để lát em mò tiếp. Nhưng mà mò ra được chỗ xét điều kiện đúng em vui vler :)))

2 Likes

Bạn phải xác định xem với case kép như vậy thì có được coi là comment không đã. Nếu không thì sơ đồ mà @noname00 đưa ra đã cover được đầy đủ các trường hợp cần rồi.
Tất nhiên bạn có thể muốn xử lí hơn thế để clean được comment trong 1 đoạn code bị sai cú pháp thì nghiên cứu thêm để xử lí cũng rất hay

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