C#(.Net)におけるエンコードのバグ?

このQ&Aのポイント
  • 複数のテキストファイルを読み込み、置換などの処理を加えた後に、文字コードはそのままで別名保存するアプリケーションを開発しています。
  • しかし、Encodingクラスを使って文字コードを変換するところでつまずきました。EUC-JPとShift_JISを変換するときだけ、一定の文字列が文字化け(あるいは脱字)してしまいます。それも必ず化けるわけではないようです。
  • 文字コードを取得したり、元の文字コードに戻すために、かなり回りくどいコードになってしまいました。代替策をお教えいただければ幸いです。
回答を見る
  • ベストアンサー

C#(.Net)におけるエンコードのバグ?

複数のテキストファイルを読み込み、置換などの処理を加えた後に、文字コードはそのままで別名保存するアプリケーションを開発しています。 しかし、Encodingクラスを使って文字コードを変換するところでつまずきました。EUC-JPとShift_JISを変換するときだけ、一定の文字列が文字化け(あるいは脱字)してしまいます。それも必ず化けるわけではないようです。 以下、簡単なチェックの手順です。 まず、下記テキストを含むテキストファイルを作成します。ファイル名は「test1.txt」、文字コードはEUC-JPとします。 ________________________ この文章は処理対象に含まれません。 この文章はダミーです。 この文章はこのファイルが正常に処理されるかどうかをチェックするために含まれています。  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ 次に、下記コードでテキストファイルを読み込み、別名で保存します。 string Buffer=File.ReadAllText("test1.txt",Encoding.Unicode); Encoding EncodingSrc=Encoding.GetEncoding("euc-jp"); byte[] b=Encoding.Unicode.GetBytes(Buffer); b=Encoding.Convert(EncodingSrc,Encoding.Unicode,b); Buffer=Encoding.Unicode.GetString(b); File.WriteAllText("test2.txt",Buffer,EncodingSrc); すると、「test2.txt」に脱字が発生します。 ________________________ この文章は処理対にれせん。 この文章はダーです。 この文章はこのファイルが正常に処理されるかどうかをチェックするためにれていす。  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ かなり回りくどいコードですが、文字コードを取得したり、また元の文字コードに戻したりするためにこうなってしまいました。 代替策でもかまいませんので、ご教授のほど、よろしくお願いします。

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

  • ベストアンサー
  • UKY
  • ベストアンサー率50% (604/1207)
回答No.6

> それからさらに元のエンコードに変換しようとすると、おかしなことになってしまいます。 何度もいいますが、一回でも間違ったエンコーディングで変換したらその時点で化けているのでもうどうしようもありません。だから化ける前のデータ (ファイルに保存されている生のバイト列) を正しいエンコーディングで変換する必要があります。 > エンコードの判別をする関数はあるのですが、そのためにはまずファイルを読み込まなければなりません。しかし、ファイルのエンコードがわからないので、Unicodeで読み込んでいます。 なんだか奇妙な方法でエンコーディングの判別をしているように思います。最初はエンコーディングが分からないんだから、とりあえず ReadAllBytes などを使って生のバイト列を取り込み、それをエンコーディング判定ルーチンに渡して、正しいエンコーディングが分かってからバイト列から文字列にデコードするのが筋ですよね。いきなり Unicode で読み込んだって、どうしようもないでしょう? それともその判定ルーチンがバイト列ではなく文字列から判別するなどという訳の分からない作りになっているのでしょうか。 > 2度読み込むことになってしまいますが、それしか方法はないのでしょうか? デコードする前の生のバイト列を取っておけばファイルからの読み込みは一応一回だけですみます。 byte[] bytes = File.ReadAllBytes("test1.txt"); Encoding encoding = ???; // ここで bytes からエンコーディングを判定 string text = encoding.GetString(bytes); File.WriteAllText("test2.txt", text, encoding);

randman
質問者

お礼

> それともその判定ルーチンがバイト列ではなく文字列から判別するなどという訳の分からない作りに なっていました。Unicodeから各コードを求めようとしているようだったのですが、ご指摘の通りバイト列で判断するようにしたところ、うまくいきました。 どうもありがとうございます。

その他の回答 (5)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.5

#3>それからさらに元のエンコードに変換しようとすると、おかしなことになってしまいます。 だから、取り込んだものを使うのでなくて、読み込み直します。

randman
質問者

補足

