Cách nhập tiếng Việt từ Console?

Chào mọi người, mình đang làm 1 Project Console nhưng cần nhập tiếng việt từ Console, mình đã thử cách sau :

package test_1;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.Scanner;

public class Test_1 {

    public static void main(String[] args) throws UnsupportedEncodingException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF8"));
        Scanner scan = new Scanner(in);
        System.out.println("Nhập chuỗi Tiếng Việt:  ");
        String ans = scan.nextLine();
        scan.close();
        System.out.println("Ket qua: " + ans);
    }

}

Mọi người cho mình hỏi là sai chỗ nào với ạ ? Thanks All

1 Like

cho hỏi bạn dùng ide hay text editor gì vậy

2 Likes

Vote xài API mới: System.console, xài cái này thì ko cần lo lắng về encoding nữa.

BufferedReader in = new BufferedReader(System.console().reader());
Nguồn tham khảo:

Nếu không thì làm trên Windows thì phải dùng trực tiếp WinAPI (siêu khó).

3 Likes

Mình dùng Netbean bạn ạ :))

2 Likes

Nó bị lỗi này bạn ạ @@

1 Like

Mình tự hỏi tại sao bạn sử dụng BufferedReader rồi lại sử dụng Scanner làm gì nữa ???
Đây là code mình sửa:

package chap01.basic;

import java.io.*;

public class Test {

	public static void main(String[] args) {
		
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("Nhập chuỗi Tiếng Việt:  ");
		
		String ans = "";
		
		try {
			ans = in.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		System.out.println("Kết quả: " + ans);
	}
}

1 Like

Đây là mình run trên Netbean, nó vẫn bị lỗi vậy @@ Thanks bạn

Thử lưu file dưới định dạng UTF-8 xem sao !

Người ta đọc từ console chứ không phải từ file, cũng không ghi ra file.
Cái này bug ngay từ lúc đọc rồi, chứ out.print xử lý tốt Unicode.

2 Likes

OK, sau một lúc nghiên cứu thì mình cũng biết thế nào rồi:

API System.console không xài được với redirected terminal (VD terminal được tích hợp của IDE), nó trả null, mà nó cũng không có cho tự chỉnh Unicode gì ráo (chỉ có auto detect encoding thôi), bên trên mình nhầm lẫn cho mình xin lỗi.
Ở trên các hệ điều hành họ Unix thì bạn cứ nhập xuất bình thường không cần chỉnh thêm, nó mặc định UTF8 cả.

Ở trên Windows thì khá phức tạp:

  • Input sẽ từ UTF-16LE (encoding của HĐH Windows) qua Input Encoder của terminal rồi mới qua được đến Input Decoder của Java (InputStreamReader, Scanner, v.v.). Input Encoding của CMD thì thường là Cp437; trong NetBeans (redirected terminal) thì vì một lý do nào đó, Input Encoding luôn là ISO-8859-1; trong Eclipse thì Input Encoding đi theo Project Setting, mặc định là UTF-8.
  • Output thì tương tự, đi từ UTF-16LE (encoding của class String trong Java) qua Output Encoder của Java, rồi mới qua Output Decoder của terminal. Output Encoding của CMD cũng thường là Cp437, trong NetBeans hoặc Eclipse thì đều theo project setting mặc định là UTF-8.

Tóm lại trên Windows thì thường là:

  • Input: UTF-16LE 🡲(1)🡲 Cp437 🡲(2)🡲 UTF-16LE
  • Output: UTF-16LE 🡲(3)🡲 Cp437 🡲(4)🡲 UTF-16LE

Terminal của NetBeans thì mặc định là:

  • Input: UTF-16LE 🡲(1)🡲 ISO-8859-1 🡲(2)🡲 UTF-16LE
  • Output: UTF-16LE 🡲(3)🡲 UTF-8 🡲(4)🡲 UTF-16LE

Terminal của các IDE khác:

  • Input: UTF-16LE 🡲(1)🡲 UTF-8 🡲(2)🡲 UTF-16LE
  • Output: UTF-16LE 🡲(3)🡲 UTF-8 🡲(4)🡲 UTF-16LE

Vậy thì phải điều chỉnh Input Decoder và Encoder của Java cho đúng với Encoding trung gian kia (số (2) và số (3) ) :
Input:

BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "Cp437"));

