• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:sedやperlでの2バイト文字を含む変換)

sedやperlでの2バイト文字を含む変換

このQ&Aのポイント
  • sedやperlで2バイト文字を含む変換を行う際に問題が発生しました。
  • sedやperlでのシフトJISコードでの2バイト文字の扱い方について、アドバイスを求めています。
  • sedやperlでの2バイト文字の処理において、エラーメッセージが発生しているため、解決策を探しています。

質問者が選んだベストアンサー

  • ベストアンサー
  • N60-BASIC
  • ベストアンサー率80% (17/21)
回答No.3

> \Q$ARGV[1]\E は、$ARGV[1]に正規表現が含まれていても、 > 普通の文字列として扱うという事なのでしょうか? はい、その通りです。私がご質問の内容を見落としていたのですが、 スクリプトの引数に正規表現を意図的に使えるようにしたいということであれば (=sedと同様の動作を期待するなら)\Q \Eは全く必要ありません。失礼しました。 サンプルスクリプトのエラーの原因を説明するために必要だったということでご容赦ください。 もちろんその際は、各種カッコやピリオド等を必要に応じて手動エスケープしてやる必要があります。 (例:「a.txt」が「abtxt」にマッチしてしまうのを防ぐ→「a\.txt」にする) > ・「cp932文字列がバイナリとして入ってきます。」というのは、 > 2バイト文字は、2つの1バイト文字の並びとして入ってくる、つまり、 > 内部では2バイト文字として扱われないという意味でしょうか? はい、そうです。length()で文字数を確認してみるとわかりやすいです。 マルチバイト文字を1文字として扱うには、Encodeモジュール等でテキストを内部utf8表現にしてやる必要があります。 バイナリはlength()がバイト数を返すのに対して、内部utf8表現は文字数を返します。 これはUTF-8文字も同様です。UTF-8であってもデフォルトではバイナリとして扱われます。 つまり、一般的なUTF-8と内部utf8表現は異なるものです。 少々ややこしい話になるので、詳細は「Perl utf8」等で検索してみてください。 > ・最後に、 > use strict; use warnings; > は、いままでソースファイルに記述してこなかったのですが、 > これらはなぜ記述するべきなのでしょうか? スクリプトの潜在的なバグを回避するのに極めて有効な手段だからです。 今回のような小規模なスクリプトでは恩恵は少ないように思われるかもしれませんが、 ミスを防ぐために冒頭につけておくのはよい習慣とされています。 大雑把に説明すると、 ・use strictプラグマ - 宣言のない変数の使用等をエラーにする use strict; # my $hoge = 'abc'; # 変数宣言をコメントアウトすると・・・ print $hoge; # 宣言されていない変数$hogeが使われたよ、とエラーになる ・use warningsプラグマ - 未定義の値に対する操作や同名変数の二重定義等に対して警告を出す use warnings; my $hoge = 'abc'; # 変数宣言 $hoge = 'def'; # 変数の使用 my $hoge = 'ghi'; # 同名変数が同じスコープで宣言されたよ、と警告が出る といったところです。詳細は検索してみてください。

MetalLover
質問者

お礼

大変御丁寧な御説明、ありがとうございます。 御説明頂いた内容で、分からなかった事は理解できました。 Perlというのは便利ですが、2バイト文字を扱うとなると、結構厄介な問題が多いのですね。 Perlについては色々と勉強してみたのですが、現在は文字列の置換にしか応用できていないので、これからもっと応用が利くように頑張りたいと思います。 ちなみに、N60-BASICさんは、どんな場面でPerlを利用しているのですか? 大変優秀な方なので、他にどんなプログラミング言語を使うのなんかも教えていただきたいと思いました。 僕は普段、C言語、バッチスクリプト、CygwinでのShellといったものを使ってプログラミングを行っています。

その他の回答 (4)

  • N60-BASIC
  • ベストアンサー率80% (17/21)
回答No.5

