はらけんログ

unity触ったりバイクに乗ったり

【Unity】CSVの読み込みでハマるあれこれ

外部ファイルからアプリ内設定をしたり、データそのものを外部ファイルで扱いたいときって多々あるよね。

 

今回は外部ファイル(CSV)の読み込み方とか覚書しておく。

 

そもそもUnityで外部ファイルを扱う場合は「StreamingAssets」フォルダーを作成し、その中のファイルを独自に管理しなければならない。(とはいってもフォルダー名とか形式とかぐらいだが)

まぁこのあたりは他資料を参照してもらって、問題はExcelなどで管理したデータを使用する際に多用されるCSVファイルを読み込む方法について踏み込む。

 

・ざっくりと読み込み方

ExcelC#の大きな壁は文字コードだ。

Excelで書き出す際にShift-JISからUTF-8に変えないとC#では扱いづらい(個人的に)

Excelでは書き出すときに設定ができるので、そこはよしとして、次にC#UTF-8の文字列を読み込むには?って話をしよう。

 

これにはファイルを読み込むためのFileと文字コードを指定するEncodingクラスを使用する。FileはネームスペースにSystem.IOをEncodingはネームスペースにSystem.Textを追加しておく必要がある。

using  UnityEngine;

using System.Text;
using System.IO;

public class TestRead:Monobehaviour

{

    Encoding encoding;

    void  Start()

    {
  this.encoding = Encoding.GetEncoding("utf-8");

        string path =  Application.streamingAssetsPath + "test.csv";

        string csvText = File.ReadAllText(path, this.encoding);

        string dataStr = csvText .Split(","[0]);

    }

}

 

 

Start関数の1行目は文字コードの設定。

2行目は読み込むファイルのディレクトリを指定。

3行目ですべての文字列を読み込む。

4行目でCSVのカンマ区切りで文字をぶった切っている。

 

たったのこれだけ。

 

これで取得したデータを煮るなり焼くなりする。

 

 

 

 追記

セルの中に区切り文字(,)がある場合

ExcelからCSVに書き出す際に、セルの中身に「,」がある場合、「"any,text"」みたいな感じにダブルクォートでかこまれて書き出される。

このままでは、Splitで分割した際に「"any」と「text"」といった感じに分割されてしまう。  なので、一文字ずつ検索して見つけたら変換って感じにする。

(区切り文字を別にする、書き出し時にダブルクォートをつけなくする、とか言う注文ができない人用)

using  UnityEngine;

using System.Text;
using System.IO;

public class TestRead:Monobehaviour

{

    Encoding encoding;

    string dataString; 

    char targetChar = '"';
    char kanma = ',';

 

    void  Start()

    {
  this.encoding = Encoding.GetEncoding("utf-8");

        string path =  Application.streamingAssetsPath + "test.csv";

        string csvText = File.ReadAllText(path, this.encoding);

        

        StringBuilder sb = new StringBuilder(csvText .Length);
        int index = 0; //ダブルクォートをカウント
        bool addFlag; //ダブルクォートだったら加えない


        foreach (char c in csvText)
        {
            addFlag = true;
            char ch = c;
            if (c == targetChar) //ダブルクォートだったら
            {
                addFlag = false;
                index++;
            }
            if (c == kanma) //カンマだったら
            {
                 if (index % 2 != 0) //ダブルクオートの中にあるカンマ
                 {
                      ch = ',';  //別の文字に変換
                 }
            }

            if (addFlag)
            {
                sb.Append(ch);
            }
       }
       string replaceStr = sb.ToString();

 

       dataStrng = replaceStr .Split(","[0]);


       for(int i = 0; i < dataStr.Length; i++)
       {
            dataStr[i]= dataStr[i].Replace(',', ','); //別の文字に変換したカンマを元に
       } 

    }

}

 太文字の部分が重要。

ダブルクォートを文字列から外して、Splitで変換したくないカンマを「大文字のカンマ」に変えている。(大文字のカンマでなくてもなんでもいい)すべて変換し終わったらSplitで配列にして、このあとに配列に入っている文字列の大文字カンマを半角カンマに直している。

 

 

1行目と2行目の間にもカンマを入れたい

2行3行と行がかさむのは当たり前なんだけど、「行の最後のセル」と「次の行の最初のセル」の間には区切り文字が入らず改行コードが入る。

このままだとSplitした時に両方とも同じ文字列になってしまうので変換する。

using  UnityEngine;

using System.Text;
using System.IO;

public class TestRead:Monobehaviour

{

    Encoding encoding;

    void  Start()

    {
  this.encoding = Encoding.GetEncoding("utf-8");

        string path =  Application.streamingAssetsPath + "test.csv";

        string csvText = File.ReadAllText(path, this.encoding);

   csvText = csvText .Replace(System.Environment.NewLine, ",");

        string[] dataStr = csvText .Split(","[0]);

    }

}

 System.Environment.NewLineは改行コードの意。これを「,」に直している。

こうした後にSplitすれば行の変わり目も文字列をくぎることができる。