Sử dụng 'use utf8;' cho tôi 'Ký tự rộng trong bản in'


86

Nếu tôi chạy chương trình Perl sau:

perl -e 'use utf8; print "鸡\n";'

Tôi nhận được cảnh báo này:

Wide character in print at -e line 1.

Nếu tôi chạy chương trình Perl này:

perl -e 'print "鸡\n";'

Tôi không nhận được một cảnh báo.

Tôi nghĩ rằng use utf8bắt buộc phải sử dụng các ký tự UTF-8 trong tập lệnh Perl. Tại sao điều này không hoạt động và làm thế nào tôi có thể sửa chữa nó? Tôi đang sử dụng Perl 5.16.2. Tôi gặp vấn đề tương tự nếu điều này nằm trong một tệp thay vì là một lớp lót trên dòng lệnh.


3
"Tại sao cai nay không hoạt động?" Nó không làm việc, nhưng nó được kinh nghiệm của tôi với Unicode rằng có rất nhiều chương trình rất nổ ra ở đó mà nhìn giống như họ đang làm việc. Khi bạn sửa một điều, làm cho mã ít sai hơn một chút, kết quả có vẻ tệ hơn rất nhiều. Chỉ khi bạn sửa phần cuối cùng thì mọi thứ mới có vẻ tốt trở lại.
hobbs

Câu trả lời:


110

Không có use utf8Perl diễn giải chuỗi của bạn là một chuỗi các ký tự byte đơn. Có bốn byte trong chuỗi của bạn như bạn có thể thấy từ sau:

$ perl -E 'say join ":", map { ord } split //, "鸡\n";'
233:184:161:10

Ba byte đầu tiên tạo nên nhân vật của bạn, byte cuối cùng là dòng cấp dữ liệu.

Lệnh gọi để printgửi bốn ký tự này tới STDOUT. Bảng điều khiển của bạn sau đó sẽ tìm ra cách hiển thị các ký tự này. Nếu bảng điều khiển của bạn được đặt để sử dụng UTF8, thì nó sẽ diễn giải ba byte đó là ký tự đơn của bạn và đó là những gì được hiển thị.

Nếu chúng ta thêm vào utf8mô-đun, mọi thứ sẽ khác. Trong trường hợp này, Perl diễn giải chuỗi của bạn chỉ là hai ký tự.

$ perl -Mutf8 -E 'say join ":", map { ord } split //, "鸡\n";'
40481:10

Theo mặc định, lớp IO của Perl giả định rằng nó đang hoạt động với các ký tự byte đơn. Vì vậy, khi bạn cố gắng in một ký tự nhiều byte, Perl nghĩ rằng có gì đó không ổn và đưa ra cảnh báo cho bạn. Như mọi khi, bạn có thể nhận được thêm lời giải thích cho lỗi này bằng cách bao gồm use diagnostics. Nó sẽ nói thế này:

(S utf8) Perl đã gặp một ký tự rộng (> 255) khi nó không mong đợi một ký tự. Cảnh báo này được bật theo mặc định cho I / O (như in). Cách dễ nhất để giảm bớt cảnh báo này chỉ đơn giản là thêm lớp: utf8 vào đầu ra, ví dụ như binmode STDOUT, ': utf8'. Một cách khác để tắt cảnh báo là thêm không có cảnh báo nào 'utf8'; nhưng điều đó thường gần với gian lận hơn. Nói chung, bạn phải đánh dấu rõ ràng xử lý tệp bằng mã hóa, hãy xem mở và perlfunc / binmode.

Như những người khác đã chỉ ra, bạn cần yêu cầu Perl chấp nhận đầu ra nhiều byte. Có nhiều cách để thực hiện việc này (xem Hướng dẫn Perl Unicode để biết một số ví dụ). Một trong những cách đơn giản nhất là sử dụng -CScờ dòng lệnh - nó cho ba bộ xử lý tệp tiêu chuẩn (STDIN, STDOUT và STDERR) để đối phó với UTF8.

$ perl -Mutf8 -e 'print "鸡\n";'
Wide character in print at -e line 1.
鸡

vs

$ perl -Mutf8 -CS -e 'print "鸡\n";'

Unicode là một lĩnh vực lớn và phức tạp. Như bạn đã thấy, nhiều chương trình đơn giản dường như hoạt động đúng nhưng vì những lý do sai lầm. Khi bạn bắt đầu sửa một phần của chương trình, mọi thứ thường sẽ trở nên tồi tệ hơn cho đến khi bạn sửa xong tất cả chương trình.


Làm thế nào để đánh vần -Mutf8nếu không phải trong một lớp lót?
Lei Yang

@LeiYang:use utf8;
Dave Cross

80

Tất cả những gì use utf8;cần làm là cho Perl biết mã nguồn được mã hóa bằng UTF-8. Bạn cần cho Perl biết cách mã hóa văn bản của bạn:

use open ':std', ':encoding(UTF-8)';

Cảm ơn, điều này hoạt động tốt cho các chương trình được lưu trữ trong tệp, trái ngược với một dòng lệnh trên dòng lệnh, mà câu trả lời của @ DaveCross bao gồm.
vktec

19

Mã hóa tất cả đầu ra tiêu chuẩn dưới dạng UTF-8:

binmode STDOUT, ":utf8";

2
use open ':std', ':encoding(UTF-8)';như được đề xuất bởi một câu trả lời khác, điều này cho STDOUT nhưng cũng đánh dấu STDERR và STDIN là UTF-8, vì vậy bạn nhận được ba cho giá của một câu lệnh. Xem thêm stackoverflow.com/a/42194059
Stephen Ostermiller

Đồng ý. Điều này thậm chí còn tốt hơn.
Boris Ivanov

14

Bạn có thể đến gần "chỉ làm utf8 ở mọi nơi" bằng cách sử dụng mô-đun CPAN utf8::all.

perl -Mutf8::all -e 'print "鸡\n";'

Khi printnhận được thứ gì đó mà nó không thể in (ký tự lớn hơn 255 khi không có :encodinglớp nào được cung cấp), nó sẽ giả định rằng bạn muốn mã hóa nó bằng UTF-8. Nó làm như vậy, sau khi cảnh báo về vấn đề.


5

Bạn có thể sử dụng cái này,

perl -CS filename.

Nó cũng sẽ chấm dứt lỗi đó.


chỉ điều này đã giúp
muenalan

0

Trong tiếng Tây Ban Nha, bạn có thể tìm thấy lỗi này khi bên cạnh bắt đầu sử dụng:

use utf8;

Mã hóa trình chỉnh sửa của bạn là một mã hóa khác. Vì vậy, những gì bạn thấy trên trình chỉnh sửa không phải là những gì Perl làm. Để giải quyết lỗi đó, chỉ cần thay đổi mã hóa trình soạn thảo thành Unicode / UTF-8 .


1
Không. Đây không phải là nguyên nhân gây ra lỗi. Tất cả mã đều được mã hóa đúng thành UTF8 nhưng bộ xử lý tệp đầu ra không biết rằng đó là.
Dave Cross
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.