トップ回答者
C#で文字コードの判定・変換をする方法について

質問
-
C#の書き方について質問です。
文字コードShift-JISで書かれたファイルをUTF-8で開いた後に、
文字化けしてしまった文字列をShift-JISで正しく読み直す方法を探しています。public static string ConvertCharacterCode(string message) { var sjis = Encoding.GetEncoding("Shift_JIS"); var utf8 = Encoding.UTF8; var utf8Byte = utf8.GetBytes(message); var sjisByte = Encoding.Convert(utf8, sjis, utf8Byte); var sjisStr = sjis.GetString(sjisConvertByte); return sjisStr; }
messageに文字化けした文字列が入力されます。
実際に文字コードShift-JISで「あいうえおかきくけこ」と入力したとき、
messageの内容は「��������������������」(文字化けした文字列)でした。今回、このコードはAzure Strema AnalyticsのUDF C#として作成しており、messageをstringではなく、byte[]やchar[]で受け取ろうとすると以下のエラーとなり、動作しませんでした。
Error : **System Exception** ASA passed a non-supported type System.Byte[] to be marshaled to CSharp UDF ConvertCharacterCode at variable message
なにかいい方法はございませんでしょうか。よろしくお願いいたします。
回答
-
Azure Stream Analyticsは標準だとUTF-8しか受け付けていないです。
ですが、Azure Stream Analytics でカスタム デシリアライザーを実装する (プレビュー段階)というのがあって、受信した生のバイナリを変換する方法があります。
VS2019のプロジェクトで"Azure Stream Analytics Custom Deserializer Project(.NET)"を作成します。using System.Collections.Generic; using System.IO; using Microsoft.Azure.StreamAnalytics; using Microsoft.Azure.StreamAnalytics.Serialization; namespace ASACustomDeserializerProject { // Deserializes a stream into objects of type CustomEvent. // It reads the Stream line by line and assumes each line has three columns separated by ",". // Writes an error to diagnostics and skips the line otherwise. public class CustomCsvDeserializer : StreamDeserializer<CustomEvent> //CustomEventの中身をデータに合わせて変更 { // streamingDiagnostics is used to write error to diagnostic logs private StreamingDiagnostics streamingDiagnostics; // Initializes the operator and provides context that is required for publishing diagnostics public override void Initialize(StreamingContext streamingContext) { this.streamingDiagnostics = streamingContext.Diagnostics; } // Deserializes a stream into objects of type CustomEvent public override IEnumerable<CustomEvent> Deserialize(Stream stream) { //ここでEncodingを指定してやる using (var sr = new StreamReader(stream, System.Text.Encoding.GetEncoding("sjis"))) { //以下は自分のファイルの内容に合わせて書き換える
デシリアライザー側のdllをビルドしたら、ユーザー定義関数(UDF)側で参照して、input.jsonでイベントのシリアル化の形式をCustomClrに設定してやればdllを認識してくれます。
必要ならScript.asaqlをCustomEventのプロパティ名に合わせて書き換えます。
これで、UDFでの引数はstring型にできます。UTF-8とSJISのファイルが混在しているなら、streamをバイト配列に読み切ってから、UTF-8で開いて文字化け(U+FFFD)したらSJISで開きなおすなどの消極的方法をとるしかないです。
#プレビューなので実運用は難しいけど
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク Kazuki Yamamoto Fixer 2019年10月11日 9:50
- 編集済み gekkaMVP 2019年10月11日 13:25
すべての返信
-
逆パターン(UTF-8 ファイルを Shift_JIS でデコードした場合)は比較的復元しやすいのですが
Shift_JIS ファイルを UTF-8 でデコードした時の文字化けを復元するのは、ほぼ無理かと。『UTF-8 として読み取ることが可能なバイト列』を誤読したことによる文字化けであれば、復元できる可能性があります。
しかし、『UTF-8 としてありえないバイト列』が渡された場合は、必ず不可逆的な破損を引き起こします。
この場合、復元は原理的に不可能です。不正なバイト列が渡された場合は以下のいずれかの状態になり、元のデータの情報が既に失われている状態であるためです。
- 文字列化失敗。データエラーとして処理される。
- 不正データの読み飛ばし。欠損データとして処理される。
- 不正データを代替文字で置換。破損による文字化けとして処理される。
※代替文字としては「�」U+FFFD "REPLACEMENT CHARACTER" や
「?」U+003F "QUESTION MARK" などが使われます。
static void Main() { /*** サンプルの Shift_JIS ファイル ***/ File.WriteAllBytes("SJIS.TXT", new byte[] { 0x81, 0xe6, 0xfa, 0x5b, 0x87, 0x9a }); // 正しく Shift_JIS で読み取られた正解データ。 string correct = File.ReadAllText("SJIS.TXT", Encoding.GetEncoding(932)); // 誤って UTF-8 で読み取った文字化けデータ。この時点で破損しているので手の施しようが無い。 string garbled = File.ReadAllText("SJIS.TXT", Encoding.UTF8); // 復元を試みるも、既に手遅れ。 string proposal = ConvertCharacterCode(garbled); Console.WriteLine("正解:" + correct); Console.WriteLine("破損:" + garbled); Console.WriteLine("復元:" + proposal); Console.ReadKey(); } public static string ConvertCharacterCode(string message, bool throwIfBroken = false) { var enc = throwIfBroken ? EncoderFallback.ExceptionFallback : EncoderFallback.ReplacementFallback; var dec = throwIfBroken ? DecoderFallback.ExceptionFallback : DecoderFallback.ReplacementFallback; var sjis = Encoding.GetEncoding("Shift_JIS", enc, dec); var utf8 = Encoding.GetEncoding("UTF-8", enc, dec); return sjis.GetString(utf8.GetBytes(message)); }
- 編集済み 魔界の仮面弁士MVP 2019年10月10日 12:19
-
Azure Stream Analyticsは標準だとUTF-8しか受け付けていないです。
ですが、Azure Stream Analytics でカスタム デシリアライザーを実装する (プレビュー段階)というのがあって、受信した生のバイナリを変換する方法があります。
VS2019のプロジェクトで"Azure Stream Analytics Custom Deserializer Project(.NET)"を作成します。using System.Collections.Generic; using System.IO; using Microsoft.Azure.StreamAnalytics; using Microsoft.Azure.StreamAnalytics.Serialization; namespace ASACustomDeserializerProject { // Deserializes a stream into objects of type CustomEvent. // It reads the Stream line by line and assumes each line has three columns separated by ",". // Writes an error to diagnostics and skips the line otherwise. public class CustomCsvDeserializer : StreamDeserializer<CustomEvent> //CustomEventの中身をデータに合わせて変更 { // streamingDiagnostics is used to write error to diagnostic logs private StreamingDiagnostics streamingDiagnostics; // Initializes the operator and provides context that is required for publishing diagnostics public override void Initialize(StreamingContext streamingContext) { this.streamingDiagnostics = streamingContext.Diagnostics; } // Deserializes a stream into objects of type CustomEvent public override IEnumerable<CustomEvent> Deserialize(Stream stream) { //ここでEncodingを指定してやる using (var sr = new StreamReader(stream, System.Text.Encoding.GetEncoding("sjis"))) { //以下は自分のファイルの内容に合わせて書き換える
デシリアライザー側のdllをビルドしたら、ユーザー定義関数(UDF)側で参照して、input.jsonでイベントのシリアル化の形式をCustomClrに設定してやればdllを認識してくれます。
必要ならScript.asaqlをCustomEventのプロパティ名に合わせて書き換えます。
これで、UDFでの引数はstring型にできます。UTF-8とSJISのファイルが混在しているなら、streamをバイト配列に読み切ってから、UTF-8で開いて文字化け(U+FFFD)したらSJISで開きなおすなどの消極的方法をとるしかないです。
#プレビューなので実運用は難しいけど
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク Kazuki Yamamoto Fixer 2019年10月11日 9:50
- 編集済み gekkaMVP 2019年10月11日 13:25