Vẽ Sơ Đồ Quan Hệ Bằng Ascii - nói dối e blog

Vẽ Sơ Đồ Quan Hệ Bằng Ascii

Tại sao nên dùng nghệ thuật ASCII để vẽ sơ đồ quan hệ?

Khi viết tài liệu kỹ thuật, đôi khi chỉ mô tả bằng văn bản khó truyền đạt rõ ràng. Trong những trường hợp như vậy, việc chèn sơ đồ minh họa trực quan vào tài liệu là giải pháp tối ưu. Mặc dù công cụ Graphviz với cú pháp DOT rất tiện lợi để biểu diễn đồ thị, nhưng yêu cầu phải có phần mềm chuyên dụng để hiển thị. Do đó, trong môi trường văn bản thuần túy, nghệ thuật ASCII art vẫn là lựa chọn phù hợp nhất để minh họa trực quan.

Giải pháp hiện có và hạn chế

Tôi đã khảo sát và phát hiện Perl module Graph::Easy là công cụ duy nhất hỗ trợ xuất đầu ra ASCII art chuyên nghiệp. Tuy nhiên, công cụ này gặp vấn đề tương thích với chữ viết tiếng Việt. Mặc dù tài liệu quảng cáo hỗ trợ Unicode đầy đủ, nhưng khi dùng ký tự tiếng Trung (chữ Hán) để xuất ra ASCII, kết quả thường bị lệch định dạng.

Vấn đề phát sinh từ đặc thù hiển thị ký tự:

  1. Trong mã hóa UTF-8, một ký tự tiếng Trung chiếm 3 byte
  2. Trên phông chữ monospace, độ rộng hiển thị của chữ Hán gấp 2 lần ký tự Latin thông thường

Cơ chế định dạng trong Graph::Easy

Module này sử dụng cơ chế “bộ nhớ khung” ảo (2D character array) để xây dựng sơ đồ. Vấn đề nằm ở hàm tính chiều rộng nhãn (label width):

  • Ban đầu, tôi thử sửa hàm tính chiều rộng nhãn để trả về giá trị chính xác theo độ rộng hiển thị thực tế
  • Tuy nhiên, kết quả vẫn sai lệch vì module có cơ chế ghi chồng ký tự theo tọa độ ngẫu nhiên
  • Khi ghi ký tự tiếng Trung vào vị trí x, các ký tự bên phải sẽ bị đẩy lệch tọa độ mà module không tự xử lý được

Giải pháp tối ưu hóa

Tôi đã tìm ra phương pháp “hack” hiệu quả:

  1. Khi đọc chuỗi nhãn, thêm ký tự đặc biệt U+FFFF (không tồn tại trong thực tế) sau mỗi ký tự tiếng Trung
  2. Ký tự này giúp module nhận biết chính xác độ rộng hiển thị (coi mỗi ký tự tiếng Trung = 2 ô ASCII)
  3. Ở bước xuất kết quả cuối cùng, loại bỏ toàn bộ ký tự U+FFFF

Cơ chế này tận dụng sẵn hàm escape chuỗi có sẵn của module (tương tự xử lý \n), giúp giảm thiểu thay đổi mã nguồn và đảm bảo tương thích.

Patch cụ thể (phiên bản Graph-Easy 0.76)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
diff --git a/lib/Graph/Easy.pm b/lib/Graph/Easy.pm
index 0ae40fd..b67bacc 100644
--- a/lib/Graph/Easy.pm
+++ b/lib/Graph/Easy.pm
@@ -1570,7 +1570,9 @@ sub as_ascii
  # kích hoạt chế độ 'ascii'
  $self->{_ascii_style} = 0;
- $self->_as_ascii(@_);
+ my $asc = $self->_as_ascii(@_);
+ $asc =~ s/(\x{FFFF})//g; # xóa các ký tự placeholder
+ $asc;
  }

diff --git a/lib/Graph/Easy/Node.pm b/lib/Graph/Easy/Node.pm
index b58f538..6d7d7c7 100644
--- a/lib/Graph/Easy/Node.pm
+++ b/lib/Graph/Easy/Node.pm
@@ -1503,6 +1503,9 @@ sub label
  $label = $self->_un_escape($label) if !$_[0] && $label =~ /\\[EGHNT]/;
+ # thêm cờ placeholder cho ký tự tiếng Trung
+ $label =~ s/([\x{4E00}-\x{9FFF}])/$1\x{FFFF}/g;
+
  $label;
  }

Lưu ý khi sử dụng

Hiện tại kho lưu trữ trên GitHub không được tác giả chính bảo trì, trong khi phiên bản trên CPAN lại không hỗ trợ chức năng mở issue. Do đó, bạn có thể tự áp dụng patch trên để hỗ trợ tiếng Việt trong ASCII art của Graph::Easy. Giải pháp này tuy không hoàn hảo nhưng đáp ứng tốt nhu cầu cơ bản mà không cần thay đổi sâu trong kiến trúc module.

Bài viết đã được cập nhật và tối ưu hóa để phù hợp với đặc thù tiếng Việt. Mọi đóng góp cải tiến xin gửi về địa chỉ email: [email@example.com] (mục đích minh họa).

0%