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

たいちょーの雑記

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

!!????!??????! !!?????!??!!?? !!?????!?!?!!! !!????!????!!! !!?????!!!!!?? !!?????!?!?!!! !!????!????!!! !!?????!!!!!?? !!?????!?!!??! !!????!???!?!!

雑記

!!????!!?!!!?? !!????!?!??!?? !!????!?!!!??! !!????!!!?!!?! !!????!?!??!?? !!????!!??!??! !!?????!??!!?? !!?????!!!!?!! !!?????!?!?!!! !!?????!???!??

!???!?!????!!??? !??!!!?!???!?!! !!?????!!?!??? !!?????!??!?!! !???!?!?!?!?!!?! !!?????!!!!!!? !!?????!?!!?!! !!?????!?!!!!! !!?????!???!??

!!?????!?!??!! !!?????!!?!!!? !!??!?!!????!!! !!!!?!?!!!????? !!?????!??!!?? !???!?!?!?!?!!?! !!????!??????! !!?????!!??!!? !!?????!???!?? !!????!???!?!! !!?????!!?!??? !!?????!???!?? !!?????!???!!? !!?????!?!??!! !!?????!!?!??? !!?????!!?!!!!

!!?????!?!??!! !!?????!!?!!!? !!??!?!!????!!! !!!!?!?!!!????? !!?????!??!!?? !???!?!?!?!?!!?! !!????!??????! !!?????!!??!!? !!?????!???!?? !!????!???!?!! !!?????!!?!??? !!?????!???!?? !!?????!???!!? !!?????!?!??!! !!?????!!?!??? !!?????!!?!!!! !!???????????! !?!?!?????!!?!! !!?????!!?!!!! !!?????!!?!??? !!?????!!???!! !!?????!!??!!? !!????!?????!? !!??!!?!????!!! !!?????!!?!?!? !!????!??!??!! !!?????!!????? !!?????!!?!!?! !!!!!!!!???!!!!!

!!????!?????!? !!?????!!????! !!????!???!!?! !!????!??!??!! !!???????????! !!?????!???!?? !!?????!!!!!!? !!?????!?!??!! !!????!???!!?? !!????!??!??!? !!??!!?!!!!!??? !!?????!???!?? !!?????!!??!!? !!?????!???!?? !!????!???!?!! !?!????!!?!?!?! !!????!?????!? !!??!!?!????!!! !??!!!?!?!!!?!? !!?????!!?!?!? !!????!??!??!! !!?????!!????? !!?????!?!???! !!?????!!?!??! !!?????!!?!!?!

!!?????!!!?!!? !!?????!!???!! !!?????!!????! !!????!?????!! !!?????!?!???! !??!!!!?!?!?!?! !!!?!?!?!!?!?!? !!!???!?!??!!!? !!?????!?!!??? !!?????!!????? !!????!???!??? !!?????!!???!! !!?????!!??!!? !!????!!??!!?! !!????!?!!!!!! !!?????!!??!!! !!?????!?!!??! !!?????!??!!?? !!?????!!?!!?!

!!?????!?!??!! !!????!??!??!! !!?????!!?!?!? !!?????!?!??!! !!?????!!?!??? !!????!??!??!? !!?????!?!??!! !!?????!?!??!! !!?????!!?!?!! !!??!!?!!!!!??? !!?????!??!!!! !!?????!!?!!!? !!?????!!?!!!! !!?????!!?!?!? !!????!??!??!! !!?????!!????? !!?????!?!???! !!?????!!?!??! !!???????????! !!?????!?!??!! !!?????!!?!!!? !???!?!????!!??? !??!!!?!???!?!! !!????!??!??!? !???!?!?!?!?!!?! !!????!??????? !!?????!!?!?!! !!?????!!?!!!! !??!!!?!!!??!?! !??!!!?????!?!! !!?????!!?!!!? !!????!?!!?!!! !!????!?!??!!! !!????!!!?!?!! !?????!?!?!!!??? !!?????!??!!?? !!??!!!????!??! !?!??!?!?!!!??! !!?????!!????? !!????!???!???

