ナナヤ 学習帳

書きたいことを書くブログ

【Unity】アセットの中に全角スペース、半角スペースが含まれているか調べる

初めに

Unityのプロジェクトに含まれれるアセットの中に全角・半角の空白が含まれているファイルを探すものを作ってと言われたので作ってみた。 実務で使えるかどうかははてなマーク

環境

  • VisualStudio2019
  • Unity2020.1.0b

使用用途

空白が含まれているファイルを見つけて、一括でリネームするだけのもの。

リネームに関しては、ただ空白を詰めるだけのもの。

名称を決めることはできません。(入れてないだけ。)

使用方法

f:id:nanaya7896:20200901210204p:plain

1. "Assets/Find Space Files And ReNames"を選択する。

f:id:nanaya7896:20200901210329p:plain

2. 検索対象のフォルダ:走査したいフォルダを選択

子フォルダも全部走査します。

アセットフォルダ以下すべて ☑:Assetsファイル以下すべてを操作する。検索対象のフォルダの項目が消えます。

↓こんな感じ f:id:nanaya7896:20200901210603p:plain

検索開始:フォルダの走査をします。

f:id:nanaya7896:20200901211643p:plain

3.検索した結果が出てきます。

何もない場合は特に何も出ません。

  • 上が全角スペースを含むファイル
  • 下が半角スペースを含むファイル

File All ReName:ファイルの一括リネームウィンドウを表示します。

f:id:nanaya7896:20200901211930p:plain

4. リネームウィンドウ

元の名前 => 新しい名前

に修正します。

ReName Ok?を選択するとリネームが開始します。

コード全文

開くとコードが出てくるよ

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
using System.Text.RegularExpressions;
using System.IO;

public class ExtensionFindSpace : EditorWindow
{
    // 全角スペース
    private static readonly string BIG_SPACE  = " ";
    // 半角スペース
    private static readonly string HALF_SPACE =  " ";
    private enum SpaceType
    {
        BIG,
        HALF,
        NONE
    }
    private Dictionary<SpaceType, string[]> m_dicResultContainsSpace = new Dictionary<SpaceType, string[]>();
    //! フォルダを指定する
    private Object folder = null;
    //! true: Assetsフォルダ以下全て走査 false:フォルダ指定可能
    private bool isAsset = false;
    //! 検索が実行されたかどうか
    private bool isExcute = false;
    //! 指定されたフォルダ以下のフォルダの配列
    System.IO.DirectoryInfo[] subFolders = null;
    List<string> resultBigSpacelist = new List<string>();
    List<string> resultHalfSpacelist = new List<string>();
    // スクロールビューの座標
    private Vector2 m_leftVerticalScrollPos = new Vector2();
    private Vector2 m_rightVerticalScrollPos = new Vector2();
    [MenuItem("Assets/Find Space Files And ReNames")]
    static void Open()
    {
        GetWindow<ExtensionFindSpace>();
    }

