2014年10月26日

C#で文字変換表に基く文字列の変換

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その44

■問題 (出題者: mc さん)
UNIXのtrコマンドや、Perlのtr演算子のように、指定した対応づけに従って文字を変換する関数を作成して下さい。
予め言語内に用意されている場合は、(1)一般的な使用法と、(2)より進んだ使用方法を提示して下さい。

'ABCDEF'と'abcdef'等すべて対応する文字を書く必要があるものを、(1)基本版、'A-Z'と'a-z'のように"-"で範囲を指定できるものを(2)拡張版、2を更に発展させたものを(3)発展版とします。任意のものを選んで解答して下さい。
実行例. (与えられた文字列が、"typewriter"の場合)
tr 'qwertyuiop' 'QWERTYUIOP' "typewriter"
=> TYPEWRITER
1
2
3
4
5
6
7
8

;; 基本版/Arc
(def tr (orig subst str)
  (tostring
   (each c str
     (pr (aif (pos c orig) (subst it) c)))))

(tr "qwertyuiop" "QWERTYUIOP" "typewriter")
;=>"TYPEWRITER"



ここでは、基本版だけのコードを書きました。
問題文には、"変換する関数"とありますが、C#らしくここではクラスTranscoderを定義することとしました。

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace Doukaku.Org {
    class Transcoder {
        private Dictionary<char,char> dict = new Dictionary<char,char>();

        public Transcoder(string from, string to) {
            for (int i = 0; i < to.Length; i++ )
               dict.Add(from[i], to[i]);
        }

        public string Execute(string s) {
            StringBuilder sb = new StringBuilder();
            foreach (var c in s) {
                if (dict.ContainsKey(c))
                    sb.Append(dict[c]);
                else
                    sb.Append(c);               
            }
            return sb.ToString();
        }
    }
}

あまりにも普通すぎるコードですが、まあ良しとしましょう。 普通が一番です。
このクラスの使用例は、こんな感じ。

class Program {
    static void Main(string[] args) {
        Transcoder tr = new Transcoder("qwertyuip","QWERTYUIP");
        Console.WriteLine(tr.Execute("typewriter"));
        Console.ReadLine();
    }
}

  

Posted by gushwell at 22:30Comments(0)TrackBack(0)

2014年07月30日

C#でコード中の文字の頻度分析

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その29

■問題 (出題者:crane さん)
プログラムコード中の文字の頻度は言語によって相当にばらつきがあると思います。ある言語はピリオドが頻出するとか、別の言語はカッコの頻出頻度が高い、とか。そこで、
  • 文字の頻度解析をするプログラムを作成し、
  • 適当なプログラムに対して実行し、結果を出力して、そのような頻度になっている理由を教えてください。
(その言語で書かれた「典型的な」プログラムコード、といえるようなものがあると良いのですが・・) 簡単すぎるという方は、複数文字にしてみたり単語の頻度にしてみてください。

参考;Wikipedia 頻度分析 http://ja.wikipedia.org/wiki/%E9%A0%BB%E5%BA%A6%E5%88%86%E6%9E%90

これはDictionaryクラスの出番ですね。 頻度分析を行うCharFreequencyクラスを定義してみました。
受け取る型をstringp[] にするか、string にするか迷いましたが、 単純な string にしました。File.ReadAllText 使えば、一発で string として取得できますからね。

頻度分析する際は、制御文字とWhiteSpaceは除いていますが、IsWhiteSpace だけでも問題はないですね。たぶん...

■C#で書いたコード
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            CharFrequency cd = new CharFrequency(File.ReadAllText(args[0]));  // C#はargs[1]ではなくargs[0]
            var dict = cd.Analyze();            

            // Top20だけを表示
            var total = dict.Sum(x => x.Value);
            foreach (var d in dict.OrderByDescending(x => x.Value).Take(20)) {
                Console.WriteLine("{0} = {1},  {2:#0.#0}%", d.Key, d.Value, d.Value * 100.0 / total);
            }
            Console.ReadLine();
        }
    }

    class CharFrequency {
        private string text;
        public CharFrequency(string s) {
            text = s;
        }

        public Dictionary<char, int> Analyze() {
            var dict = new Dictionary<char, int>();
            foreach (var c in text) {
                if (char.IsControl(c) || char.IsWhiteSpace(c))
                    continue;
                if (dict.ContainsKey(c))
                    dict[c]++;
                else
                    dict[c] = 1;
            }
            return dict;
        }
    }
}
あるソースを 実行してみたところ、以下のような結果となりました。

t = 1602,  8.30%
e = 1594,  8.25%
i = 923,  4.78%
n = 788,  4.08%
s = 729,  3.78%
r = 717,  3.71%
a = 715,  3.70%
m = 681,  3.53%

set, get, return, true. int, while, string, private, foreach system など、C#では、t や e を含む単語が多いですからね。
でも、通常の英文でも t や e は多そうですね。  
Posted by gushwell at 22:00Comments(0)TrackBack(0)

2011年06月14日

stringの配列からDictionary<string, string>への変換をやってみた

   このエントリーをはてなブックマークに追加 Clip to Evernote
元ネタ:stringの配列からDictionaryへの変換
http://d.hatena.ne.jp/okazuki/20110609/1307577527
http://d.hatena.ne.jp/okazuki/20110609/1307580225
http://d.hatena.ne.jp/okazuki/20110609/1307590523
http://d.hatena.ne.jp/okazuki/20110609/1307590592

僕もやってみました。
奇数番目の要素のシーケンスと偶数番目の要素のシーケンスを作成し、
Zipメソッドで、Tupleに変換したものを ToDictionaryメソッドで、Dictionaryに変換しています。
この例では、Zipメソッドは、拡張メソッドとして使うよりも、静的メソッドとして使った方が、
可読性が高くなると思います。

ジェネリックにしているので、文字列以外のシーケンスに対しても、利用できます。

もっと簡単に書けないかなー。
配列限定ならば、やはりfor文かな。

  
Posted by gushwell at 22:36Comments(0)TrackBack(0)