WindowsパソコンでPerl置き換え演算子s// で発生した文字化けを Encode.pm でスマートに解決!
マルチバイト文字列が母国語の我々を常に悩ませる問題。
そう、文字化け!
1年ちょい前に書いたエントリーでも文字化けについて書いてるけど、
今日もややハマりそうになって、「perl Encode.pm」でググると
自分のブログに到着。
おかげでスムーズに解決。ありがとう1年ちょい前の自分!
アクセス解析なんか見てると、文字化け系の検索が多いので、
今日の事例を紹介したら少しはお役に立つのでは。
文字列の扱いの基本は
______ ________________ ______ | | | | | | | 入力 |======>| perl の処理 |======>| 出力 | |______| |________________| |______| 入力をdecode 出力前にencode
では、さっそくプラクティス!!
■主な登場ファイル
(1)idle.txt ・・・読み込むファイル(保存文字コード形式SJIS)
(2)replace_name.pl ・・・処理するPerlスクリプト(保存文字コード形式UTF-8N)
(3)idle_now.txt ・・・出力するファイル(保存文字コード形式SJIS)
■(1)idle.txt の内容
経済が不況になるとアイドルが活躍すると言う評論家がいます。 長引く平成不況に躍進したのはAKB48(*゚∀゚)=3 AKB48(*゚∀゚)=3は紅白歌合戦に出場するなど、 テレビで見ない日はないというくらい激しく活動しています。 EOF
■行いたい処理
文章中の「AKB48(*゚∀゚)=3」を「ももいろクローバーZ(*゚∀゚)モノノフ=3」に書き換えたいっ!!
■(2)replace_name.pl の内容
#!/perl/bin/perl # # Scripted by Perl48 2013.03.02 use strict; use warnings; use utf8; use 5.010; # なんとなくsayを使いたいだけ use Encode; # 読み込むファイルと書き込むファイル my $file_r = './idle.txt'; my $file_w = './idle_now.txt'; # ファイルハンドルをオープン open my $r, '<', $file_r or die "Can't openfile: $file_r: $!"; open my $w, '>', $file_w or die "Can't openfile: $file_w: $!"; while (my $line = <$r>) { chomp $line; # 読み込んだ$line を perl内部文字コードにデコード $line = decode("cp932", $line); # 「AKB48(*゚∀゚)=3」を「ももいろクローバーZ(*゚∀゚)モノノフ=3」に置き換え $line =~ s/AKB48\(\*\゚∀\゚\)=3/ももいろクローバーZ\(\*\゚∀\゚\)モノノフ=3/; # cp932にエンコードして出力。今っぽくsayしてみる #say encode("cp932", $line); # コマンドプロンプトへ表示テスト say {$w} encode("cp932", $line); } # ファイルハンドルを閉じる close $w; close $r;
■コマンドプロンプトに表示した結果
Perlで文字化けしちゃったら、Encode.pm について学ぶチャンス!
いつやるか?今でしょ!
Enjoy Encode.pm !
Perl のEncode.pm について。今さらながらに、わかったこと。
特に文字コードを意識することなく
フツーに文字コード shift_jis で書いたスクリプト内で、
日本語を print しても文字化けしないのは、
たまたま処理がうまくいってるだけなんだということが
今さらになって、わかった。
※ちなみに、WindowsXP、Perl v5.10.1 な環境でやってます。
たとえば、
#!/usr/bin/perl # # Encode.pm と文字コードについての考察(print_unko_0.pl) # 2011.10.31_scripted by perl48 # # このファイルは文字コード shift_jis で保存してます use strict; use warnings; my $string = 'うんこ'; print $string;
っていうスクリプトでも、問題なく
って出力される。
でも、これは
『まぼろし〜!』(IKKO風に言う)
なぜなら、さっきと同じスクリプトを
#!/usr/bin/perl # # Encode.pm と文字コードについての考察(print_unko_1.pl) # 2011.10.31_scripted by perl48 # # このファイルは文字コード utf8 で保存してます use strict; use warnings; my $string = 'うんこ'; print $string;
ガッツリ文字化け〜♪
そこで、Encode.pm の登場〜!!
shift_jis で保存するなら、
#!/usr/bin/perl # # Encode.pm と文字コードについての考察(print_unko_2.pl) # 2011.10.31_scripted by perl48 # # このファイルは文字コード shift_jis で保存してます use strict; use warnings; use Encode; # 文字コード shift_jis 内のハードコーディングなので、'うんこ'も shift_jis my $string = 'うんこ'; # perl内部文字コードにデコードして $string = decode( "shift_jis", $string ); # 出力時にエンコードする ※Windowsのコマンドプロンプトの文字コード shift_jis に合わせる print encode( "shift_jis", $string );
って書いて、出力は↓
utf8 で保存するなら、
#!/usr/bin/perl # # Encode.pm と文字コードについての考察(print_unko_3.pl) # 2011.10.31_scripted by perl48 # # このファイルは文字コード utf8 で保存してます use strict; use warnings; use Encode; # 文字コード utf8 内のハードコーディングなので、'うんこ'も utf8 my $string = 'うんこ'; # perl内部文字コードにデコードして $string = decode( "utf8", $string ); # 出力時にエンコードする ※Windowsのコマンドプロンプトの文字コード cp932 に合わせる print encode( "cp932", $string );
って書いて、出力は↓
いや〜、Encode.pm は偉大だ!!
Perlで複数行の置き換えをやってみたよ
mをsにしたら結構サクッと置き換えもできちゃった。
てへっ。
#!/usr/bin/perl # # 複数行の置き換えを行うスクリプト-2 # 2011.10.29_scripted by perl48 use strict; use warnings; my $multiple_data; foreach my $data (<DATA>) { $multiple_data .= $data } #print $multiple_data; # <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">.<?php をマッチさせる # htmlはスラッシュが多いので、s#pattern#pattern2#s という感じでデリミタを # にしてみる # 改行一文字を . で表すための修飾子 /s をつける if ($multiple_data =~ s#<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">.<\?php##s ){ #print $&; print $multiple_data; } __DATA__ <? //絵文字 include_once 'include/commons.php'; //ヘッダ情報 include_once 'include/content_type.php'; ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <?php include ('include/analytics.php'); ?> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <?php include ('include/head.php'); ?> </head>
Perlで複数行のマッチをやってみたよ
複数行のマッチとかできたら幸せになれるのに・・・
って思いながら結城浩さんの『Perl言語プログラミングレッスン』を読んでたら
できました。
#!/usr/bin/perl # # 複数行の置き換えを行うスクリプト # 2011.10.29_scripted by perl48 use strict; use warnings; my $multiple_data; foreach my $data (<DATA>) { $multiple_data .= $data } #print $multiple_data; # <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">.<?php をマッチさせる # htmlはスラッシュが多いので、m#pattern#s という感じでデリミタを # にしてみる # 改行一文字を . で表すための修飾子 /s をつける if ($multiple_data =~ m#<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">.<\?php#s ){ print $&; } __DATA__ <? //絵文字 include_once 'include/commons.php'; //ヘッダ情報 include_once 'include/content_type.php'; ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <?php include ('include/analytics.php'); ?> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <?php include ('include/head.php'); ?> </head>
宮川プロダクツWeb::Scraperを使って楽天の商品情報をブッコ抜いてみたよ。
待望の冨田尚樹氏の書籍『Perl CPANモジュールガイド』が発売になった。
早速購入!
「この本の登場で、Perl業界が盛り上がること間違いなし!」
などと妄想しつつ、書籍を参考にしながら以前使いこなせずに挫折した
Web::Scraper を試してみた。
お題は
『楽天ショップ別ページから、個別商品URLを取得』
#!/usr/bin/perl # 宮川プロダクツWeb::Scraperを使って # 楽天ショップ別ページから、個別商品URLを取得してやんよ # 2011.04.17_scripted by perl48 use Web::Scraper; use URI; use utf8; # 取得したい部分をXPathで指定する。 # <table class="catchTable">内の1番目の<td>内の<a href="">の@href要素を取得したい。 # # 【実際のHTMLソース↓】 # <table width="100%" border="0" cellspacing="0" cellpadding="0" class="catchTable"> # <tr> # <td width="3%" valign="top" align="center"> # <a href="http://item.rakuten.co.jp/surugaya-a-too/3511089-1/" target="_top"><img src="http://image.www.rakuten.co.jp/com/img/icon/cir_order.gif" border="0" alt=""></a> # </td> # <td valign="top" align="left"> # <a href="http://item.rakuten.co.jp/surugaya-a-too/3511089-1/" target="_top"><font size="-1">【中古】生写真/アイドル/AKB48/アイドル生ブロマイド 131 : 大島優子【10p12Apr11】【画】</font></a> # # <img src="http://image.www.rakuten.co.jp/com/img/icon/icon_arrow01.gif" width="12" height="12" border="0" alt="" align="absmiddle"> # <a href="http://review.rakuten.co.jp/item/1/239310_12458096/1.1/" target="_top"><font size="-1">感想(1件)</font> # </a> # </td> # </tr> # </table> my $scraper = scraper { process '//table[@class="catchTable"]/tr/td[1]/a', 'urls[]' => '@href'; }; # ボットの名前をつけてみる $scraper->user_agent->agent('perl48bot/0.1'); # 取得対象ののURLをセット my $url = URI->new('http://search.rakuten.co.jp/search/inshop-mall/akb48/-/f.1-p.1-s.1-sf.0-sid.239310-st.A-v.2'); my $res = $scraper->scrape($url); # 繰り返し変数$i の初期値を定義 my $i = 0; # デフォルトで1ページ30商品表示のため、30回繰り返す while( $i<30 ){ print $res->{urls}->[$i] . "\n"; $i++; }
で、実行結果はこちら↓
C:\Documents and Settings\perl48\rakuten>scrape_rakuten.pl http://item.rakuten.co.jp/surugaya-a-too/1321137-1/ http://item.rakuten.co.jp/surugaya-a-too/3398077-1/ http://item.rakuten.co.jp/surugaya-a-too/3511089-1/ http://item.rakuten.co.jp/surugaya-a-too/3398055-1/ http://item.rakuten.co.jp/surugaya-a-too/3398059-1/ http://item.rakuten.co.jp/surugaya-a-too/1304598-1/ http://item.rakuten.co.jp/surugaya-a-too/3398058-1/ http://item.rakuten.co.jp/surugaya-a-too/3476541-1/ http://item.rakuten.co.jp/surugaya-a-too/3511026-1/ http://item.rakuten.co.jp/surugaya-a-too/1661334-1/ http://item.rakuten.co.jp/surugaya-a-too/2210679-1/ http://item.rakuten.co.jp/surugaya-a-too/3509377-0/ http://item.rakuten.co.jp/surugaya-a-too/3526682-0/ http://item.rakuten.co.jp/surugaya-a-too/3612182-1/ http://item.rakuten.co.jp/surugaya-a-too/3476622-1/ http://item.rakuten.co.jp/surugaya-a-too/1411570-1/ http://sa.item.rakuten.co.jp/surugaya-a-too/a/1666978-1-0417/ http://item.rakuten.co.jp/surugaya-a-too/3511019-1/ http://item.rakuten.co.jp/surugaya-a-too/3464466-1/ http://item.rakuten.co.jp/surugaya-a-too/3511091-1/ http://item.rakuten.co.jp/surugaya-a-too/3526413-1/ http://item.rakuten.co.jp/surugaya-a-too/3476552-1/ http://item.rakuten.co.jp/surugaya-a-too/3631077-1/ http://sa.item.rakuten.co.jp/surugaya-a-too/a/3280493-1-0417/ http://item.rakuten.co.jp/surugaya-a-too/3511098-1/ http://item.rakuten.co.jp/surugaya-a-too/3398065-1/ http://item.rakuten.co.jp/surugaya-a-too/3464494-1/ http://item.rakuten.co.jp/surugaya-a-too/3526669-0/ http://sa.item.rakuten.co.jp/surugaya-a-too/a/1952671-1-0417/ http://item.rakuten.co.jp/surugaya-a-too/3509403-0/
欲しいものは取得できた様子。
取得したいURLの変数部分をインクリメントで変更するか、
取得したいURLの一覧テキストファイルを読み込む形にして
グルグル回せば、ショップ全体の情報を一気にブッコ抜ける。
Perl is cool !
Perlの聖書(ラクダ本)が届いた!
ついに、ペーパーバックの英語の中古本だけど、
2,050円(送料込み)で買った『Programming Perl』が届いたー!!
よくよく見ると、2000年出版の3rd Edition でPerl 5.6までしかカバーしてなかったりするw
Unicode の節が、「将来実装予定だぜ」的なこと書いてあるし。
欲を言えば、どのレンタルサーバでも標準になってて
Unicode正式対応して、Encode.pmが標準ライブラリ入りしたPerl5.8を
カバーしたやつがよかったけど、そんなバージョンの「The Camel」はそもそも無いようだ(爆)
本屋でフツーに買ったら2冊で9,000円くらいだから、
安いお買い物。
めっちゃテンション上がるわー!!!