読者です 読者をやめる 読者になる 読者になる

たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

UnityのTextでシンタックスハイライトしたい

半袖半ズボンにはまだ早い

さむい

今回はちょっと雑記

シンタックスハイライトしたい

シンタックスハイライト(英: Syntax highlighting)とは、テキストエディタの機能であり、テキスト中の一部分をその分類ごとに異なる色やフォントで表示するものである。シンタックスカラーリング(英: Syntax coloring)とも。 Wikipedia -シンタックスハイライト

したい

まずは手法をググってみたんですが、パーサかいたりするのとかツール使うのとかあるみたいですね

でも大体はテキストマッチングみたいですね・・・

普通にテキストマッチング

リッチテキスト形式を使って色付けするのでテキストマッチングはむしろ良い手泣きがします。

早速書くんですがその前に練習がてら3つほど拡張メソッド書きました。

public static string[] Split(this string s,char[] separator,bool containSeparator) {
    List<string> rt = new List<string>();
    rt.Add("");
    int index = 0;
    for(int i = 0; i < s.Length; i++) {
        var item = s[i];
        int _sepaIndex = Array.IndexOf(separator, item);
        if (_sepaIndex != -1 && containSeparator) {
            rt.Add(separator[_sepaIndex]+"");
            rt.Add("");
            index += 2;
        } else {
            rt[index] += s[i];
        }
    }
    return rt.ToArray();
}
public static string Docking(this string[] s) {
    var length = s.Length;
    string str = "";
    for (int i = 0; i < length; i++) {
        str += s[i];
    }
    return str;
}
public static string ToRichTextColor(this string s, Color col) 
    => "<color=#" + ColorUtility.ToHtmlStringRGB(col) + ">" + s + "</color>";

Splitオーバーロードですね。既にあるSplitだとセパレーターに指定した文字列を失ってしまうので作りました。
セパレーターが1種類なら連結するときに指定すればいい話なんですが、今回は複数個あったので作りました。
Dockingstring.Joinに似たやつってかそのものですがJoinを使わなかったのはメソッドチェーンに組み込めな・・・いとおもうから(あいまい)
ToRichTextColorはそのままリッチテキスト形式に書き換えるだけですね

Dockingの方は使う予定がないけどもう一つ書きました

public static string Docking<T>(this IEnumerable<T> list,Func<T,string> toStringer=null) {
    string rt = "";
    foreach (var item in list) {
        if (toStringer != null) {
            rt += toStringer(item);
        } else {
            rt += item.ToString();
        }
    }
    return rt;
}

list.ForEach(a => str += a);とかするのちょっとカッコ悪く感じてたのでいいでしょう。うん まぁJoinでいいんですが・・・

それらを組み合わせてシンタックスハイライトするのがこちら

//テキスト更新
TX_OneLine.text = user_inputString
                    .Split(separator, true)
                    .Select(splited =>
                    {
                        if (separator.Any(___=>___.ToString()==splited)) {
                            return splited.ToRichTextColor(color_separator);
                        } else if (syntaxArray.Any(___ => splited == ___)) {
                            return splited.ToRichTextColor(color_syntax);
                        }
                        return splited;
                    }).ToArray().Docking();

シンタックスしたいのは大した量でないのでこれでいいでしょう

それでは良いシンタックスハイライトを!