Dành cho NetBeans

BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "ISO-8859-1"));

Dành cho những IDE còn lại:

BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));

Ouput thì: (Copy lại của bác Joe)

System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out),true,"Cp437"));
System.out.println("àáä");

Trong bất kì IDE nào thì:

System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out),true,"UTF-8"));
System.out.println("àáä");

Và giờ đến vấn đề khó nhất: làm sao để biết Input Encoder và Ouput Decoder của Console ( số (1) và số (4) ) chúng đang được để ở Encoding nào? Trên Windows, nếu đổi system locale sang Tiếng Nhật chẳng hạn, Input Encoder và Ouput Decoder cũng thay đổi theo. Hay thậm chí là encoding của chính cái redirect terminal. Và có cách nào để dùng code Java để thay đổi tạm thời 2 cái số (1) và số (4) theo ý muốn không (chỉ có Cp1258, UTF-16, UTF-8 là có Tiếng Việt)?
Rất tiếc là Java không có cách nào standard để làm điều đó cả (C# thì có). Link này https://stackoverflow.com/questions/6172972/how-to-get-console-charset có một số cách get bằng Reflection, nhưng không sửa lại được bằng code.
Nếu ko dùng chuẩn Java thì có thể dùng WinAPI như SetConsoleCP, SetConsoleOutputCP, hoặc run chcp (nhưng sẽ gây ảnh hưởng đến các app khác chạy sau nếu có trong cùng cửa số console):

new ProcessBuilder("cmd.exe", "/c", "chcp", "65001")
     .inheritIO().start().waitFor();

(Nếu chỉnh CMD input encoding sang UTF-8 thì còn dính bug: https://social.msdn.microsoft.com/Forums/vstudio/en-US/6db367e1-6b39-4c91-bd08-e3779ae5fc23/problems-with-readingwriting-utf8-characters-to-console?forum=vcgeneral, tới Windows 10 mà Microsoft vẫn chưa thèm sửa, may mà không ảnh hưởng gì tới redirected terminal)

Vậy nếu trên Windows thì cách chuẩn nhất là xài chính API của Windows, và thao tác trực tiếp trên UTF-16LE thông qua các API W luôn mà không phải thông qua Decoder và Encoder trung gian. Cái này thì lại là 1 thứ hết sức phức tạp khác, bạn tham khảo 2 link sau:
https://illegalargumentexception.blogspot.com/2009/04/java-unicode-on-windows-command-line.html
https://illegalargumentexception.blogspot.com/2009/04/i18n-unicode-at-windows-command-prompt.html

11 Likes

The first post example can be simplified, I know that. But your example will not work for Vietnamese language. We need UTF-8 or UTF-16 to display Vietnamese language, but the console encoding is not set to that (setting encoding of Scanner or FileOutputStream to UTF-8 or UTF-16 will not work because the underlying encoding of terminal is intact). So one has to understand how all of this works.

I written that too in my post :slight_smile:
That why I suggested @anon12276517 to use another way specially for Windows:

https://illegalargumentexception.blogspot.com/2009/04/java-unicode-on-windows-command-line.html
https://illegalargumentexception.blogspot.com/2009/04/i18n-unicode-at-windows-command-prompt.html

Cảm ơn bạn :smile::slight_smile: mình nghĩ là nó phụ thuộc vào IDE mà mình đang dùng và lấy theo OS của mình :slight_smile:

I think it depends on the IDE that I am using and taking my OS :slight_smile: :slight_smile: Thank you :slight_smile:

Thật ra bạn nên hiểu cách nó hoạt động (post của mình đã ghi rõ), chứ đừng dựa dẫm quá vào IDE, nếu bạn chạy jar ngoài IDE thì sao?
Chỉ có UTF-8, UTF-16 và CP1258 (Tiếng Việt Unicode Tổ hợp) là support cho Tiếng Việt thôi (không tính đến các bảng mã “mượn” Iso-8859-1 như VNI, TCVN3, v.v.).

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