2016-10-23 23 views
11

Bazı dizelerde aksan işaretlerini kaldırmak istiyorum. tr/// işi yapmak gerekirdi ama (aşağıya bakınız) başarısız. Ben bir kodlama/kod çözme sorunu vardı, ama beklediğim gibi ben s/// eser ettim. Birisi nedenini açıklayabilir mi? İşte Perl: tr /// beklediğim şeyi yapmıyorken ///

sonuçların bir örnektir alıyorum:

my $str1 = 'èîü'; 
my $str2 = $str1; 
$str1 =~ tr/î/i/; 
print "$str1\n"; # => i�iii� 
$str2 =~ s/î/i/; 
print "$str2\n"; # => èiü 

tr/// da dize değil, sadece ortadaki birinin birinci ve üçüncü karakterleri değiştirilmiş Not söyledi.

Düzenleme: Ubuntu 16.04'ü Mate masaüstü ortamı ile kullanıyorum. Benim için beklendiği gibi çalışır

cevap

18

use utf8;'a sahip değilseniz, ancak kodu bir utf8 metin düzenleyicisiyle görüntülüyorsanız, perl'in görmediği yolu görmezsiniz. s/// ve tr///'un sol yarısında tek bir karakterin olduğunu düşünürsünüz, ancak çoklu bayt olduğu için perl bunu birden çok karakter olarak görür.

Eğer perl görüyor Ne:

my $str1 = "\xE8\xEE\xFC"; 
my $str2 = $str1; 
$str1 =~ tr/\xEE/i/; 
print "$str1\n"; 
$str2 =~ s/\xEE/i/; 
print "$str2\n"; 

Ne Perl aslında görür: s/// ile

my $str1 = "\xC3\xA8\xC3\xAE\xC3\xBC"; 
my $str2 = $str1; 
$str1 =~ tr/\xC3\xAE/i/; 
print "$str1\n"; 
$str2 =~ s/\xC3\xAE/i/; 
print "$str2\n"; 

, karakterlerin hiçbiri regexp operatörleri olduğundan, sadece bir alt dize arama yapıyoruz. Çok karakterli bir alt dizgi arıyorsunuz. Ve onu bulursunuz, çünkü s///'unuzda gerçekleşen aynı şey dizilerinizde de yaşanıyor: Düşündüğünüz karakterler gerçekten yok, ancak çok karakterli sıra 'dur.

tr///10 da, çoklu karakterler bir dizi olarak ele alınmaz, bunlar bir küme olarak kabul edilir. Her karakter (bayt) bulunduğunda ayrı ayrı ele alınır. Bir utf8 dizesinin bireysel bayt değişen istediğini asla çünkü bu, istediğiniz sonuçları almaz.

UCS2 gibi diğer kodlamalar ile değil de utf8 hakkında hiçbir şey bilmeyen basit bir ASCII odaklı alt dize arama çalıştırmak ve bir utf8 ipe doğru sonucu elde edebilirsiniz gerçeği, utf8 iyi bir geriye dönük uyumluluk özelliği olarak kabul edilir/utf16 veya ucs4.


çözüm use utf8; ekleyerek kaynak UTF-8 kodlanmış kullanıyor perl anlatmaktır. Ayrıca, çıktılarınızı terminalinizin beklentilerini karşılayacak şekilde kodlamanız gerekecektir. Benim için de çalışıyor

use utf8;        # The source is encoded using UTF-8. 
use open ':std', ':encoding(UTF-8)'; # The terminal provides/expects UTF-8. 
my $str1 = 'èîü'; 
my $str2 = $str1; 
$str1 =~ tr/î/i/; 
print "$str1\n"; 
$str2 =~ s/î/i/; 
print "$str2\n"; 
3

:

use v5.10; 
use utf8; 
use open qw/:std :utf8/; 

my $str1 = 'èîü'; 
my $str2 = $str1; 
$str1 =~ tr/î/i/; 
say $str1; # èiü 
$str2 =~ s/î/i/; 
say $str2; # èiü 

use utf8 Pragma UTF-8 kaynak kodunda sayılların sağlayan, use open pragma UTF-8'e STDOUT geçer.

+0

, teşekkür ederim. s' değil 'iken tr', bu pragmas ihtiyaç görünüyor neden' ​​fikri olan? – Georg

+4

Sadece karakter dizisi ve bayt dizisi anlamlarıyla ilgili bir şeyler söyleyecektim, ancak @ Wumpus’un cevabına bakarsak, sorunun daha iyi olduğunu düşünüyorum. – zoul

+0

@zoul, Yapmadığınıza sevindim; Bunun iki dahili depolama formatıyla ilgisi yok. – ikegami