!!??!?! !!???!! !!?!??? !!?!!!! !????? !???!? !!????!?????!? !!?????!?!!??? !!????!???!!?? !!?????!!??!?? !???!? !!!!!?? !!!??!! !!??!?! !!??!?? !????? !??!!! !!!??!! !?!!!! !!???! !?!!!! !????! !?!!!! !!??!!! !!!?!! !!!??!! !?!!!! !!???? !?!!!! !!!!!! !?!!!! !!??!!! !!!?!! !!!??!! !?!!!! !????? !?!!!! !?!!!?? !!?!!!? !?!!!! !!??!!! !??!!! !!!!!?? !!????! !!!?!!! !!?!?!! !????? !??!!! !!!!?!! !!!???? !!!??!? !!?!??! !!?!!!? !!!?!?? !????? !???!? !!?!??! !!???!? !!????! !!!??!! !!??!?! !!!!?! !!??!? !!!?!! !???!? !??!?? !!???! !!!!!?! !??!!! !!!!!?? !!???!? !!???!! !!!!!?? !!????! !!!?!!! !!?!?!! !????? !??!!! !!!!!?? !!!???? !!!??!? !!?!??! !!?!!!? !!!?!?? !!??!!? !????? !???!? !??!?! !!???!! !???!? !?!!?? !??!?? !!???! !!!?!! !!??!?! !!?!??? !!???!! !!?!!!!

!!?????!????!? !!?????!!?!??? !!?????!!?!!!! !?????! !?!??!! !????!! !??!??! !??!??! !!?????!!?!?!! !?!!??!????!??! !!???!!!!?!!?!! !!?????!?!!??! !!????!???!?!! !!?????!!????? !!?????!?!???! !!?????!!??!!! !!?????!?!!??! !!?????!!?!!?! !!!!!!!!???????!

!??!!!!?!?!?!?! !!?????!!?!!!? !!?????!?!!!!! !!????!??????! !!?????!!?!!!? !???!?!????!!??? !??!!!?!???!?!! !!?????!!?!?!? !!?????!!?!!!? !!!!!!!!???!!!!!

!!????!?????!? !!?????!??!!!! !!?????!!??!!? !!?????!??!!?! !!?????!!?!!!! !!?????!!?!??? !!?????!??!!!! !!?????!!?!?!! !!?????!!?!?!? !!?????!???!?? !!?????!!??!!! !!?????!?!!??! !!????!???!??? !!????!!!!!?!! !!????!!!!!?!! !!????!!!!!?!! !!!!!!!!???????! !!?????!?!?!!! !!?????!???!?? !!?????!!??!!? !???!?!????????? !!?????!???!!? !!?????!!?!?!? !!????!???!??! !!?????!!!???! !!?????!!???!! !!?????!!?!??? !???!??!!???!?!! !!?????!!??!!! !?!!!!!???!?!?! !!?????!???!?? !!?????!!??!!? !!?????!!!!?!! !!?????!?!?!!! !!?????!??!?!! !!?????!!???!! !!?????!?!!!!! !!?????!!????? !!?????!?!???! !!?????!!??!!! !!?????!?!!??! !!?????!!?!!?! !!!!!!!!???????!

!!?????!?!!!?! !!????!???!!?! !!?????!?!!!?! !!????!???!!?! !??????!!!!?!?!? !?!??!??????!!? !!?????!!??!!! !!????!?????!? !??!!!!?!?!?!?! !!?????!??!?!! !!?????!???!?? !!?????!!??!!? !!????!???!?!! !!?????!??!?!! !!????!???!!!! !!?????!??!?!! !!????!???!??! !!?????!!?!?!? !!?????!??!!!! !!?????!!?!?!? !!?????!!???!! !!?????!!??!!? !!?????!??!!?! !!?????!?!!!!! !!?????!!?!!!? !!?????!!??!!! !!?????!?!??!! !!?????!!?!!!? !???!!!!!?!!!?!? !!?????!!??!!! !!!!!?!?!????!? !!????!???!!!! !!????!???!?!? !!?????!!!!!!? !!?????!?!!??!