となると、2度読み込むことになってしまいますが、それしか方法はないのでしょうか? 確かにその方法ならうまくいきますが、代替策にしてもかなり気が引けますし、根本的な解決にはなっていない気がします。

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

使われているエンコーディングを自動的に正しく推定する方法は存在しません. 従って, ユーザがエンコーディングを指定しない限りどうしても誤ってしまう可能性があるということは当然承知の上だと思います. その上で, かつ Encode.Unicode でどのように読み込むのか知らないので完全に憶測になりますが, 見た感じでは Unicode の surrogated pair にあたるところの文字が読めていない感じがします. 例えば「象」という文字は EUC では BEDD というコードを持ちます. これを上下のバイトをスワップして UTF-16 として解釈すると DDBE というコードを持つ文字になりますが, これは surrogated pair の 2文字目にあたるので単独で存在することはありません (必ず surrogated pair の 1文字目のコードを持つ文字がその前にあるはずです). そのためにこの文字が削除されているという可能性があります. 「裳象」で「象」の文字が消えなければこの可能性は高そう.

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

>test1.txtの文字コードは不定です。EUC-JPとは限りません。 >「test1.txt」、文字コードはEUC-JPとします。 ? もし、エンコードの判別をされているのであれば、判別がついてから#1と同様のやりかたで読み直すのがよろしいと思います。

randman
質問者

補足

エンコードの判別をする関数はあるのですが、そのためにはまずファイルを読み込まなければなりません。 しかし、ファイルのエンコードがわからないので、Unicodeで読み込んでいます。 それからさらに元のエンコードに変換しようとすると、おかしなことになってしまいます。 「EUC-JPとする」というのはチェック時の前提です。

  • UKY
  • ベストアンサー率50% (604/1207)
回答No.2

> test1.txtの文字コードは不定です。EUC-JPとは限りません。 質問文にあるコードでは EUC に決め打ちしていたので私もそれに倣っただけです。 > 提案されたコードでは問題解決にはなりません。 そもそも何が「問題」なのかよく分からないのですが。 なぜ化けるのかが分からないのですか? それなら先の回答でもちょっと言いましたが、間違ったエンコーディングで読み込んだらその時点で化けているのでそれを更に変換したりしても元には戻りません。 それとも文字コードを取得する方法が分からないのですか? もしかして文字コードを自力で判別しようとしてますか? 何が問題なのかも分からずに「代替策」など出せるはずがありませんので情報をよろしくお願いします。もし質問者さん自身 何が問題か分からないというのであればエンコーディングや文字列・バイト列などの概念についてもっと勉強してくださいとしか言いようがありません。

randman
質問者

補足

決め打ちはしていません。「~とします」とあるように、チェックの時は仮にEUC-JPにしてください、の意です。 しかし、わかりづらい質問ですので、質問文を変えてみましょう。 文字コードのわからない複数のテキストファイルを読み込み、置換などの処理を加えた後に、文字コードはそのままで別名保存するアプリケーションを開発することになりました。あなたならどうしますか? という感じです。

  • UKY
  • ベストアンサー率50% (604/1207)
回答No.1

> string Buffer=File.ReadAllText("test1.txt",Encoding.Unicode); そりゃあ、EUC のテキストを Unicode で読んだら化けるに決まってるじゃないですか。 というか、何で Unicode が出てきたりバイト配列に戻したりするんでしょうか? 単に EUC で読んで EUC で書き出すだけですよね? Encoding eucEncoding = Encoding.GetEncoding("EUC-JP"); string text = File.ReadAllText("test1.txt", eucEncoding); File.WriteAllText("test2.txt", text, eucEncoding);

randman
質問者

補足

質問に書いてあるとおり、test1.txtの文字コードは不定です。EUC-JPとは限りません。 ともかく、提案されたコードでは問題解決にはなりません。

