2017-03-03 4 views
0

正規表現のテスターで以下の単純な置換を試したところ、うまくいきました。私はPerlコードでそれを使用する場合でも、ùは交換されていません。ここで私の代用で特殊文字 "ù"が置き換えられないのはなぜですか?

#!/usr/bin/perl 

use 5.010; 
use strict; 
use warnings; 

use File::Slurp; 

my $file = 'test.html'; 
my $str = read_file($file); 

$str =~ s/ù/u/g; 

write_file("out/$file", $str); 

は、私が変更したいサンプルテキストです:

umbrella under uuuuu utters 

ùmbrella ùnder ùùùùù ùtters 

すべてのヘルプ提案は高く評価されています。

+0

@ iiamありがとうございました!私は "use utf8;"を追加しなければならなかった。上にも同様に – Xavia

+2

@サイアム:あなたはPythonを考えている!それはPerlの単なるコメントです。 – Borodin

+4

[File :: Slurpが壊れていて間違っています。](http://blogs.perl.org/users/leon_timmermans/2015/08/fileslurp-is-broken-and-wrong.html) – ThisSuitIsBlackNot

答えて

7

スクリプトと入力ファイルが同じエンコードでエンコードされている場合、コードはそのまま動作します。

$ cat>test.html 
ùmbrella ùnder ùùùùù ùtters 

$ perl a.pl 

$ cat out/test.html 
umbrella under uuuuu utters 

あなたのプログラムは、しかし、バグがあります。私たちがUTF-8について話しているとしましょう。あなたが持っていた場合、これはありませんので、悪いですが、Perlは実際に

$str =~ s/\xC3\xB9/u/g; 

見て、想像

$str =~ s/[ùú]/u/g; 

Perlは

$str =~ s/[\xC3\xB9\xC3\xBA]/u/g; 

これは ùC3 B9uuに変わるだろうと見るであろう éC3 A9)を u<garbage>とする。

プログラムで非ASCII文字を認識するためには、プログラムファイルがUTF-8でエンコードされていることを確認し、ファイルの先頭にuse utf8;を追加する必要があります。 use utf8;では、Perlは

$str =~ s/[ùú]/u/g; 

かという

$str =~ s/[\xF9\xFA]/u/g; # F9 and FA are the Unicode Code Points for ù and ú 

を見ただし、use utf8;を追加するソリューションの半分だけです。 Perlが正規表現をどのように見えるかを変更しましたが、$strを変更していないため、これ以上一致する可能性はありません。私たちは常にあなたの入力をデコードùF9

のUnicodeのコードポイントでùC3 B9)のエンコーディングを比較しています。常にあなたの出力をエンコードする。

すでに1つの入力(プログラム自体)をデコードしました。今度はファイルの内容と同じことをする必要があります。

同様に、出力をエンコードする必要があります。これには、ファイルの内容だけでなく、警告がSTDERRに出力されます。

ことの多くは、

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

によって行われるそれはSTDIN、STDOUTとSTDERRへのエンコード層を追加し、プラグマの字句範囲内で開かれたファイルのデフォルトのエンコーディング層を設定します。

#!/usr/bin/perl 

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

use strict; 
use warnings; 

my $in_qfn = 'test.html'; 
my $out_qfn = 'out/test.html'; 

# :encoding(UTF-8) is added by "use open". 
open(my $in_fh, '<', $in_qfn) or die("Can't open \"$in_qfn\": $!\n"); 
open(my $out_fh, '>', $out_qfn) or die("Can't create \"$out_qfn\": $!\n"); 

while (<$in_fh>) { 
    s/[ùú]/u/g; 
    print($out_fh $_); 
} 

[ファイル::読まを使用する場合は、そのopenuse openの範囲ではないため、ファイルをデコード(またはそれを自分でデコード)するためにそれを伝える必要があります。

#!/usr/bin/perl 

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

use strict; 
use warnings; 

use File::Slurp qw(read_file write_file); 

my $in_qfn = 'test.html'; 
my $out_qfn = 'out/test.html'; 

my $file = read_file($in_qfn, binmode => ':encoding(UTF-8)'); 

$file =~ s/[ùú]/u/g; 

write_file($out_qfn, { binmode => ':encoding(UTF-8)' }, $file); 
0

ソリューション:

#!/usr/bin/perl 

use 5.010; 
use strict; 
use utf8; # <-- Added this 
use warnings; 
use File::Slurp; 
my $file = test.html; my $str; 

$str = read_file($file); 
$str =~ s/ù/u/g; 

write_file("out/$file",$str); 
+1

'use utf8'プラグマは、あなたの_sourceコードfile_がutf8エンコーディングで保存されていることをPerlに伝えています(これは悪いことですが、私の答えを読んでください)。 – simbabque

+1

つまり、Perlに出力をUTF-8としてエンコードするよう依頼する必要があります。 – ThisSuitIsBlackNot

+1

変更されたプログラムは入力ファイルを変更しません。'use utf8;を追加するのは適切ですが、それは解決策の一部に過ぎません。もっと私の答えを見てください。 – ikegami

0

私は問題のカップルがここにあります疑います。まず、File :: Slurpを使用していて、データがUTFでエンコードされているとは言いません。つまり、2バイトの "ù"文字は2つのシングルバイト文字として解釈されます。第二に、あなたのコードにはリテラル "ù"がありますが、PerlにソースコードをUTF8として解釈させることはありません。したがって、おそらく1バイトのISO-8859表現を持つでしょう。

入力文字列の2つのシングルバイト文字がソースコードの1バイト文字と一致しないため、置換は機能しません。

a)ソースコードがUTF8であることをPerlに伝え、b)出力の入力とエンコーディングのデコードを正しく処理する必要があります。私はFile :: Slurpを投げ捨て、あなた自身でそれをすることをお勧めします。

ファイルをスラッピングすることはお勧めしませんが、可能な場合は一度に1行ずつ処理することをお勧めします。

#!/usr/bin/perl 

use 5.010; 
use strict; 
use warnings; 
use utf8; 

my $file = 'test.html'; 
open my $in_fh, '<:utf8', $file or die $!; 
open my $out_fh, '>:utf8', "out/$file" or die $!; 

while (<$in_fh>) { 
    s/ù/u/g; 

    print $out_fh $_; 
} 

更新:ここで私は、文字列に関する情報を取得するために使用し、本当に簡単なサブルーチンです。

sub string_chars { 
    say join ':', map { ord } split //, $_[0]; 
} 

あなたはあなたのコードにこれを追加して、「U」を渡す場合 - あなたは、出力(ISO-8859-1で「U」のコードポイントである)「249」を取得します。あなたはそれあなたの$str値を渡すと、あなたが得る:

'195:185:109:98:114:101:108:108:97:32:195:185:110:100:101:114:32:195:185:195:185:195:185:195:185:195:185:32:195:185:116:116:101:114:115:10' 

を繰り返し「195:185」はUTF8で「U」の2バイト表現です。

+1

これはもっと簡単です: 'sub string_chars {sprintf"%vX "、$ _ [0]}'(ボーナス、数字は16進数です!) – ikegami

関連する問題