!!?????!?!!!?! !!????!???!!?? !!?????!!??!!! !!?????!!?!!!! !?????!??!!?!!!! !!?????!???!?? !??!!!?!???!!?? !??!??????!!??!? !!??!?!?!!!???? !!????!!!?!??! !!????!?!??!?? !!????!!?!?!?! !!????!??!??!? !!!!!!!!???????!

!?!??!!!!????!? !?????????????!!

!?????! !?!??!! !????!! !??!??! !??!??! !!????!?!!??!! !!????!!!!!!?? !!????!!??!??! !?!!??!????!??! !!???!!!!?!!?!! !!?!?!??!?!!!!!

たのしい拡張メソッド

C# Unity 雑記

肘の痛みが取れない

たぶんしぬ

VSがないといきていけない

VisualStudio2017がリリースされましたね。 www.visualstudio.com
自分はUnityとかC#でなんかするときはエディターにVSCommunityを使ってますので新バージョンのリリースはわくわくもんです。

ぼくはインテリセンスにどっぷり浸かってしまっているので他のではできないですね・・・おそるべし

インストーラーの段階でUnityのツールが同時にインスコできたりするので楽になりましたね。

何よりUIがかっこいいのよね

拡張メソッドたのしい

前回の記事でちょいと書いた拡張メソッドなんですけど、あれからそれにはまってしまいました。
拡張メソッドにハマるってなんだよ って思うと思うんですけど、拡張メソッドばかり書いて肝心の作品ができてないってことです。沼ですね。

最近ではメソッドチェーンとか三項演算子を見ていると

纏めて一つの拡張メソッドにしたい

というわけのわからない衝動がわくようになりました。
例えば

str = str.Length < limit ? str : str.Substring(0,limit);

こういうのがあれば

public static string Truncate(this string s,int boader) {
    if (s.Length < boader) return s;
    return s.Substring(0, boader);
}

こうして

str = str.Truncate(limit);

こうしたくなるんです!可読性もいいし精神的に良いでしょ?変な変数も増えないし?補完も変数名かいて.打てばインテリセンスがしてくれるし

だからなんか作るのが止まらないです。おかげできれいにはなったんじゃないかな・・・・・・
最近は文字列処理系が多くて前回の記事にあったDocking()は派生が結構できちゃってたのしくなっちゃう

public static string RangeDocking<T>(this IEnumerable<T> list, int start, int range, Func<T, string> filter = null) {
    string str = "";
    T[] array = list.ToArray();
    for (int i = start; i < range; i++) {
        str += (filter != null ? filter(array[i]) : array[i] + "");
    }
    return str;
}

コレクションのここからここまで連結したい!なんていうのは日常茶飯事だし、デリゲート渡せばちょいとした加工もしながら連結できるし気に入ってる一つです。
ほかにも個人的に気に入ってるのがこちら

[Conditional("UNITY_EDITOR")]
public static void UnityDebugLog(this object s) {
    UnityEngine.Debug.Log("UnityDebugLog value = " + s);
}

てきとうに値が見たいだけなのにDebug.Log()打つのが面倒だったので拡張しちゃったほしみ
単純だけどすごくべんり・・・とけちゃう

文字列の後ろから何文字か削除とかいうメソッドも(たぶん)ないし、いちいちSubstringするのたるいし

public static string RemoveRangeFromLast(this string s,int range) {
    if (range <= 0) return s;
    return s.Substring(0, s.Length - range);
}

自分しか使わないので需要とかパフォーマンスも気にする必要ないし