関連するQ&A

  • unicodeファイルの読み込み

    javaアプレット上で BufferedReader file = new BufferedReader(new FileReader("C:/test/list.txt")); で外部テキストファイルを読み込んでいるのですが、この外部テキストファイルの文字コードをANSIからUnicodeに変えるとプログラムが動かなくなります。日本語やアルファベットではない文字の保存のためにテキストをUnicodeにて保存しなければならないのですが、どうすればUnicodeのテキストファイルを読み込むことができますか。

    • ベストアンサー
    • Java
  • C#のテキストファイル読み込みについて

    C#のテキストファイル読み込みについて 2次元配列を使います(a[行][列]みたいに テキストファイルを1文字ずつ読み込みます。 そして、改行文字が見つかると行を1つずらします それを繰り返して最後まで読みこむと終わり そんなことをしたいです DOBON.NETでこんなの見つけたんですが 上の処理をしようと思っても、どこをいじればできるのかわかりませんでした //"C:\test.txt"をShift-JISコードとして開く System.IO.StreamReader sr = new System.IO.StreamReader( @"C:\test.txt", System.Text.Encoding.GetEncoding("shift_jis")); //内容を一行ずつ読み込む while (sr.Peek() > -1) { Console.WriteLine(sr.ReadLine()); } //閉じる sr.Close(); よくわかるサイトとかあったら教えてください、お願いします

  • 「C#」文字コードの取得&文字変換

    C#で文字コードを調べるプログラムを作成しています。 そこで2つ質問をさせてください。 1つ目(文字コード調べ) TextBoxに漢字を入力して,各エンコーディングの文字コードを調べるときに,UNICDEの場合, Encoding enc_default = Encoding.GetEncoding(932); string input = tb_input.Text; byte[] byte_input = enc_default.GetBytes(input); string outtext_unicode = ""; Encoding enc_unicode = Encoding.Unicode; byte[] byte_unicode = Encoding.Convert(enc_default,enc_unicode, byte_input); foreach (byte b in byte_unicode) { outtext_unicode += string.Format("{0:X}", (int)b); } tb_output_unicode.Text = outtext_unicode; とすると,調べたい文字コードがLE(リトルエディアン)で出力されます。これをBE(ビッグエディアン)で出力されるにはどうしたらよいでしょうか? ご存知の方がいらっしゃいましたら,ぜひ教えてください。 よろしくお願いいたします。 2つ目(文字コードから文字を取得する) 上記の質問と逆のパターンで,TextBoxに文字コードを入力してもらい,人間が読める文字に変換する場合下記のようなコードを書くと, string codePoint_string = tb_output_unicode.Text; int codePoint = int.Parse(codePoint_string); char c = (char)codePoint; tb_input.Text = Convert.ToString(c); ASCIIの文字コードを入力した場合には,きちんと変換してくれるのですが,漢字の文字コードを入力すると,FormatExceptionが発生します。 何か勘違いをしているのかもしれませんが,いまいちやり方が創造できません。 こちらも,ご存知の方がいらっしゃいましたら,ご教示願います。

  • 文字コードの判別について

    とあるテキストファイルがあります。UNIX上で文字コードの判別を行いたいのですが、nkf --guess test.txtと打って調べると、 test.txt: ASCII (CRLF) となります。このファイルは、Shift-JISだという判定だと思います。 ファイルをUTF8に変換したいので、(1)Windows上のエディタ(秀丸)の機能を使ってUTF8に変換してからUNIX上にアップロードしたり、また(2)UNIX上から直接nkf -w --overwrite test.txtを実行して変換したりしたのですが、nkf --guess test.txtを打って調べると相変わらず test.txt: ASCII (CRLF) のままです。 色々調べた結果、ファイルの中身が英数字のみしか書かれていないので、nkfがこのファイルをShift JISだと「推測」しているということがわかってきました。確かに、試しにファイルの中身に日本語を書いて保存して実行してみると、ようやくnkf --guess test.txtの結果が test.txt: UTF-8 (CRLF) と表示されるようになりました。 これらの結果は、ファイルの中身のマルチバイト文字のコードを見て初めて文字コードがわかるようになるというように思えます。 私の理解ではファイル自体にEUCやShift JIS、UTF-8などの文字コードがあるものとばかり思っておりました。つまり、test.txtの内容が"This is a pen."であったとしてEUC、Shift JIS、UTF-8では全く異なる三種類のファイルが存在し得るものだと思っておりました。しかしこれは私の理解が間違っていて、英数字であれば常にShift JISであり、マルチバイト文字があって初めてUTF-8なのかEUCなのかShift JISなのかが決定されるということなのでしょうか? 英数字のみのファイルでもUTF-8ファイルという前提を確認する方法はないのでしょうか? 宜しくお願いします。

  • mysql登録時の文字化け

    PHPで作成した登録フォームで入力されたデータをmysqlに登録すると、文字化けというか?になってしまいます。すべての文字を検証したわけではないのですが、どうも環境依存文字が?になってしまうようです。環境依存文字を登録するにはどうしたらいいでしょうか? ちなみに、現在の文字コードは HTMLの<head>の部分に<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> PHP開始時に mb_language("uni"); mb_internal_encoding("utf-8"); mb_http_input("auto"); mb_http_output("utf-8"); ただし、PHPの設定ファイルがさわれないのでPHP使用時の内部文字コードは恐らくデフォルトのEUC mysqlの文字コードとしては、DB,テーブルともにutf8_unicode_ci ファイルの保存形式はutf-8(BOMなし) SQL文のデータ部分にmb_convert_encodingを使用 例: insert into test(test1,test2) values( mb_convert_encoding("テスト1","EUC-JP","UTF-8"), mb_convert_encoding("テスト2","EUC-JP","UTF-8")) よろしくお願いします

    • ベストアンサー
    • PHP
  • 文字のエンコードの仕方

    お世話になります。 Excelで、Linuxマシンからテキストファイルを読み込むマクロを組みました。 ところが文字コードがEUC_JPのため文字化けしてしまいます。 VBAでEUC_JPをShift-JISにまたその逆を行う方法をご存知の方、ご教示ください。

  • ホームページのエンコードについて。

    ホームページの文字コードについて。 Yahoo!のトップページの文字コードがUnicode(UTF-8)になって、 日本語(シフトJIS)、日本語(EUC)などすべての他の文字コードは文字化けされるので、 正常でしょうか?自動選択に設定しても文字化けしてます。 前は日本語(シフトJIS)だったのにいつ変わったんでしょうか? またトップページ以外にはすべて日本語(EUC)になってます。 もちろん、これ以外はもじばけてます。 P.S. OCNのトップページはエンコードが日本語(シフト JIS)、 so-netは日本語(シフト JIS)、 GOOは Unicode(UTF-8)、 Microsoftは Unicode(UTF-8)などですが、 皆さんはどうなってますか? 正常なら私のPCに設定されたエンコートは少なくとも日本全国で同じだと思ってますが・・・

  • C# ファイルを読み込みlistviewに展開

    C#でtxtファイルを読み込み、listviewに展開したいのですが、txtファイルが ○○○,○○○ △△△,△△△ となっている場合、最初の一文字が消えて ○○,○○○ △△△,△△△ と表示されます。 コードは下記の通りです。 System.IO.StreamReader load = new System.IO.StreamReader(@".\test.txt", System.Text.Encoding.GetEncoding("shift_jis")); load.Read(); String file; while ((file = load.ReadLine()) != null) { string[] txtdate = file.Split(','); itemx = new ListViewItem(); itemx.Text = txtdate[0]; itemx.SubItems.Add(txtdate[1]); listView1.Items.Add(itemx); } load.Close(); 何を直せば最初の一文字目も読み込まれるかご教授下さい。

  • エンコードのEUCについて

    はじめまして 現在○○サービスというところでホームページ を作ってもらっています。 メタタグを入れようとすると、更新の度にファイルを送る必要 があります。個人情報の関係もあり、セキュリティとシステム の関係でこうなるようです。 問題はメタタグをいれるとエンコードが自動的に変わり文字化け してしまいます。 そのサポート会社から、つぎのような回答が返ってきましたが、 私がどうすれば理解出来ません。 どなたかご指導お願いします。 *************************** ブラウザでページを表示させて、「ソースの表示」でソースを 見ると文字化けしているということでしょうか? 「ソースの表示」でソースを見るときに起動されるソフトである 「メモ帳」は「EUCコード」のコード指定表示ができません。 ですが○○SERVICEのホームページを置いてある サーバーは「EUCコード」で動いておりますので、ファイルを 「EUCコード」にしておく必要があります。 「EUCコード」でない文字コードで保存したファイルをアップすると、 公開URLを表示させたときに見えるホームページの文字が化けて しまいます。 必ず「EUCコード」で保存をしていただく必要がありますので、 もしも「メモ帳」しかエディターをお持ちでないのであれば、 「文字コード」変換ができるソフトを使って、「EUCコード」で 保存して下さい。

  • Unicodeの文字がどれか、調べたいです

    ある文章をメモ帳で保存しようとしたら「このファイルはANCIテキストファイルで保存すると失われてしまうUnicode形式の文字を含んでいます。Unicodeの情報を保存するには、[文字コード]から[Unicode]を選択してください」と出ました。どれがUnicodeの文字なのかを調べる方法を探しましたが、アテになるのが全くありません。また、「[文字コード]から[Unicode]を選択する」という言葉の意味も分かりません。文字コード表を開きましたが、その後詰まりました。 限りなく分かりやすい説明をお願いします!