> どんな場面でPerlを利用しているのですか? Webプログラミング、サーバー運用(解析、監視、etc.)、複数システム間のデータ連携などの業務にPerlやJavaScriptを使っています。 Perlを使ってる理由ですが、 ・旧バージョンとの後方互換性がある程度担保されるため、比較的長期運用が必要な社内システム等の構築が容易。プラットフォームOSへの依存が少なく、機器更新時の選択自由度が高い ・強力かつ大量のCPANモジュールが利用可能 ・コンパイル不要。迅速な修正が可能。最悪担当者が逃げてもソースコードがあればなんとかなるよね・・・?(^^; 最後のは半分冗談ですが、こんな感じです。 Perlもまだまだ勉強中なので、しっかり身につけてから他の言語に手を出そうかなと思ってます。 Python、Rubyあたりには興味がありますね。用途次第でしょうけど、ご参考まで。

MetalLover
質問者

お礼

御回答ありがとうございます。 なるほど。 結構複雑な事にも、Perlは応用できるのですね。 Perlを使っておられる理由も、参考になりました。 色々とありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

一応突っ込んでおくと, Perl に限らずどんなプログラム言語であっても 2バイト (以上) の大きさを持つ文字を扱おうとすると面倒です. 厳密には「1バイト文字だけを扱っていても面倒」なんだけど. そして Unicode にもやっぱり暗黒面があったりする.

  • N60-BASIC
  • ベストアンサー率80% (17/21)
回答No.2

うまく行かなかったのは次の2点が原因と思われます。 (1)use encodingプラグマは@ARGVに対して効力を発揮しない @ARGVにはcp932文字列がバイナリとして入ってきます。 従って、#置換操作 の前に次の一文を置いてやれば動きます。 $_ = Encode::decode('cp932', $_) foreach (@ARGV); (2)置換の検索キーワードである$ARGV[1]は正規表現として扱われる $ARGV[1]に正規表現の制御文字が含まれている場合、意図する置換にはなりません。 今回の場合、(1)が原因でcp932文字列がバイナリとして扱われた結果、 cp932文字の2バイト目がたまたま '[' だったために不正な正規表現としてエラーになったと 思われますが、実際$ARGV[1]にこれらの記号を入れてやると同じエラーが起きます。 従って、\Q~\Eなどで適切にエスケープしてやる必要があります。 $name =~ s/\Q$ARGV[1]\E/$ARGV[2]/g; 以上でおそらくご質問の回答にはなっていると思いますが、老婆心ながら忠告を。 use encodingプラグマは今回のご質問のようなケース以外にも副作用が非常に 多かったため、現在は「使用が推奨されないプラグマ」とされています。 Encodeモジュールのメンテナである小飼弾さんが「黒歴史」と明言されているほどです。 http://blog.livedoor.jp/dankogai/archives/51221731.html 基本的にはかつて存在したJperl用の古いソースコードを無理やり動かす専用の機能と割り切るべきと考えています。 せっかくここまで書ける知識をお持ちなのですから、新規で書くスクリプトについては 現在推奨されている記述方法: ・PerlのソースコードはUTF-8で保存する ・ソースコードにマルチバイト文字を含む場合は use utf8プラグマを使う ・use strict; use warnings; も忘れずに を強く推奨します。 ソースコードをWindowsネイティブであるcp932で書けるというのはなかなか捨てがたい魅力では あるのですが、それを捨てるだけの価値があるケースがきっと今後出てくると思います。 # use encodingしてるとうまく動かないCPANモジュールがいっぱいあるんですよね・・・

MetalLover
質問者

お礼

大変御丁寧な御回答、ありがとうございます。 提供された御説明で、幾つか分からなかった所があるので、質問させて下さい。 ・仰られたように $_ = Encode::decode('cp932', $_) foreach (@ARGV); を記述すれば、 $name =~ s/\Q$ARGV[1]\E/$ARGV[2]/g; とせずに $name =~ s/$ARGV[1]/$ARGV[2]/g; のままでも上手く行きました。 \Q$ARGV[1]\E は、$ARGV[1]に正規表現が含まれていても、 普通の文字列として扱うという事なのでしょうか? ・「cp932文字列がバイナリとして入ってきます。」というのは、 2バイト文字は、2つの1バイト文字の並びとして入ってくる、つまり、 内部では2バイト文字として扱われないという意味でしょうか? ・最後に、 use strict; use warnings; は、いままでソースファイルに記述してこなかったのですが、 これらはなぜ記述するべきなのでしょうか?

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

考えるのが面倒なので, Encode::decode とか Encode::encode とかを駆使したらどうだろうか.

MetalLover
質問者

お礼

御回答ありがとうございます。 encode関数は使った事がありますので、少しは知っています。 例えば、2バイト文字を含む名前を持つファイルを扱う場合は、 以下のような関数を、perlスクリプトの先頭にでも記述しておけば、 このopen関数で、2バイト文字を含む名前を持つファイルをファイルを開く事ができます。 ____________________________________________________________ use subs qw(open); sub open { use Encode; return CORE::open(shift,encode('cp932',shift),encode('cp932',shift)); } ____________________________________________________________ 今回のNameRep.plでは、どのようにしてencode関数やdecode関数を使えばよいのでしょうか? perlについて初心者なので、具体的なコードを記述して、 説明して下さると大変助かります。

MetalLover
質問者

補足

ちなみに、texのsedコマンドの代わりに、onigsedというコマンドをダウンロードして使うことで、今回の問題は解決できました。 ただ、perlでの2バイト文字の扱いについて、もっと詳しく知りたいので、 引き続き、よろしくお願い致します。

関連するQ&A