/// <summary>
/// T1tT2のIEnumerableからUniRx.Tupleのリストを生成して返す罪深いメソッド
/// </summary>
public static List<Tuple<T1, T2>> MakeTupleList<T1, T2>(this IEnumerable<T1> list, IEnumerable<T2> combination) {
    List<Tuple<T1, T2>> rt = new List<Tuple<T1, T2>>();
    var listRange = list.Count() > combination.Count() ? combination.Count() : list.Count();
    var array_list = list.ToArray();
    var array_combi = combination.ToArray();
    for (int i = 0; i < listRange; i++) {
        rt.Add(new Tuple<T1, T2>(array_list[i], array_combi[i]));
    }
    return rt;
}

インデックスが範囲外になっちゃうの気にするのが楽になるし

/// <summary>
/// 定義域を超えないようにしてくれる心優しいメソッド
/// </summary>
public static int AutoDomain(this int value, int _min, int _max) {
    return value < _min ? _min : value > _max ? _max : value;
}

三項演算子りすぎてわけわからんくなった

さて作業にもどりますかね

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

C# Unity 雑記

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

さむい

今回はちょっと雑記

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

シンタックスハイライト(英: 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();

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

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

UnityでInputFieldを使わずに文字列を受け取る

C# Unity

掃除するときは気を付けろ

奴は大事なものを捨てていっちまったんだ

InputFieldでいいんじゃないのか?

最近せっせこ作っている作品では、キーボードからの文字列入力と同じ場所に出力が必要だったのでUnityがuGUIで提供しているInputFieldを使おうと思いました。
docs.unity3d.com

ふつーに文字列を受け取るところがあって、背景やフォントも変えられるふつーの入力フォームです。イベントの通知もできます。
Textを子に持っていてInputField.textに書き込んでやれば出力もできると踏んでました。
NoIF1

しかし問題点が一つありました。Enterを押すともう一度Enterを押さないと入力待ち状態にならない点です。
ぼくが欲しかったのは コマンドラインのような入出力環境 だったのです。
NoIF2
こういうの

Enterを押したらC#に入力文字列を送信して、また次の入力待ちしてほしいのです。
InputFieldのリファレンスを読んでみましたが、それっぽいプロパティは見つかりませんでした。
唯一Interactableというプロパティがそれっぽかったのですが、どちらかというとenabledに近い動作だったので期待した動作を実現できませんでした。

つくった

こういう痒いところに手が届かないときはワクワクして自前で用意していきます。
使うのは同じuGUIのTextです。
docs.unity3d.com
NoIF3
見づらいな

入力を受け取るソースはこちら

this.UpdateAsObservable().Subscribe(_ =>
{
    foreach (char item in Input.inputString) {
        if (item == '\b' && user_inputString.Length > 0) {
            user_inputString = user_inputString.Substring(0, user_inputString.Length - 1);
        } else if (item == '\r' || item == '\n') {
            user_inputString = "";
        } else {
            user_inputString += item;
        }
    }
    updateCommandLine();
});

Updateの代わりにUniRxを使っています。理由は特にないですけど
InputクラスのinputStringプロパティからそのフレーム中に入力された文字列を受け取って1字ずつ解読していきます。
もし\b(backspace)だったらSubstringで一字消し、\n(Enter)であれば文字列をクリアします。それ以外なら入力文字列として追加していきます。

こんなんでうまくいくんかいって思いながら書いてたんですが
NoIF4

ありえんぐらいうまくいった

ひとつ問題点があるとすれば日本語はEnterで確定するまで表示されないところですね。まあ使う予定がないのでいいですが

いつもこれくらいトントン進めばいいんですけどね。

Unityと文字コードでレッツダンスパーティ!

C# Unity bash 文字コード

続・僕らの文字コード

なんかVSCodeでMarkdown書くの使いやすくなってますね

文字コードという無限の闇

前回に続いて文字列に関する話題です
xztaityozx.hatenablog.com

bashからの出力を得てUnityに表示したいだけなんだけれども中々うまくいかなかったというお話だったわけですが
今回もなかなかうまくいかなかったお話です

Process process_bash = new Process();
ProcessStartInfo psi_bash = new ProcessStartInfo();
//設定
psi_bash.FileName = @"C:\cygwin64\bin\bash.exe";

psi_bash.RedirectStandardInput = true;
psi_bash.RedirectStandardOutput = true;
psi_bash.RedirectStandardError = true;

psi_bash.CreateNoWindow = false;
psi_bash.UseShellExecute = false;
psi_bash.Arguments = "--login";

//プロセス起動
process_bash = Process.Start(psi_bash);
process_bash.BeginOutputReadLine();
process_bash.BeginErrorReadLine();
process_bash.OutputDataReceived += onBashOutput;
process_bash.ErrorDataReceived += onBashError;

コード見てもらったらわかる通りOutputやErrorが出るたびハンドルを介して出力が得られる非常に簡単な構造
間違えそうなところがない

しかし!
MojiCode1
ご覧の通り文字がばけとります

www.bandai.co.jp

cygwinbashから受け取ったデータをUnityのTextに表示しているだけなんですが何がダメなのかな?
ともかくこのままじゃまともに使えないですね

文字コードをさがせ

文字化けについてggっていたところどうやらUTF-8でも BOM付き ってのと BOM無し ってのがあるみたいで?
site.oukasei.com

詳しいことはおいといて、UnityがBOMないとアカンのかどうかを調べてみると
MojiCode4

どうやら ソースについてはBOM付き である必要があるみたい
UnityのTextがどうかはわからないけどBOM付きUTF-8だろ~な~と思いました。

bashの方の出力がBOM付なのかどうかが問題ですね。
先ずは$LANGechoします

% echo $LANG
ja_JP.UTF-8

次に適当にコマンドをリダイレクトしてBOMついてるか見ます

% date > date_res.txt
% file date_res.txt
date_res.txt: UTF-8 Unicode text

BOM付きの場合は

date_res.txt: UTF-8 Unicode (with BOM) text

と出力されるのでどうやらBOM無しUTF-8のようです

このままではC#に渡したところで正常に出力されまへん
MojiCode5

さしあたってbashの出力にBOMをくっつければ解決するわけですから適当にBOMつけてみました。
MojiCode6

Encoding enc_src = new UTF8Encoding();
Encoding enc_dst = Encoding.UTF8;
byte[] noBOMbytes = enc_src.GetBytes(data);
byte[] BOM = enc_dst.GetPreamble();
byte[] appendedBOMBytes = BOM.Concat(noBOMbytes).ToArray();
string encodedStr = enc_dst.GetString(appendedBOMBytes);

そーれ

・・・
MojiCode1
画像は使いまわしです

あかんやんけ!!!!!!!!!

まぁ想定の範囲内でしたが(嘘)

実はShift_JISに浮気していた

そうこうしているうちにTwitterで心強いリプが

  

ええ!?Shift_JIS!?
んえ!?

いままでUnityのTextがUTF-8であると踏んでいましたがなんかShift_JISのようです・・・?
MojiCode7

こうなったらEncoding.Convertを使ってShift_JISにしてやります。

byte[] convBytes=Encoding.Convert(Encoding.UTF8,Encoding.GetEncoding("Shift_JIS"),data);
string convStr=Encoding.GetEncoding("Shift_JIS").GetString(convBytes);

これで円満解決。ね。

・・・
MojiCode1
画像は使いまわしです

ちょw

stdoutはすごぉい美少女

色々ggったりsrcとdst入れ替えたりProcessStandardOutputEncodingとかもいじってみたんですけどどうにもこうにもダメでした
なんかな~と思ってハンドラをやめてProcessStandardOutputから直接読み取ってみると文字化けしませんでした。

MojiCode8
たぶんstdoutがすごい美少女だから素直に言うこと聞くけど、ハンドラの方はさえない男なのでこういう塩対応なんでしょう

でも便利なハンドラの方使いたいです。さえないってところで親近感もわきますし

base64って

このままじゃ全く前に進まないので死んだ目をしながらggっていたんですがまたTwitterにて心強いリプが

base64ってなんやねん

Base64は、データを64種類の印字可能な英数字のみを用いて、それ以外の文字を扱うことの出来ない通信環境にてマルチバイト文字やバイナリデータを扱うためのエンコード方式である。MIMEによって規定されていて、7ビットのデータしか扱うことの出来ない電子メールにて広く利用されている。具体的には、A–Z, a–z, 0–9 までの62文字と、記号2つ (+, /)、さらにパディング(余った部分を詰める)のための記号として = が用いられる。この変換によって、データ量は4/3(約133%)になる[1]。また、MIMEの基準では76文字ごとに改行コードが入るため、この分の2バイトを計算に入れるとデータ量は約137%となる[2]。 Wikipedia -Base64

なるほど
どうやら変換用のbase64コマンドもCoreutilsに入っているようなのでだいたいの環境で使えそうです
適当にbase64に通して結果を見てみましょう

$ date | base64
MjAxN+W5tCAy5pyIIDE05pelIOeBq+abnOaXpSAxNTowMDoxOSBKU1QK

こいつを間に挟み込みましょう
bashのstdinに書き込むときに2>&1 | base64を付け加えておきます
MojiCode9
MojiCode10

デコードにはSystem.Convert.FromBase64String(String)メソッドをつかいます。

private void outputCommand(string o) {
    byte[] converted = System.Convert.FromBase64String(o);
    Encoding enc = new UTF8Encoding();
    string encoded = enc.GetString(converted);
    output = o + "\n" + encoded + "\n";
}
private void onBashOutput(object sender, DataReceivedEventArgs e) {
    outputCommand(e.Data);
}

それ~

MojiCode11
で、
でた~~~~~~~~~

いやー助かりました。

まだまだ終わらないぞ~~~~!

終わらないです。
この調子で行くかと思ったら違いました。不思議よね

まあ適当にコマンドの実験をしているとなんか変な結果が
MojiCode12

んw

このコマンドはないですという旨の出力を期待してたんですがなんかへんです
ちなみに本来なら

$ da 2>&1 | base64
YmFzaDogZGE6IOOCs+ODnuODs+ODieOBjOimi+OBpOOBi+OCiuOBvuOBm+OCkwo=

という文字列が得られるはずなんですが、gZvjgpMKしかとれてないしどことも部分一致しないんです・・・!

わーいwおもしろーいw

まぁとりあえず落ち着けよ
まずはstdoutとstderrを分けるんだ

da 2>&1 > /dev/null | base64 >&2;da 2> /dev/null | base64 >&1

そうそう・・・こうやって・・・
MojiCode12
画像は使いまわしです

まぁこういう問題じゃぁないことぐらいわかってるよHAHAHA

じゃあなんなのよ!

stderrの反乱

いままで構ってこなかったからかすっかりご機嫌ナナメのstderrがついに暴走しました
stderrはかわいい少年のイメージです
MojiCode15

まずはstdoutかstderrかもわからんのでTextのリッチテキスト形式を利用して赤くします

private void outputCommand(string o,bool isError=false) {
    byte[] converted = System.Convert.FromBase64String(o);
    Encoding enc = new UTF8Encoding();
    string encoded = enc.GetString(converted);
    if (isError) {
        encoded = "<color=red>" + encoded + "</color>";
    }
    output = o + "\n" + encoded + "\n";
}

private void onBashOutput(object sender, DataReceivedEventArgs e) {
    outputCommand(e.Data);
}

private void onBashError(object sender, DataReceivedEventArgs e) {
    outputCommand(e.Data,true);
}

うんうん

そしてとりあえずstderrをbase64に通さず素直に出力しましょうね

private void onBashError(object sender, DataReceivedEventArgs e) {
    UnityEngine.Debug.Log("Debug : "+e.Data);
    outputCommand(e.Data,true);
}

MojiCode13

まぁ化けるわな

ここでなんとなく同じ文字列をTextに出してみました。

private void onBashError(object sender, DataReceivedEventArgs e) {
    byte[] errorBytes = Encoding.GetEncoding("Shift_JIS").GetBytes(e.Data);
    string errorStr_base64 = System.Convert.ToBase64String(errorBytes);
    outputCommand(errorStr_base64,true);
}

こんなふうにC#エンコードデコードをどっちもやります
MojiCode14

!?

ええ!?Shift_JISでいいの!?
なんか一部化けてるけどほぼ正常に出てる!?なんだこれ! (ちなみにハンドラから直接e.Data渡したら全部化けました、もしかしてここか?)

え?ハンドラからでてくるstdoutは何かわからない文字コード(たぶんUTF-8)だったのにstderrの方はShift_JISなの?
なんだこれ?
MojiCode16

Unityの方のコンソールは化けたままなのでUTF-8・・・だとおもいます・・・
Textの方は文字コードを適当に合わせてくれるようです・・・?
stdoutの方が化けてしまったのはTextがUTF-8Shift_JISだと誤解してしまった、というかどこかで誤解させてしまったのか
もしかしたらもともとShift_JISだったのか
で、でもbashの$LANGはUTF-8だし・・・

ともあれ何とか日本語を表示できるようになったのでこの件はいいですがもう少しちゃんと調べる必要がありそうです。

まとめ

今回はかなり振り回されました。base64Shift_JISのヒントをもらったりしてなんとか漕ぎつけましたが・・・
無意識にこのクラスにクソコードを紛れ込ませてしまっているのかわかりませんがコメントをちゃんと残しつつ、整理したいと思います。

名前 文字コードだと思うもの
bash stdout UTF-8? Shift_JIS?
bash stderr Shift_JIS?
bash $LANG UTF-8
Unity Text たぶん合わせてくれる
Unity コンソール UTF-8だとおもう

そ、それでは良い文字コードライフを・・・

今更改行コードで死にかけたお話

C# Unity bash

コタツに入っていても手は寒い

何とかなりませんかね?

改行コード

ふと思い立ってC#からbashを起動したくなった。
bashの起動自体は

Process process = new Process();
ProcessStartInfo psi_bash = new ProcessStartInfo();
//設定
psi_bash.FileName= @"C:\cygwin64\bin\bash.exe";
psi_bash.RedirectStandardInput = true;
psi_bash.RedirectStandardOutput = true;
psi_bash.RedirectStandardError = true;
psi_bash.CreateNoWindow = true;
psi_bash.UseShellExecute = false;
psi_bash.Arguments = "--login";
psi_bash.StandardErrorEncoding = System.Text.Encoding.UTF8;
psi_bash.StandardOutputEncoding = System.Text.Encoding.UTF8;

//プロセス起動
process = Process.Start(psi_bash);
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.OutputDataReceived += onBashOutput;
process.ErrorDataReceived += onBashError;

とまぁこんなふうに標準入出力を確保して起動すれば標準入力のStreamWriterに書き込めば次々とbashのコマンドを実行するんですぜ

private void sendToCygwinBash(Process bash) {
    StreamWriter sw = bash.StandardInput;
    if (sw.BaseStream.CanWrite) {
        sw.WriteLine(command);
    }
}
private void onBashOutput(object sender, DataReceivedEventArgs e) {
    outputCommand(e.Data);
}

private void onBashError(object sender, DataReceivedEventArgs e) {
    outputCommand(e.Data);
}

標準出力や標準エラー出力はリダイレクトしてて出力を読み取るたびにイベントが呼び出されるのでそこは楽でした。

問題は入力

上のコードを見ると入力を適当に受け取ってStreamWriterに適当に書き込んでますがなんか出力がへん
入力はls
出力はhomelsした結果が返ってくると踏んでました。

CRNL1

エラーでとるやんけ!

文字化けもしとるやんけ!

この際文字化けはいいですがbashがなんて言ってるのかはだいたい掴めます

ls\rなんてコマンドはないです

さいですか

謎の\r

どこから降って湧いたのか改行コード\rがこんにちはしていますね。
これのせいでbashがコマンドを理解できないでいます。うっとうしい

手始めにコマンドを格納している変数commandにコマンドを格納するときに紛れ込んでしまったとみてReplace

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

CRNL1

ダメみたいですね。
ていうかそもそもcommandを出力させてるところに\rが紛れ込んでない時点でここじゃないですね~

ならばStreamWriterかな?

private void sendToCygwinBash(Process bash) {
    StreamWriter sw = bash.StandardInput;
    sw.NewLine="\n";
    if (sw.BaseStream.CanWrite) {
        sw.WriteLine(command);
    }
}

CRNL2

あっうまくいった!

大した問題ではなかったですがここで躓いてたら 大いなる計画 がとん挫するところだったので解決してよかったです。

それでは良い改行コードライフを!

まほプリが終わってしまうダメージをシェル芸で癒したいね

bash 雑記 シェルスクリプト

魔法つかいプリキュア49話でめちゃくちゃ泣いた

涙腺のゆるみから老化を感じる

シェル芸をやろうとおもいました

近々部活でコンテストがあるので作品をまた作ろうと思っていました。
しかし今度のコンテストではLT部門っつーのができるらしくて

d.hatena.ne.jp

どうせなら出たいので、なにを話そうかな~~~と考えてました。
何か勧誘的なことを話せば一緒にそれをやる人がふえるな~~と思って色々考えてました。
例えば

まぁいろいろあるのですがどれも人を選ぶので、僕の話術ではなかなか思うように引き込めないだろうな~~と

なら よく使ってて馴染みのあるものを強化した感じ のことを話せば何とかこちらサイドに引き込めるのでは
つまるところ シェル芸

https://blog.ueda.asia/?page_id=1434blog.ueda.asia

まぁ僕も最近真剣にやり始めたばかりなので部内コンまでにお勉強しないとなんですが、試しにFizzBuzzやってみました

seq 1 50|
awk '{if(NR%3==0){print "Fizz"}else{print $1}}'|
awk '{if(NR%5==0){print $1 "Buzz"}else{print $1}}'|
sed -E 's/[0-9]+Buzz/Buzz/g'

そしてドーン

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
FizzBuzz
46
47
Fizz
49
Buzz

awkを二連続でつなげて3の倍数と5の倍数をFizzとBuzzにドーン!!
最後にBuzzの前の余計な数字をsedでドカーン!

sed拡張正規表現の指定が-eではなく-Eであることに気付くのに5分ぐらいかかったのでまだまだ感があります。

そしてこんなものも・・・

% seq 0 2|awk '{if($1==0){print "NOP"}else if($1==1){print "ADD"}else if($1==2){print "SUB"}}'
NOP
ADD
SUB

catで命令列を記述したファイルを読み出してパイプすればCPUできないかなーーー?なんて思っております。

問題はレジスタファイルやデータメモリをどうするかなんですが・・・
ファイルに書き出してみる?Open usp Tukubai系を使えばなんとかなりそう?

https://uec.usp-lab.com/TUKUBAI/CGI/TUKUBAI.CGI?POMPA=ABOUTuec.usp-lab.com

なんにせよまだ手探りでやっています。

上達すれば、部内LTでも頑張って話したいですね。

( ˘ω˘ ).oO(そして身内や部内でシェルスクリプトbashが流行りますように・・・)