ฉันจะส่งออก UTF-8 จาก Perl ได้อย่างไร


110

ฉันพยายามเขียนสคริปต์ Perl โดยใช้ pragma "utf8" และได้ผลลัพธ์ที่ไม่คาดคิด ฉันใช้ Mac OS X 10.5 (Leopard) และกำลังแก้ไขด้วย TextMate การตั้งค่าทั้งหมดของฉันสำหรับทั้งตัวแก้ไขและระบบปฏิบัติการของฉันเป็นค่าเริ่มต้นในการเขียนไฟล์ในรูปแบบ utf-8

อย่างไรก็ตามเมื่อฉันป้อนสิ่งต่อไปนี้ลงในไฟล์ข้อความบันทึกเป็น ".pl" และดำเนินการฉันได้รับ "เพชรที่มีเครื่องหมายคำถาม" ที่เป็นมิตรแทนอักขระที่ไม่ใช่ ASCII

#!/usr/bin/env perl -w

use strict;
use utf8;

my $str = 'Çirçös';
print( "$str\n" );

มีความคิดว่าฉันทำอะไรผิดหรือเปล่า? ฉันคาดหวังว่าจะได้ 'Çirçös' ในผลลัพธ์ แต่ฉันได้ ' ir s' แทน


1
อาจจะไม่ใช่โปรแกรมก็ได้ .. ฉันคิดว่ามันเป็นเชลล์ของคุณมากกว่าตัวแก้ไขของคุณซึ่งทำผลลัพธ์
n00ki3

คำตอบทั้งหมดตอบคำถามของคุณได้อย่างถูกต้องว่าจะตั้งค่าเป็น UTF8 อย่างไร ฉันคิดว่าคุณควรจะปรับตัวเข้ากับการตั้งค่าตำแหน่งที่ตั้งของสถานีของคุณตามที่แสดงในstackoverflow.com/a/14405949/498634 เทอร์มินัลอาจไม่ได้ตั้งค่าเป็น UTF8 จากนั้นข้อมูลที่เขียนถึง STDOUT ใน UTF8 จะถูกเข้ารหัสอย่างไม่ถูกต้อง !
Daniel Böhmer

คำตอบที่ดีในการทำงานกับutf8:
Eugen Konkov

คำตอบ:


160

use utf8;ไม่เปิดใช้งานเอาต์พุต Unicode - ช่วยให้คุณสามารถพิมพ์ Unicode ในโปรแกรมของคุณได้ เพิ่มสิ่งนี้ลงในโปรแกรมก่อนprint()คำสั่งของคุณ:

binmode(STDOUT, ":utf8");

ดูว่าช่วยได้ไหม สิ่งนี้ควรทำให้STDOUTเอาต์พุตเป็น UTF-8 แทน ASCII ธรรมดา


ฉันไม่รู้เกี่ยวกับเรื่องนี้ (ฉันใส่ UTF8 ในฐานข้อมูลเท่านั้นไม่เคยพิมพ์เลย) +1.
Paul Tomblin

1
ยินดีต้อนรับ ดูคำตอบที่ถูกต้องอีกคำตอบ: stackoverflow.com/questions/627661/writing-perl-code-in-utf8/…และจำไว้ว่า TMTOWTDI และ @Paul - ถ้าคุณกำลังเขียน UTF-8 ลงในไฟล์คุณควรใช้ binmode () กับ filehandle นั้นและทำให้เป็น UTF-8 ที่ "เหมาะสม" แต่ถ้ามันใช้งานได้ ..
Chris Lutz