    private void OnGUI()
    {
        // リネーム用のWindowが開いている時は処理を行わない。
        if (ReNameAllFile.IsOpen)
        {
            return;
        }
        if (!isAsset)
        {
            folder = EditorGUILayout.ObjectField("検索対象のフォルダ", folder, typeof(DefaultAsset), true);
        }
        isAsset = EditorGUILayout.Toggle("アセットフォルダ以下すべて走査しますか?", isAsset);

        if (this.folder == null && !isAsset)
        {
            return;
        }
        if (GUILayout.Button("検索開始"))
        {
            isExcute = IsSearchContainSpaceinFileName();
        }
        
        if(!isExcute)
        {  
            EditorGUILayout.LabelField("Contains \"Space\" File Not Found");
            Clear();
            return;
        }
        List<string> result = new List<string>();
        if (m_dicResultContainsSpace.ContainsKey(SpaceType.BIG))
        {
            FileNameBigSpaceScrollView(m_dicResultContainsSpace[SpaceType.BIG]);
            result.AddRange(m_dicResultContainsSpace[SpaceType.BIG]);
        }
        if (m_dicResultContainsSpace.ContainsKey(SpaceType.HALF))
        {
            FileNameHalfSpaceScrollView(m_dicResultContainsSpace[SpaceType.HALF]);
            result.AddRange(m_dicResultContainsSpace[SpaceType.HALF]);
        }

        if(m_dicResultContainsSpace.Count > 0)
        {
            if(GUILayout.Button("File All ReName"))
            {
                ReNameAllFile.Set(result.ToArray());
            }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    private void Clear()
    {
        m_dicResultContainsSpace.Clear();
        resultBigSpacelist.Clear();
        resultHalfSpacelist.Clear();
    }

    /// <summary>
    /// 指定されたフォルダ以下から全角、半角スペースが含まれているファイルを取得し、リストへ格納する
    /// </summary>
    /// <returns></returns>
    private bool IsSearchContainSpaceinFileName()
    {   
        // 検索開始する際に前回の結果を削除
        Clear();
        var path = AssetDatabase.GetAssetPath(folder);
        if (isAsset)
        {
            path = "Assets";
        }
        // パスフォルダの情報を取得
        System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(path);
        subFolders = null;
        // 指定されたフォルダ以下のフォルダをすべて取得する
        subFolders = di.GetDirectories("*", System.IO.SearchOption.AllDirectories);
        

        // 子階層にフォルダがない場合
        if(subFolders == null)
        {
            var files = di.GetFiles(path);
            foreach(var file in files)
            {
                AddSpaceList(file);
            }
            
        }
        else
        {
            foreach (var sub in subFolders)
            {
                var files = sub.GetFiles();

                foreach (var file in files)
                {
                    AddSpaceList(file);
                }
            }
        }

        if(resultBigSpacelist.Count > 0)
        {
            m_dicResultContainsSpace.Add(SpaceType.BIG, resultBigSpacelist.ToArray());
        }
        if(resultHalfSpacelist.Count > 0)
        {
            m_dicResultContainsSpace.Add(SpaceType.HALF, resultHalfSpacelist.ToArray());
        }

        return m_dicResultContainsSpace.Count > 0;
    }

    /// <summary>
    /// ファイルの情報から全角半角が含まれたデータをListに加える
    /// </summary>
    /// <param name="fileInfo"></param>
    private void AddSpaceList(FileInfo fileInfo)
    {
        SpaceType type = SpaceType.NONE;
        var assetPath = GetContainsSpace(fileInfo, out type);
        if (type == SpaceType.BIG)
        {
            resultBigSpacelist.Add(assetPath);
        }
        else if (type == SpaceType.HALF)
        {
            resultHalfSpacelist.Add(assetPath);
        }

    }
    /// <summary>
    /// スペースを含むファイルか銅貨を調べる
    /// </summary>
    /// <param name="file"></param>
    /// <param name="type">out 含まれていたスペースのタイプを返す</param>
    /// <returns></returns>
    private string GetContainsSpace(System.IO.FileInfo file , out SpaceType type)
    {
        type = SpaceType.NONE;
        // メタファイルは結果には入れない
        if (file.Name.Contains(".meta"))
        {
            return "";
        }
        string[] splitPath = Regex.Split(file.FullName, pattern: @"\\Assets\\");
        string assetPath = @"Assets\" + splitPath[1];
        if (file.Name.Contains(BIG_SPACE))
        {
            type = SpaceType.BIG;
            return assetPath;
        }
        else if(file.Name.Contains(HALF_SPACE))
        {
            type = SpaceType.HALF;
            return assetPath;
        }
        return "";
    }

    /// <summary>
    /// ファイルネームに全角の空白が含まれているファイルの一覧をスクロールビューで表示する
    /// </summary>
    private void FileNameBigSpaceScrollView(string[] resultStrs)
    {
        EditorGUILayout.BeginVertical();
        {
            m_leftVerticalScrollPos = EditorGUILayout.BeginScrollView(m_leftVerticalScrollPos, true, true, GUILayout.Height(350));
            {
                for (int i = 0; i < resultStrs.Length; i++)
                {
                    EditorGUILayout.SelectableLabel(resultStrs[i]);
                }
            }
            EditorGUILayout.EndScrollView();
        }
        EditorGUILayout.EndVertical();
    }

    /// <summary>
    /// ファイルネームに半角の空白が含まれているファイルの一覧をスクロールビューで表示する
    /// </summary>
    private void FileNameHalfSpaceScrollView(string[] resultStrs)
    {
        EditorGUILayout.BeginVertical();
        {
            m_rightVerticalScrollPos = EditorGUILayout.BeginScrollView(m_rightVerticalScrollPos, true, false, GUILayout.Height(350));
            {
                for (int i = 0; i < resultStrs.Length; i++)
                {
                    EditorGUILayout.SelectableLabel(resultStrs[i], GUILayout.Height(20));
                }
            }
            EditorGUILayout.EndScrollView();
        }
        EditorGUILayout.EndVertical();
    }
}

public class ReNameAllFile : EditorWindow
{
    private static readonly string Format = "{0} => {1}";

    private static ReNameAllFile window = null;
    private static string[] m_renameFiles = null;
    private bool isExcute = false;

    private static bool isOpen = false;
    public static bool IsOpen
    {
        get
        {
            return isOpen;
        }
    }
    private static void Open()
    {
        window = GetWindow<ReNameAllFile>();
        window.Show();
        isOpen = true;
    }

    public static void Set(string[] strs)
    {
        m_renameFiles = strs;
        Open();
    }
    public void OnDestroy()
    {
        window = null;
        m_renameFiles = null;
        isExcute = false;
        isOpen = false;
    }

    private void OnGUI()
    {
        if(m_renameFiles.Count() == 0)
        {
            EditorGUILayout.LabelField("Rename File not found. please call Set Method,Before call Open");
            return;
        }

        if (!isExcute)
        {
            for (int i = 0; i < m_renameFiles.Count(); i++)
            {
                var spDel = m_renameFiles[i];
                spDel = spDel.Replace(" ", "").Replace(" ", "");
                var label = string.Format(Format, m_renameFiles[i], spDel);
                EditorGUILayout.LabelField(label);
            }
            if (GUILayout.Button("ReName OK?"))
            {
                isExcute = true;
            }
            return;
        }

        var result = new List<string>();

        for(int i=0;i<m_renameFiles.Length;i++)
        {
            var r = m_renameFiles[i];
            r = r.Replace(" ", "").Replace(" ", "");
            var split = System.IO.Path.GetFileNameWithoutExtension(r);

            Debug.LogFormat("{0} => {1}", m_renameFiles[i], split);
            var msg = AssetDatabase.RenameAsset(m_renameFiles[i], split);
            if(msg.Length > 0)
            {
                Debug.LogError(msg);
            }
            
        }
        isOpen = false;
        window.Close();
    }
}

ちょっとだけ解説

Unityでファイルのリネームを行う場合

AssetDataBase.RenameAssetを使用するといいぞ。

.metaも書き換わっている

RenameAsset(string assetPath.string fileName);

第二引数のファイルネームはフルパスではなく拡張子を除いたファイル名のみ

これにはまってエラーはきまくりました。

docs.unity3d.com

【Unity】【Editor拡張】Transformの値をクリップボードに保存してみた。

初めに

今回作成したのは、

汎用的な用途ではなくとある一点にのみ有用なEditor拡張として君臨します。

ほんとに用途は限定的です。。。

使用用途

Transformの値をコピーして、そのコピーした内容をClipboardに保存してしまおうという機能です。 単純にそれだけです。 なお、エクセルにペーストしても問題ないように(というか特化)一応別セルへ分けれるようにはなっております。

使用方法

1.Hierarchyでオブジェクトを選択して、コンポーネント右上のメニュー(点が縦に三連なっているやつ)を選択します。

その中にある、「CustomCopy」を選択します。 f:id:nanaya7896:20200621193621p:plain

選択するとConsoleにコピーした値が表示されます。

※Debug.Logが有効の場合のみ

f:id:nanaya7896:20200621194258p:plain

終了!

ちなみに

スプシにPasteするとこうなります。

f:id:nanaya7896:20200621194730p:plain

ね?便利でしょ?()

コード全文

クリックすると展開されます

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if DEBUG
using UnityEditor;
#endif
using System.Text;


public class CustomCopyComponent : Editor
{
#if DEBUG
    // コピー対象のオブジェクト
    public static GameObject copyObject;
    // コピー対象のオブジェクトのTransform
    public static Transform copyComponent;
    // context menu へ追加
    [MenuItem("CONTEXT/Component/Custom Copy", false,100)]
    static void ComponentCopy()
    {
        // 現在選択されているオブジェクト
        copyObject = Selection.activeGameObject;
        if(copyObject == null)
        {
            return;
        }
        copyComponent = copyObject.transform;
        if(copyComponent == null)
        {
            return;
        }
        Vector3[] copyTransform = new Vector3[3];
        // 必要なTransformの要素を取得
        copyTransform[0] = copyComponent.localPosition;
        copyTransform[1] = copyComponent.localEulerAngles;
        copyTransform[2] = copyComponent.localScale;

        StringBuilder strBuilder = new StringBuilder();

        foreach(var c in copyTransform)
        {
             // 文字列結合
            strBuilder.AppendFormat("{0} ", c);
        }
        // 末尾のタブ列は不要なため削除
        strBuilder.ToString().TrimEnd('   ');
        Debug.Log(strBuilder.ToString());
        // システムのバッファへコピー
        GUIUtility.systemCopyBuffer = strBuilder.ToString();
    }
#endif
}

ちょっとだけ解説

Selection.activeGameObject;

Unity上で現在選択されているオブジェクトがこの中に入っています。

GUIUtility.systemCopyBuffer = strBuilder.ToString();

いつも使うコピー(Ctrl+C)と同じ動作をすると思えばきっと問題なさそう。 コピーされたものはクリップボードにも保存されます。 (Windows+Vで確認できます。)

下に公式を張っておきます。

docs.unity3d.com