LotosLabo

プログラミング技術とか気になった情報を載せていきます

UnityによるProcess出力の日本語文字化け対策の奮闘記録

はじめに


前回紹介した外部プロセスの記事の内容から、Subversionバージョン管理システム)のプロセスをUnityから呼び出す処理を試しみました。


しかし、その記事にも書いていたのですが、Subversionから出力を取る際に、日本語の文章が文字化けしてしまいました。
WindowsMacで両方で試してみたのですが、どうやらMacのみ文字化けしており、その問題点と解決方法をまとめてみました。


問題点


------以下、文字化けした結果-----


WindowsSubversion
f:id:lo25131:20150929231926j:plain                  

WindowsのUnity
f:id:lo25131:20150929232001j:plain


MacSubversion
f:id:lo25131:20150929232220p:plain

MacのUnity
f:id:lo25131:20150929232140p:plain

このようにMacのUnityの出力だけ、文字化けしてしまいました。
「?\227?\129?\138?.......」

Shift-JISかな?UTF8に変換してあげればいいかな。

試行錯誤中


~以下、試行錯誤の記録~


・出力のエンコード設定を変更

StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;

結果:失敗


・取得したデータを一度Unityのオブジェクトに入れる

string data = args.Data;
Debug.Log(data);

結果:失敗


・取得したデータをUTF8に変換

System.Text.Encoding enc = System.Text.Encoding.GetEncoding("Shift_JIS");
System.Text.Encoding utf8 = System.Text.Encoding.UTF8;

byte encByte = enc.GetBytes(data);
byte
encConByte = System.Text.Encoding.Convert(enc,utf8,encByte);
string encText = utf8.GetString(encConByte);
Debug.Log(encText);

結果:失敗

対策の発見へ


Twitterで聞いてみました。

> 参考となるサイトを紹介してもらいました。ありがとうございました。

MacでSubversionを利用する際に発生する文字コード問題の解消方法 - Shuichi’Tec


どうやらSubversionの方に問題があったようで、一度Macに入ってるSubversionをアンインストールして再度インストールしてみました。
私のMacではXcodeのCommadn Line ToolsのSubversionを使っていたため、Xcode自体を一回アンインストールしました。


そして新たに上記のサイトを参考にしてSubversionをインストール。
以下コマンド

sudo port install subversion + unicode_path

そのままコマンドを叩くと、Subversion1.9.2がインストールされました。
見た目ではヘルプ等の文字が日本語化されていました。


次に、UnityでSubversionを起動させてみます。
しかし、svnコマンドは使えないと言われてしまいます。

どうやらターミナルで叩いているsvnコマンドと、Unityから起動するプロセスのsvnコマンドでは起動しているパスが異なっているようです。
↑解決方法がわからないので、御存知の方いらっしゃればご教授よろしくお願いします。


なので直接先ほどMacPortからインストールしたSubversionのパスからSubversion
プロセスを起動します。
Subversionのパスは、ターミナルから取得することができます。

which svn

多分デフォルトは以下の場所にインストールされるかと思います。
> /opt/local/bin/svn

上記の場所を指定してプロセスを立ち上げます。

すると、先ほどの文字化け文字に変化がありました。


以下変化画像
f:id:lo25131:20150930000115p:plain

{U+30C6}{U+30B9}{U+30C8}.....

見覚えのあるコードが出てきました。

30C6 -> テ
30B9 -> ス
30C8 -> ト

[参考サイト]
ASCIIコード変換機


あとはこれをすべて文字に直す作業です。

文字化けコードの変換


変換する流れとしては…

①一行分のログが変換できるかどうか (できる場合は変換、できない場合はそのまま取得)
②文字化けコード全てを取得
③文字化けコードの中のASCIIコードのみ取得
④ASCIIコードを16進数に変換して文字列に変換
⑤元の文字化けコードの場所に変換した文字列を置き換える


これをプログラムにしていきます。

以下プログラム

// 出力された文字列.
string data = args.Data; 

if(!string.IsNullOrEmpty(data)) {
  string encData = EncodeBinaryToString(data);
  Debug.Log(encData);
}

/// <summary>
/// 文字化けした文字列を日本語文字列に変換.
/// </summary>
/// <param name="data">コンソール出力文字.</param>
/// <returns>文字化け文字を日本語変換された文字.</returns>
private string EncodeBinaryToString(string data) {
  string Result = null;
  
  List<string> asciiArray = new List<string>();
  List<string> codeArray = new List<string>();

  // ASCIIコードのみを取得するためのパターン.
  string getAsciiPattern = @"(\{U\+)(?<Result>.+?)(\})";

 // 文字化け文字列全てを取得するためのパターン.
 string getcodePattern = @"(\{.*?\})";

  System.Text.RegularExpressions.Match asciiMatch;
  System.Text.RegularExpressions.Match codeMatch;

  // マッチされない場合はそのまま返す.
  if(!System.Text.RegularExpressions.Regex.IsMatch(data, getcodePattern)) {
   return data;
  }

  // 文字化け文字の取得.
  codeMatch = System.Text.RegularExpressions.Regex.Match(data, getcodePattern);

 // マッチしている間.
 while(codeMatch.Success) {
     codeArray.Add(codeMatch.Value);

     // 次のマッチングへ.
     codeMatch = codeMatch.NextMatch();
  }

  // ASCIIコードのみを取得.
  asciiMatch = System.Text.RegularExpressions.Regex.Match(data, getAsciiPattern);

  while(asciiMatch.Success) {
     asciiArray.Add(asciiMatch.Groups["Result"].Value);
     asciiMatch = asciiMatch.NextMatch();
  }

  List<string> japaneseCharArray = new List<string>();

  // ASCIIコードを日本語文字列に変換する.
  for(int index = 0; index < asciiArray.Count; ++index) {
     // 16進数を基に32bit符号付き変数に変換.
     int intCode16 = Convert.ToInt32(asciiArray[index], 16);

     // char型に変換.
     char conChar = Convert.ToChar(intCode16);

     // string文字列に変換.
     string strChar = conChar.ToString();
     japaneseCharArray.Add(strChar);
  }

  // 元の文字列を日本語文字列に置き換える.
  for(int index = 0; index < japaneseCharArray.Count; ++index) {
     data = data.Replace(codeArray[index], japaneseCharArray[index]);
  }

  encResult = data;
  return encResult;
}


結果

f:id:lo25131:20150930005059p:plain


コードについて


ASCIIコードから文字列に変換するプログラムは以下のQiitaの投稿を参考にしました。


全体的に、もうちょっとスマートにならないかどうか考えてるけど、これで精一杯でした。


まとめ

結果としては日本語に置き換えることができました。


流れとしては...

Subversionのアップデート → 新しいSubversionで起動する → 文字化け文字を変換する

という感じです。


しかし一つ問題として、濁点・半濁点がなくなっています。
考えられる理由としては、Subversionのインストール時にunicode_pathのオプションが
うまく実行されていなかったため、濁点・半濁点が文字化けした時に
ユニコードとして出力されていなかった可能性があります。


例えば本来、

デスト → 30C7 30B9 30C8  のはずが

テスト → 30C6 30B9 30C8  として置き換わっています。


こちらについては原因を特定中ですが、やはりインストールに失敗しているというところが問題っぽいです。


今回の文字化けからの日本語への変換に関して、かなり強引に変換してみました。
もしかしたら設定次第でなんとかなるのかもしれませんが、こんな風にしても変換できるということを紹介させていただきました。