Linqで文字のバイト単位でグループ分け

var input = "e4bba5e4b88be381aee69687e5ad97e58897e381af5554462d38e38292e69687e5ad97e382a8e383b3e382b3e383bce38387e382a3e383b3e382b0e5bda2e5bc8fe381a8e38199e3828b3136e980b2e695b0e381aee38390e382a4e38388e58897e381a7e38182e3828be38082";
var count = 0; // 外部にカウント用フラグ変数を置く
var words = Regex.Matches(input, "..")
    .Cast<Match>()
    .Select(m => Convert.ToByte(m.Value, 16))
    .Select(b => Convert.ToString(b, 2).PadLeft(8, '0'))
    .ToLookup(s => (s.StartsWith("10")) ? count : ++count);
Console.WriteLine(words.Count);

前回(たった10時間前ですが)の続き。16進数バイト列で表現されたUTF-8の文章の文字数を数えろ、というお話でした。せっかくなのでビット見てうんたらかんたら、のほうでも。律義に2進数に変換しながら分類。例えばwords[0]は[11100100,10111011,10100101]になる。こんな感じで41個分グルーピングされています。.Keyで何文字目かが取得出来るところが地味に素敵でいて微妙に混乱を招く(配列の何番目、ではない)。 で、まあしかし、場外にフラグ変数を置くことで何でもこなせるけれど、それってアリなの?という疑問はある。Linq連鎖の場外に変数を置くなんてグローバル変数的な害悪です。かどうかは分からないけれど、イマイチだとは思う。

場外に置かないで分類するとしたら、どうすればよいかなー。うーん。思い浮かばない。

var text = words.Select(g => g.Select(s => Convert.ToByte(s, 2)).ToArray())
    .Select(bytes => Encoding.UTF8.GetString(bytes))
    .Aggregate(new StringBuilder(), (sb, s) => sb.Append(s))
    .ToString();
Console.WriteLine(text);

こっちはどうでもいいんですが、文章への復元はこんな感じで。面倒くさー。何個Select使えば気が済むんだ、みたいなみたいな。でもLinq使わないとそれこそもっと面倒くさい気はする。とりあえず=>かわいい。=>のかわいさは異常。=>がかわいいすぎて萌え死ぬ。

Profile

Yoshifumi Kawai

Cysharp, Inc
CEO/CTO

Microsoft MVP for Developer Technologies(C#)
April 2011
|
July 2023

Twitter:@neuecc GitHub:neuecc

Archive