Pythonで CSV -> Json を作る(そしてそれをUnityで読み込み)
はじめに
前回に引き続き必要になったのでメモっておきます。
Pythonを使ってCSVとして保存されたファイルを読み込み、Jsonファイルとして出力。
それをUnityで読み込みます。
Pythonを使うことになった理由は単に興味があったからですw
※2017.9.20修正
Pythonのファイル名、データを格納するための Parts クラスでのアトリビュートの宣言方法を修正しました。
CSVを読み込む
まずはCSVを読み込んで、 Parts というクラス(酷い名前なのは気にしない方向で。。。)に格納します。
parts.csv
PartsNo,PartsName,Description, No.1,Parts1,一つ目のパーツです, No.2,Parts2,二つ目のパーツです,
parts.py
# -*- coding: utf-8 -*- # coding: utf-8 class Parts: def __init__(self, parts_no: str, parts_name: str, description: str): self.parts_no = parts_no self.parts_name = parts_name self.description = description
main.py
# -*- coding: utf-8 -*- import csv from parts import Parts def main(): # CSVファイルを読み込む. with open(f'parts.csv', encoding='utf-8') as csvFile: for index, row in enumerate(csv.reader(csvFile)): # タイトル行を無視する. if index <= 0: continue # 読み込んだ内容に[]が含まれているためそれを取り除く. replace_row = remove_symbols(str(row)) split_rows = str.split(replace_row, ',') # コンマ区切りでSplitした内容をクラスに格納. new_parts = Parts(split_rows[0], split_rows[1], split_rows[2]) def remove_symbols(original: str): # 読み込んだ内容に[]、半角スペースが含まれているためそれを取り除く. remove_left_bracket = str.replace(original, '[', '') remove_right_bracket = str.replace(remove_left_bracket, ']', '') remove_space = str.replace(remove_right_bracket, ' ', '') return remove_space main()
- 「with」を使用することで、C#の「using」と同様ファイルの使用が終わったら自動で開放してくれるようになります。
- 読み込んだ内容は「[‘PartsNo’, ‘PartsName’, ‘Description’, ‘’]」のように [ と ] が含まれるため、それを取り除く必要があります
(もう少し上手いやり方がありそうな気はしています)。 - 今回は読み込んだ内容をわざわざクラスに入れる必要はあまりないのですが、形式や文字数に制限がある場合などはクラス格納 -> チェックとした方が良さそうです。
Jsonファイルとして出力
クラスのデータをDictionaryデータとして受け取る
このままクラスをJsonに変換できると良いのですが(C#やJavaのように)、
Pythonでは難しいようです。
そのため、クラスとして格納したデータを受け取って、Dictionaryとして返すようにします。
parts_dictionary_factory.py
# -*- coding: utf-8 -*- from parts import Parts class PartsDictionaryFactory: def create(self, target_parts: Parts): if type(target_parts) != Parts: return return {"PartsNo": target_parts.parts_no, "PartsName": target_parts.parts_name, "Description": target_parts.description}
main.py
# -*- coding: utf-8 -*- import csv from parts import Parts from parts_dictionary_factory import PartsDictionaryFactory def main(): parts_dictionary = [] dictionary_creator = PartsDictionaryFactory() with open(f'parts.csv', encoding='utf-8') as csvFile: for index, row in enumerate(csv.reader(csvFile)): if index <= 0: continue replace_row = remove_brackets(str(row)) split_rows = str.split(replace_row, ',') new_parts = Parts(split_rows[0], split_rows[1], split_rows[2]) # Dictionaryのデータに変換したものをDictionaryに追加. parts_dictionary.append(dictionary_creator.create(new_parts)) ~省略~
Jsonファイルの出力
あとはこれまで取得・変換した文字列をJsonに置き換えて、 ファイルとして出力するだけです。
main.py
# -*- coding: utf-8 -*- import json import csv from parts import Parts from parts_dictionary_factory import PartsDictionaryFactory def main(): parts_dictionary = [] dictionary_creator = PartsDictionaryFactory() with open(f'parts.csv', encoding='utf-8') as csvFile: for index, row in enumerate(csv.reader(csvFile)): if index <= 0: continue replace_row = remove_symbols(str(row)) split_rows = str.split(replace_row, ',') new_parts = Parts(split_rows[0], split_rows[1], split_rows[2]) parts_dictionary.append(dictionary_creator.create(new_parts)) meta_parts = {"ModelName": "Model1", "PartsList": parts_dictionary} # 文字列をJson形式に変換. json_text = json.dumps(meta_parts) # ファイル出力. with open(f'parts.json', 'w') as file_object: file_object.write(json_text) file_object.flush() def remove_symbols(original: str): remove_left_bracket = str.replace(original, '[', '') remove_right_bracket = str.replace(remove_left_bracket, ']', '') remove_space = str.replace(remove_right_bracket, ' ', '') return remove_space main()
結果として下記のようなファイルが作成されます。
parts.json
{ "ModelName": "Model1", "PartsList": [ { "PartsNo": "'No.1'", "PartsName": "'Parts1'", "Description": "'\u4e00\u3064\u76ee\u306e\u30d1\u30fc\u30c4\u3067\u3059'" }, { "PartsNo": "'No.2'", "PartsName": "'Parts2'", "Description": "'\u4e8c\u3064\u76ee\u306e\u30d1\u30fc\u30c4\u3067\u3059'" } ] }
- 実際は改行されずに出力されますが、見やすさのために編集しています。
UnityでJsonファイルを読み込む
UnityでJsonのデータをクラスに格納するのは以前もやりましたが、
今回もJsonUtilityを使用します。
まずはJsonのデータを格納するクラスの準備から。
今回はJsonの中に配列(PythonでDictionaryとして出力したもの)が含まれており、
これを格納する Parts というクラスと、
Parts のリスト、及びメタ情報(ModelName)を格納する MetaParts というクラスを作成します。
(名前の酷さはry)
Parts.cs
using System; [Serializable] public class Parts { public string PartsNo; public string PartsName; public string Description; }
MetaParts.cs
using System; using System.Collections.Generic; [Serializable] public class MetaParts { public string ModelName; public ListPartsList; }
- Jsonのデータを格納するクラスには [Serializable] をつけておく必要があり、
これがないとうまくデータを格納できませんでした。
ファイルの読み込みとJsonデータからの変換
あとはJsonファイルを読み込み、クラスに格納します。
JsonファイルはUnityEditorで動かす場合は Assets フォルダ直下、Windowsで出力した場合は プロジェクト名_Data フォルダの直下に置きます。
FileLoader.cs
using System.IO; using System.Text; using UnityEngine; public class FileLoader { private readonly string filePath; public FileLoader() { filePath = Application.dataPath + @"/parts.json"; } public MetaParts LoadFromJson() { if (File.Exists(filePath)) { // ファイルの読み込み. using (var reader = new StreamReader(filePath, Encoding.UTF8)) { // ファイルの内容は一括で読み込む. var readText = reader.ReadToEnd(); if (readText.Length > 0) { // Jsonからの変換に関するエラーチェックは省略. return JsonUtility.FromJson(readText); } } } return new MetaParts(); } }
あとはこのクラスを読んであげればOKです。
終わりに
Pythonを使うことで、さらっと処理が書けるのは良いと感じます。
ただ、C#でやるように常に型を意識して書きたいのならちょっと厳しいかもしれませんね。
その辺り、Pythonならではの便利なやり方というものがあると思うので、
それを身につけられたらな、と思います。
参照
Python
- 7. 入力と出力 — Python 3.6.1 ドキュメント
- 14.1. csv — CSV ファイルの読み書き — Python 3.6.1 ドキュメント
- 26.1. typing — 型ヒントのサポート — Python 3.6.1 ドキュメント
- みんなのPython 第4版
- 【Python入門】for文でデータのindexを取得する方法 - プロスタ
- Pythonではじまる、型のある世界 - Qiita