1
วิธีอื่น ๆ : pragma ที่เปิด ( search.cpan.org/perldoc/open ), สวิตช์ -C ( perldoc.perl.org/perlrun.html#-C )
ysth

1
FWIW นี่คือเหตุผล: สตริงที่มีเฉพาะอักขระ latin1 (ISO-8859-1) แม้ว่าจะถูกเก็บไว้มากหรือน้อยใน utf8 แต่จะได้รับเอาต์พุตเป็น latin1 ตามค่าเริ่มต้น ด้วยวิธีนี้สคริปต์จากยุคก่อน Unicode ยังคงทำงานเหมือนเดิมแม้ว่าจะมี Unicode-Aware Perl ก็ตาม
mirod

3
utf8 pragma ไม่อนุญาตให้คุณเขียนซอร์สของคุณใน UNICODE มันบังคับให้เข้าใจแหล่งที่มาของคุณในการเข้ารหัส UTF-8 (หรือ UTF-EBCDIC) ของ UNICODE ซึ่งเป็นความแตกต่างที่สำคัญ
Chas. Owens

83

คุณสามารถใช้เปิด pragma

สำหรับเช่น ด้านล่างตั้งค่า STDOUT, STDIN & STDERR ให้ใช้ UTF-8 ....

use open qw/:std :utf8/;

1
BTW ... ฉันให้คุณ +1 ฉันคิดว่า binmode (STDOUT, ': utf8') น่าจะถูกต้องกว่าในสถานการณ์นี้ "use open" มีประโยชน์อื่น ๆ แต่ฉันไม่พบวิธีตั้งค่าให้เข้ารหัส STDOUT เท่านั้น?
draegtun

66

TMTOWTDIเลือกวิธีที่เหมาะกับวิธีการทำงานของคุณมากที่สุด ฉันใช้วิธีสภาพแวดล้อมดังนั้นฉันไม่ต้องคิดเกี่ยวกับมัน

ในสิ่งแวดล้อม :

export PERL_UNICODE=SDL

ในบรรทัดคำสั่ง :

perl -CSDL -le 'print "\x{1815}"';

หรือด้วยbinmode :

binmode(STDOUT, ":utf8");          #treat as if it is UTF-8
binmode(STDIN, ":encoding(utf8)"); #actually check if it is UTF-8

หรือด้วยPerlIO :

open my $fh, ">:utf8", $filename
    or die "could not open $filename: $!\n";

open my $fh, "<:encoding(utf-8)", $filename
    or die "could not open $filename: $!\n";

หรือด้วยpragma แบบเปิด :

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";

1
+1 สำหรับคำตอบที่ครอบคลุม สังเกตSDLโดยนัยทั้งกับ-CและPERL_UNICODE. use open ':locale'pragma ยังเป็นมูลค่าการกล่าวขวัญเพราะมันเป็นเทียบเท่าในสคริปต์ของและ-C export PER_UNICODE=3 สิ่งเหล่านี้จะให้การสนับสนุน UTF8 สำหรับสตรีมอินพุตและเอาต์พุตทั้งหมด (ไม่ว่าจะเป็นไฟล์หรือ stdin / stdout / stderr) โดยสมมติว่าโลแคลของสภาพแวดล้อมของคุณเป็นแบบ UTF8 สุดท้ายหากต้องการรักษาซอร์สโค้ดเป็น UTF8 ให้ใช้use utf8;pragma
mklement0

perl -Mutf8 -CSDL -e '...'อนุญาตให้ใช้ / เอาต์พุต UTF-8 และใช้ตัวอักษร UTF-8 ภายใน-eเช่นสำหรับโฟลเดอร์เคสของคนจน:perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
vladr


0

ขอขอบคุณในที่สุดก็มีวิธีแก้ไขที่จะไม่ใส่ utf8 :: เข้ารหัสทับโค้ด เพื่อสังเคราะห์และทำให้สมบูรณ์สำหรับกรณีอื่น ๆ เช่นเขียนและอ่านไฟล์ใน utf8 และยังทำงานร่วมกับ LoadFile ของไฟล์ YAML ใน utf8

use utf8;
use open ':encoding(utf8)';
binmode(STDOUT, ":utf8");

open(FH, ">test.txt"); 
print FH "something éá";

use YAML qw(LoadFile Dump);
my $PUBS = LoadFile("cache.yaml");
my $f = "2917";
my $ref = $PUBS->{$f};
print "$f \"".$ref->{name}."\" ". $ref->{primary_uri}." ";

โดยที่ cache.yaml คือ:

---
2917:
  id: 2917
  name: Semanário
  primary_uri: 2917.xml

-3

ทำในเชลล์ของคุณ: $ env | grep LANG

นี่อาจจะแสดงว่าเชลล์ของคุณไม่ได้ใช้ภาษา utf-8


ที่จริงมันถูกตั้งค่าเป็น utf-8 ปัญหาคือฉันส่งออกไปยัง STDOUT โดยไม่ได้ตั้งค่า binmode เป็น utf-8

2
นี่จะเป็นข้อกังวลที่ตั้งฉากกัน คุณต้องใช้สคริปต์ Perl ของคุณเพื่อส่งออกข้อมูลที่ถูกต้องก่อนที่คุณจะไม่ต้องกังวลว่าโปรแกรมจำลองเทอร์มินัลของคุณตีความอย่างไร
jrockway
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.